diff --git a/ios/Podfile.lock b/ios/Podfile.lock index c4bd4c18..a364d080 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -271,6 +271,8 @@ PODS: - PromisesObjC (= 2.4.0) - protocol_handler_ios (0.0.1): - Flutter + - quick_actions_ios (0.0.1): + - Flutter - receive_sharing_intent (1.8.1): - Flutter - record_ios (1.1.0): @@ -365,6 +367,7 @@ DEPENDENCIES: - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`) - protocol_handler_ios (from `.symlinks/plugins/protocol_handler_ios/ios`) + - quick_actions_ios (from `.symlinks/plugins/quick_actions_ios/ios`) - receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`) - record_ios (from `.symlinks/plugins/record_ios/ios`) - sensors_plus (from `.symlinks/plugins/sensors_plus/ios`) @@ -481,6 +484,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/pointer_interceptor_ios/ios" protocol_handler_ios: :path: ".symlinks/plugins/protocol_handler_ios/ios" + quick_actions_ios: + :path: ".symlinks/plugins/quick_actions_ios/ios" receive_sharing_intent: :path: ".symlinks/plugins/receive_sharing_intent/ios" record_ios: @@ -567,6 +572,7 @@ SPEC CHECKSUMS: PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 protocol_handler_ios: 59f23ee71f3ec602d67902ca7f669a80957888d5 + quick_actions_ios: 500fcc11711d9f646739093395c4ae8eec25f779 receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00 record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374 SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 98d66fb2..d7ffdc09 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -216,6 +216,8 @@ }; 7310A7D52EB10962002C0FD3 /* Solian Watch App */ = { isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + ); path = "Solian Watch App"; sourceTree = ""; }; @@ -757,14 +759,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; @@ -822,14 +820,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; @@ -880,14 +874,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks.sh\"\n"; diff --git a/ios/Runner/Assets.xcassets/Contents.json b/ios/Runner/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/ios/Runner/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/lib/main.dart b/lib/main.dart index d20382cb..5893d594 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -24,6 +24,7 @@ import 'package:island/services/notify.dart'; import 'package:island/services/widget_sync_service.dart'; import 'package:island/services/timezone.dart'; import 'package:island/services/app_intents.dart'; +import 'package:island/services/quick_actions.dart'; import 'package:island/widgets/alert.dart'; import 'package:island/widgets/app_scaffold.dart'; import 'package:relative_time/relative_time.dart'; @@ -111,6 +112,17 @@ void main() async { ); } + try { + talker.info("[QuickActions] Initializing Quick Actions service..."); + final quickActionsService = QuickActionsService(); + await quickActionsService.initialize(); + talker.info("[QuickActions] Quick Actions service is ready!"); + } catch (err) { + talker.error( + "[QuickActions] Failed to initialize Quick Actions service... $err", + ); + } + final prefs = await SharedPreferences.getInstance(); if (!kIsWeb && (Platform.isMacOS || Platform.isLinux || Platform.isWindows)) { diff --git a/lib/services/quick_actions.dart b/lib/services/quick_actions.dart new file mode 100644 index 00000000..61ae7cd1 --- /dev/null +++ b/lib/services/quick_actions.dart @@ -0,0 +1,89 @@ +import 'dart:io'; +import 'package:flutter/foundation.dart'; +import 'package:go_router/go_router.dart'; +import 'package:island/route.dart'; +import 'package:island/services/event_bus.dart'; +import 'package:island/talker.dart'; +import 'package:quick_actions/quick_actions.dart'; + +class QuickActionsService { + static final QuickActionsService _instance = QuickActionsService._internal(); + factory QuickActionsService() => _instance; + QuickActionsService._internal(); + + final QuickActions _quickActions = const QuickActions(); + bool _initialized = false; + + Future initialize() async { + if (kIsWeb || (!Platform.isAndroid && !Platform.isIOS)) { + talker.warning( + '[QuickActions] Quick Actions only supported on Android and iOS', + ); + return; + } + + if (_initialized) { + talker.info('[QuickActions] Already initialized'); + return; + } + + try { + talker.info('[QuickActions] Initializing Quick Actions...'); + + // TODO Add icons for these + final shortcuts = [ + const ShortcutItem(type: 'compose_post', localizedTitle: 'New Post'), + const ShortcutItem(type: 'explore', localizedTitle: 'Explore'), + const ShortcutItem(type: 'chats', localizedTitle: 'Chats'), + const ShortcutItem( + type: 'notifications', + localizedTitle: 'Notifications', + ), + ]; + + await _quickActions.initialize(_handleShortcut); + await _quickActions.setShortcutItems(shortcuts); + + _initialized = true; + talker.info('[QuickActions] Quick Actions initialized successfully'); + } catch (e, stack) { + talker.error('[QuickActions] Initialization failed', e, stack); + rethrow; + } + } + + void _handleShortcut(String type) { + talker.info('[QuickActions] Shortcut tapped: $type'); + + final context = rootNavigatorKey.currentContext; + if (context == null) { + talker.warning('[QuickActions] Context not available, skipping action'); + return; + } + + switch (type) { + case 'compose_post': + eventBus.fire(const ShowComposeSheetEvent()); + break; + + case 'explore': + context.go('/explore'); + break; + + case 'chats': + context.go('/chat'); + break; + + case 'notifications': + context.go('/notifications'); + break; + + default: + talker.warning('[QuickActions] Unknown shortcut type: $type'); + } + } + + void dispose() { + _initialized = false; + } +} diff --git a/pubspec.lock b/pubspec.lock index fd3d6b41..85856159 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -2229,6 +2229,38 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.0" + quick_actions: + dependency: "direct main" + description: + name: quick_actions + sha256: "7e35dd6a21f5bbd21acf6899039eaf85001a5ac26d52cbd6a8a2814505b90798" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + quick_actions_android: + dependency: transitive + description: + name: quick_actions_android + sha256: "23f04632ada7fc16665d84ba54a0c792c09727e7fda6c989c6e6ba1853aa15dc" + url: "https://pub.dev" + source: hosted + version: "1.0.27" + quick_actions_ios: + dependency: transitive + description: + name: quick_actions_ios + sha256: a2e08ceb01f9d26e1b1826b1c4f5da6b7b6bbf61bcbaacd8e93dfff58b91f996 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + quick_actions_platform_interface: + dependency: transitive + description: + name: quick_actions_platform_interface + sha256: "1fec7068db5122cd019e9340d3d7be5d36eab099695ef3402c7059ee058329a4" + url: "https://pub.dev" + source: hosted + version: "1.1.0" recase: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 31c5aeeb..01621421 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,7 @@ dependencies: cupertino_icons: ^1.0.8 flutter_hooks: ^0.21.3+1 hooks_riverpod: ^3.1.0 + quick_actions: ^1.0.8 go_router: ^17.0.1 styled_widget: ^0.4.1 shared_preferences: ^2.5.4