Skip to content

Commit

Permalink
Merge pull request #1924 from matthiasn/feat/paste_image_from_clipboard
Browse files Browse the repository at this point in the history
feat: paste image from clipboard
  • Loading branch information
matthiasn authored Feb 3, 2025
2 parents fb86cbe + 418780e commit c5af080
Show file tree
Hide file tree
Showing 13 changed files with 668 additions and 3 deletions.
2 changes: 1 addition & 1 deletion lib/features/ai/state/ollama_image_analysis.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions lib/features/journal/repository/clipboard_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:super_clipboard/super_clipboard.dart';

part 'clipboard_repository.g.dart';

@riverpod
SystemClipboard? clipboardRepository(Ref ref) {
return SystemClipboard.instance;
}
29 changes: 29 additions & 0 deletions lib/features/journal/repository/clipboard_repository.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/features/journal/state/entry_controller.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 54 additions & 0 deletions lib/features/journal/state/image_paste_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import 'dart:async';

import 'package:lotti/features/journal/repository/clipboard_repository.dart';
import 'package:lotti/logic/image_import.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:super_clipboard/super_clipboard.dart';

part 'image_paste_controller.g.dart';

@riverpod
class ImagePasteController extends _$ImagePasteController {
@override
Future<bool> build({
required String? linkedFromId,
required String? categoryId,
}) async {
final clipboard = ref.read(clipboardRepositoryProvider);
if (clipboard == null) {
return false;
}
final reader = await clipboard.read();
return reader.canProvide(Formats.png) || reader.canProvide(Formats.jpeg);
}

Future<void> paste() async {
final clipboard = ref.read(clipboardRepositoryProvider);
if (clipboard == null) {
return;
}
final reader = await clipboard.read();

if (reader.canProvide(Formats.png)) {
reader.getFile(Formats.png, (file) async {
await importPastedImages(
data: await file.readAll(),
fileExtension: 'png',
linkedId: linkedFromId,
categoryId: categoryId,
);
});
}

if (reader.canProvide(Formats.jpeg)) {
reader.getFile(Formats.jpeg, (file) async {
await importPastedImages(
data: await file.readAll(),
fileExtension: 'jpg',
linkedId: linkedFromId,
categoryId: categoryId,
);
});
}
}
}
201 changes: 201 additions & 0 deletions lib/features/journal/state/image_paste_controller.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:lotti/features/journal/ui/widgets/create/create_entry_action_list_tile.dart';
import 'package:lotti/features/journal/ui/widgets/create/paste_image_list_tile.dart';
import 'package:lotti/l10n/app_localizations_context.dart';
import 'package:lotti/themes/theme.dart';
import 'package:lotti/utils/modals.dart';
Expand All @@ -24,6 +25,7 @@ class CreateEntryModal {
ImportImageAssetsListTile(linkedFromId, categoryId: categoryId),
if (isMacOS)
CreateScreenshotListTile(linkedFromId, categoryId: categoryId),
PasteImageListTile(linkedFromId, categoryId: categoryId),
verticalModalSpacer,
],
),
Expand Down
37 changes: 37 additions & 0 deletions lib/features/journal/ui/widgets/create/paste_image_list_tile.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:lotti/features/journal/state/image_paste_controller.dart';
import 'package:lotti/l10n/app_localizations_context.dart';

class PasteImageListTile extends ConsumerWidget {
const PasteImageListTile(
this.linkedFromId, {
this.categoryId,
super.key,
});

final String? linkedFromId;
final String? categoryId;

@override
Widget build(BuildContext context, WidgetRef ref) {
final provider = imagePasteControllerProvider(
linkedFromId: linkedFromId,
categoryId: categoryId,
);
final canPasteImage = ref.watch(provider).valueOrNull ?? false;

if (!canPasteImage) {
return const SizedBox.shrink();
}

return ListTile(
leading: const Icon(Icons.paste),
title: Text(context.messages.addActionAddImageFromClipboard),
onTap: () {
Navigator.of(context).pop();
ref.read(provider.notifier).paste();
},
);
}
}
1 change: 1 addition & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"addActionAddEvent": "Event",
"addActionAddMeasurable": "Measurable",
"addActionAddPhotos": "Photo(s)",
"addActionAddImageFromClipboard": "Paste Image",
"addActionAddScreenshot": "Screenshot",
"addActionAddSurvey": "Fill Survey",
"addActionAddTask": "Task",
Expand Down
Loading

0 comments on commit c5af080

Please sign in to comment.