diff --git a/android/app/src/main/res/drawable/plus.png b/android/app/src/main/res/drawable/plus.png new file mode 100755 index 00000000..de5cf864 Binary files /dev/null and b/android/app/src/main/res/drawable/plus.png differ diff --git a/android/app/src/main/res/drawable/report.png b/android/app/src/main/res/drawable/report.png new file mode 100755 index 00000000..49531471 Binary files /dev/null and b/android/app/src/main/res/drawable/report.png differ diff --git a/ios/Runner/Assets.xcassets/plus.imageset/Contents.json b/ios/Runner/Assets.xcassets/plus.imageset/Contents.json new file mode 100644 index 00000000..849cb5db --- /dev/null +++ b/ios/Runner/Assets.xcassets/plus.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "plus.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/ios/Runner/Assets.xcassets/plus.imageset/plus.png b/ios/Runner/Assets.xcassets/plus.imageset/plus.png new file mode 100755 index 00000000..de5cf864 Binary files /dev/null and b/ios/Runner/Assets.xcassets/plus.imageset/plus.png differ diff --git a/ios/Runner/Assets.xcassets/report.imageset/Contents.json b/ios/Runner/Assets.xcassets/report.imageset/Contents.json new file mode 100644 index 00000000..a8fbdcf3 --- /dev/null +++ b/ios/Runner/Assets.xcassets/report.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images": [ + { + "idiom": "universal", + "filename": "report.png", + "scale": "1x" + }, + { + "idiom": "universal", + "scale": "2x" + }, + { + "idiom": "universal", + "scale": "3x" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/ios/Runner/Assets.xcassets/report.imageset/report.png b/ios/Runner/Assets.xcassets/report.imageset/report.png new file mode 100755 index 00000000..49531471 Binary files /dev/null and b/ios/Runner/Assets.xcassets/report.imageset/report.png differ diff --git a/lib/app/services/deep_link_service.dart b/lib/app/services/deep_link_service.dart index f016c93c..29357919 100644 --- a/lib/app/services/deep_link_service.dart +++ b/lib/app/services/deep_link_service.dart @@ -1,6 +1,8 @@ +import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:app_links/app_links.dart'; +import 'package:quick_actions/quick_actions.dart'; import 'package:taskwarrior/app/modules/home/views/add_task_bottom_sheet_new.dart'; import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart'; import 'package:taskwarrior/app/routes/app_pages.dart'; @@ -8,21 +10,64 @@ import 'package:taskwarrior/app/routes/app_pages.dart'; class DeepLinkService extends GetxService { late AppLinks _appLinks; Uri? _queuedUri; + Uri? get queuedUri => _queuedUri; - @override - void onReady() { - super.onReady(); - _initDeepLinks(); - } + final QuickActions _quickActions = const QuickActions(); + StreamSubscription? _linkSubscription; - void _initDeepLinks() { + Future init() async { _appLinks = AppLinks(); - _appLinks.uriLinkStream.listen((uri) { + + await _initQuickActions(); + + try { + final initialUri = await _appLinks.getInitialLink(); + if (initialUri != null) { + _queuedUri = initialUri; + debugPrint('🔗 INITIAL LINK QUEUED: $_queuedUri'); + } + } catch (e) { + debugPrint('Deep link init error: $e'); + } + + _linkSubscription = _appLinks.uriLinkStream.listen((uri) { debugPrint('🔗 LINK RECEIVED: $uri'); _handleWidgetUri(uri); + }, onError: (err) { + debugPrint('🔗 LINK STREAM ERROR: $err'); }); } + Future _initQuickActions() async { + await _quickActions.initialize((String shortcutType) { + debugPrint("⚡ SHORTCUT RECEIVED: $shortcutType"); + if (shortcutType == 'shortcut_add_task') { + _handleWidgetUri(Uri.parse('taskwarrior://addclicked')); + } else if (shortcutType == 'shortcut_reports') { + _handleWidgetUri(Uri.parse('taskwarrior://reports')); + } + }); + + await _quickActions.setShortcutItems([ + const ShortcutItem( + type: 'shortcut_add_task', + localizedTitle: 'Add Task', + icon: 'plus', + ), + const ShortcutItem( + type: 'shortcut_reports', + localizedTitle: 'Reports', + icon: 'report', + ), + ]); + } + + @override + void onClose() { + _linkSubscription?.cancel(); + super.onClose(); + } + void _handleWidgetUri(Uri uri) { if (Get.isRegistered()) { _executeAction(uri, Get.find()); @@ -64,6 +109,12 @@ class DeepLinkService extends GetxService { ), ); } + } else if (uri.host == "reports") { + if (Get.context != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + Get.toNamed(Routes.REPORTS); + }); + } } } } diff --git a/lib/main.dart b/lib/main.dart index 09f0268c..d21785af 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,8 +3,6 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -// 1. Add this import -import 'package:app_links/app_links.dart'; import 'package:taskwarrior/app/services/deep_link_service.dart'; import 'package:taskwarrior/app/utils/app_settings/app_settings.dart'; @@ -42,7 +40,11 @@ void main() async { WidgetsFlutterBinding.ensureInitialized(); await AppSettings.init(); - Get.put(DeepLinkService(), permanent: true); + await Get.putAsync(() async { + final service = DeepLinkService(); + await service.init(); + return service; + }, permanent: true); runApp( GetMaterialApp( darkTheme: darkTheme, diff --git a/pubspec.lock b/pubspec.lock index c7182030..c8475ca7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + app_links: + dependency: "direct main" + description: + name: app_links + sha256: "5f88447519add627fe1cbcab4fd1da3d4fed15b9baf29f28b22535c95ecee3e8" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + app_links_linux: + dependency: transitive + description: + name: app_links_linux + sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81 + url: "https://pub.dev" + source: hosted + version: "1.0.3" + app_links_platform_interface: + dependency: transitive + description: + name: app_links_platform_interface + sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + app_links_web: + dependency: transitive + description: + name: app_links_web + sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555 + url: "https://pub.dev" + source: hosted + version: "1.0.4" archive: dependency: transitive description: @@ -65,6 +97,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + build_cli_annotations: + dependency: transitive + description: + name: build_cli_annotations + sha256: e563c2e01de8974566a1998410d3f6f03521788160a02503b0b1f1a46c7b3d95 + url: "https://pub.dev" + source: hosted + version: "2.1.1" build_config: dependency: transitive description: @@ -519,6 +559,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.32" + flutter_rust_bridge: + dependency: "direct main" + description: + name: flutter_rust_bridge + sha256: "37ef40bc6f863652e865f0b2563ea07f0d3c58d8efad803cc01933a4b2ee067e" + url: "https://pub.dev" + source: hosted + version: "2.11.1" flutter_slidable: dependency: "direct main" description: @@ -601,6 +649,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + gtk: + dependency: transitive + description: + name: gtk + sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c + url: "https://pub.dev" + source: hosted + version: "2.1.0" hashcodes: dependency: transitive description: @@ -1049,6 +1105,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.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" quiver: dependency: transitive description: @@ -1141,10 +1229,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "3.0.0" sizer: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 12e80726..e1cf0ae4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -69,6 +69,7 @@ dependencies: flutter_rust_bridge: ^2.11.1 ffi: any # Required for FFI app_links: ^6.4.1 + quick_actions: ^1.1.0 dev_dependencies: build_runner: null