diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index 33941ab..546ca88 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -38,5 +38,8 @@ "delete": "Delete", "deletePublisher": "Delete Publisher {}", "deletePublisherHint": "Are you sure to delete this publisher? This will also deleted all the post and collections under this publisher.", - "somethingWentWrong": "Something went wrong..." + "somethingWentWrong": "Something went wrong...", + "deletePost": "Delete Post", + "deletePostHint": "Are you sure to delete this post?", + "copyLink": "Copy Link" } diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e04bbc8..aa1211b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -47,6 +47,8 @@ PODS: - Flutter - image_picker_ios (0.0.1): - Flutter + - irondash_engine_context (0.0.1): + - Flutter - Kingfisher (8.3.1) - media_kit_libs_ios_video (1.0.4): - Flutter @@ -67,6 +69,8 @@ PODS: - sqflite_darwin (0.0.4): - Flutter - FlutterMacOS + - super_native_extensions (0.0.1): + - Flutter - SwiftyGif (5.4.5) - url_launcher_ios (0.0.1): - Flutter @@ -82,6 +86,7 @@ DEPENDENCIES: - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) - flutter_platform_alert (from `.symlinks/plugins/flutter_platform_alert/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`) - Kingfisher (~> 8.0) - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`) - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`) @@ -89,6 +94,7 @@ DEPENDENCIES: - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) + - super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - volume_controller (from `.symlinks/plugins/volume_controller/ios`) - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) @@ -115,6 +121,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_platform_alert/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" + irondash_engine_context: + :path: ".symlinks/plugins/irondash_engine_context/ios" media_kit_libs_ios_video: :path: ".symlinks/plugins/media_kit_libs_ios_video/ios" media_kit_video: @@ -127,6 +135,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" sqflite_darwin: :path: ".symlinks/plugins/sqflite_darwin/darwin" + super_native_extensions: + :path: ".symlinks/plugins/super_native_extensions/ios" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" volume_controller: @@ -143,6 +153,7 @@ SPEC CHECKSUMS: flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 flutter_platform_alert: bf3b5fcd4ac14bd637e20527e9c471633071afd3 image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a + irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486 Kingfisher: 3204d23de16b5ea53541c44ca5a8efb55741dec3 media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854 media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474 @@ -152,6 +163,7 @@ SPEC CHECKSUMS: SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868 shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 + super_native_extensions: b763c02dc3a8fd078389f410bf15149179020cb4 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 url_launcher_ios: 694010445543906933d732453a59da0a173ae33d volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12 diff --git a/lib/main.dart b/lib/main.dart index 473bb01..75de821 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -65,6 +65,7 @@ class IslandApp extends HookConsumerWidget { final theme = ref.watch(themeProvider); useEffect(() { + // Load userinfo final userNotifier = ref.read(userInfoProvider.notifier); Future(() { userNotifier.fetchUser(); diff --git a/lib/widgets/post/post_item.dart b/lib/widgets/post/post_item.dart index cdbc1f5..f8d01db 100644 --- a/lib/widgets/post/post_item.dart +++ b/lib/widgets/post/post_item.dart @@ -1,16 +1,22 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:island/models/post.dart'; +import 'package:island/pods/network.dart'; +import 'package:island/pods/userinfo.dart'; import 'package:island/route.gr.dart'; +import 'package:island/widgets/alert.dart'; import 'package:island/widgets/content/cloud_file_collection.dart'; import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/markdown.dart'; -import 'package:island/widgets/context_menu.dart'; +import 'package:lucide_icons/lucide_icons.dart'; import 'package:styled_widget/styled_widget.dart'; +import 'package:super_context_menu/super_context_menu.dart'; -class PostItem extends StatelessWidget { +class PostItem extends ConsumerWidget { final SnPost item; final EdgeInsets? padding; final bool isOpenable; @@ -24,62 +30,104 @@ class PostItem extends StatelessWidget { }); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final renderingPadding = padding ?? EdgeInsets.symmetric(horizontal: 12, vertical: 16); - return ContextMenuRegion( - contextMenuBuilder: (_, offset) { - return AdaptiveTextSelectionToolbar.buttonItems( - anchors: TextSelectionToolbarAnchors(primaryAnchor: offset), - buttonItems: [ - ContextMenuButtonItem( - onPressed: () { - ContextMenuController.removeAny(); - context.router.push(PostEditRoute(id: item.id)).then((value) { - if (value != null) { - onRefresh?.call(); - } - }); + final user = ref.watch(userInfoProvider); + final isAuthor = useMemoized( + () => user.hasValue && user.value!.id == item.publisher.accountId, + [user], + ); + + return ContextMenuWidget( + menuProvider: (_) { + return Menu( + children: [ + if (isAuthor) + MenuAction( + title: 'edit'.tr(), + image: MenuImage.icon(LucideIcons.edit), + callback: () { + context.router.push(PostEditRoute(id: item.id)).then((value) { + if (value != null) { + onRefresh?.call(); + } + }); + }, + ), + if (isAuthor) + MenuAction( + title: 'delete'.tr(), + image: MenuImage.icon(LucideIcons.trash), + callback: () { + showConfirmAlert( + 'deletePostHint'.tr(), + 'deletePost'.tr(), + ).then((confirm) { + if (confirm) { + final client = ref.watch(apiClientProvider); + client + .delete('/posts/${item.id}') + .catchError((err) { + showErrorAlert(err); + return err; + }) + .then((_) { + onRefresh?.call(); + }); + } + }); + }, + ), + if (isAuthor) MenuSeparator(), + MenuAction( + title: 'copyLink'.tr(), + image: MenuImage.icon(LucideIcons.link), + callback: () { + Clipboard.setData( + ClipboardData(text: 'https://solsynth.dev/posts/${item.id}'), + ); }, - label: 'edit'.tr(), ), ], ); }, - child: Padding( - padding: renderingPadding, - child: Column( - spacing: 8, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 12, - children: [ - ProfilePictureWidget(item: item.publisher.picture), - Expanded( - child: GestureDetector( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(item.publisher.nick).bold(), - if (item.content.isNotEmpty) - MarkdownTextContent(content: item.content), - ], + child: Material( + child: Padding( + padding: renderingPadding, + child: Column( + spacing: 8, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 12, + children: [ + ProfilePictureWidget(item: item.publisher.picture), + Expanded( + child: GestureDetector( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(item.publisher.nick).bold(), + if (item.content.isNotEmpty) + MarkdownTextContent(content: item.content), + ], + ), + onTap: () { + if (isOpenable) { + context.router.push(PostDetailRoute(id: item.id)); + } + }, ), - onTap: () { - if (isOpenable) { - context.router.push(PostDetailRoute(id: item.id)); - } - }, ), - ), - ], - ), - if (item.attachments.isNotEmpty) - CloudFileList(files: item.attachments), - ], + ], + ), + if (item.attachments.isNotEmpty) + CloudFileList(files: item.attachments), + ], + ), ), ), ); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 3268e87..a9e61fe 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -9,8 +9,10 @@ #include #include #include +#include #include #include +#include #include void fl_register_plugins(FlPluginRegistry* registry) { @@ -23,12 +25,18 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) flutter_platform_alert_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterPlatformAlertPlugin"); flutter_platform_alert_plugin_register_with_registrar(flutter_platform_alert_registrar); + g_autoptr(FlPluginRegistrar) irondash_engine_context_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "IrondashEngineContextPlugin"); + irondash_engine_context_plugin_register_with_registrar(irondash_engine_context_registrar); g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin"); media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar); g_autoptr(FlPluginRegistrar) media_kit_video_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin"); media_kit_video_plugin_register_with_registrar(media_kit_video_registrar); + g_autoptr(FlPluginRegistrar) super_native_extensions_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "SuperNativeExtensionsPlugin"); + super_native_extensions_plugin_register_with_registrar(super_native_extensions_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 38256a7..533c9d2 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -6,8 +6,10 @@ list(APPEND FLUTTER_PLUGIN_LIST bitsdojo_window_linux file_selector_linux flutter_platform_alert + irondash_engine_context media_kit_libs_linux media_kit_video + super_native_extensions url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 3e36600..d56d620 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,12 +11,14 @@ import file_picker import file_selector_macos import flutter_inappwebview_macos import flutter_platform_alert +import irondash_engine_context import media_kit_libs_macos_video import media_kit_video import package_info_plus import path_provider_foundation import shared_preferences_foundation import sqflite_darwin +import super_native_extensions import url_launcher_macos import volume_controller import wakelock_plus @@ -28,12 +30,14 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) FlutterPlatformAlertPlugin.register(with: registry.registrar(forPlugin: "FlutterPlatformAlertPlugin")) + IrondashEngineContextPlugin.register(with: registry.registrar(forPlugin: "IrondashEngineContextPlugin")) MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) + SuperNativeExtensionsPlugin.register(with: registry.registrar(forPlugin: "SuperNativeExtensionsPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) VolumeControllerPlugin.register(with: registry.registrar(forPlugin: "VolumeControllerPlugin")) WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 20e1bb0..99e069c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -845,6 +845,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + irondash_engine_context: + dependency: transitive + description: + name: irondash_engine_context + sha256: cd7b769db11a2b5243b037c8a9b1ecaef02e1ae27a2d909ffa78c1dad747bb10 + url: "https://pub.dev" + source: hosted + version: "0.5.4" + irondash_message_channel: + dependency: transitive + description: + name: irondash_message_channel + sha256: b4101669776509c76133b8917ab8cfc704d3ad92a8c450b92934dd8884a2f060 + url: "https://pub.dev" + source: hosted + version: "0.7.0" js: dependency: transitive description: @@ -1141,6 +1157,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.0" + pixel_snap: + dependency: transitive + description: + name: pixel_snap + sha256: "677410ea37b07cd37ecb6d5e6c0d8d7615a7cf3bd92ba406fd1ac57e937d1fb0" + url: "https://pub.dev" + source: hosted + version: "0.1.5" platform: dependency: transitive description: @@ -1482,6 +1506,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.1" + super_context_menu: + dependency: "direct main" + description: + name: super_context_menu + sha256: "29f5a7090a35d3af627a80dc77d56b4a748b723461f2e5a5e592c61607b17e87" + url: "https://pub.dev" + source: hosted + version: "0.9.0-dev.6" + super_native_extensions: + dependency: transitive + description: + name: super_native_extensions + sha256: "09ccc40c475e6f91770eaeb2553bf4803812d7beadc3759aa57d643370619c86" + url: "https://pub.dev" + source: hosted + version: "0.9.0-dev.6" sync: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 51f52a1..ab69567 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -78,6 +78,7 @@ dependencies: riverpod_annotation: ^2.6.1 image_picker_platform_interface: ^2.10.1 image_picker_android: ^0.8.12+23 + super_context_menu: ^0.9.0-dev.6 dev_dependencies: flutter_test: diff --git a/web/index.html b/web/index.html index d619049..1aa2a74 100644 --- a/web/index.html +++ b/web/index.html @@ -34,5 +34,8 @@ + diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 16c40b5..c042a7f 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -10,8 +10,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -24,10 +26,14 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); FlutterPlatformAlertPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterPlatformAlertPlugin")); + IrondashEngineContextPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("IrondashEngineContextPluginCApi")); MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi")); MediaKitVideoPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi")); + SuperNativeExtensionsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SuperNativeExtensionsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); VolumeControllerPluginCApiRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 3a6ea80..ac6339c 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -7,8 +7,10 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows flutter_inappwebview_windows flutter_platform_alert + irondash_engine_context media_kit_libs_windows_video media_kit_video + super_native_extensions url_launcher_windows volume_controller )