diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index fb8c596..1bce189 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -12,15 +12,8 @@ if (localPropertiesFile.exists()) { } } -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') ?: '1' +def flutterVersionName = localProperties.getProperty('flutter.versionName') ?: '1.0' android { namespace "com.forkfolio.mobile" @@ -57,6 +50,15 @@ android { } } +configurations.all { + resolutionStrategy { + force 'androidx.activity:activity:1.9.3' + force 'androidx.activity:activity-ktx:1.9.3' + force 'androidx.core:core:1.15.0' + force 'androidx.core:core-ktx:1.15.0' + } +} + flutter { source '../..' } diff --git a/mobile/android/build.gradle b/mobile/android/build.gradle index 0c5ea57..bc157bd 100644 --- a/mobile/android/build.gradle +++ b/mobile/android/build.gradle @@ -13,18 +13,6 @@ subprojects { project.evaluationDependsOn(':app') } -subprojects { project -> - if (project.name != 'app') { - project.afterEvaluate { - if (project.hasProperty('android')) { - project.android { - compileSdkVersion 35 - } - } - } - } -} - tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/mobile/lib/core/constants/app_theme.dart b/mobile/lib/core/constants/app_theme.dart index 6262ed3..cef38c7 100644 --- a/mobile/lib/core/constants/app_theme.dart +++ b/mobile/lib/core/constants/app_theme.dart @@ -37,7 +37,7 @@ class AppTheme { letterSpacing: -0.3, ), ), - cardTheme: CardTheme( + cardTheme: CardThemeData( color: surface, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14), diff --git a/mobile/lib/features/share_receiver/share_receiver_service.dart b/mobile/lib/features/share_receiver/share_receiver_service.dart index d48386d..7646837 100644 --- a/mobile/lib/features/share_receiver/share_receiver_service.dart +++ b/mobile/lib/features/share_receiver/share_receiver_service.dart @@ -7,68 +7,59 @@ class ShareReceiverService { StreamSubscription? _intentSub; void init(BuildContext context) { - // 1. Listen to shared text/links while app is in memory - _intentSub = ReceiveSharingIntent.getTextStream().listen((String value) { + // 1. Listen to shared media/text while app is in memory + _intentSub = ReceiveSharingIntent.instance.getMediaStream().listen((List value) { if (value.isNotEmpty) { - _handleSharedText(context, value); + _handleSharedMedia(context, value); } }, onError: (err) { - debugPrint("getLinkStream error: $err"); + debugPrint("getMediaStream error: $err"); }); - // 2. Get the shared text/link when the app is launched from closed state - ReceiveSharingIntent.getInitialText().then((String? value) { - if (value != null && value.isNotEmpty) { - _handleSharedText(context, value); - } - }); - - // 3. Listen to shared files/images (e.g. sharing photo from Gallery) - ReceiveSharingIntent.getImageStream().listen((List value) { + // 2. Get the shared media/text when the app is launched from closed state + ReceiveSharingIntent.instance.getInitialMedia().then((List value) { if (value.isNotEmpty) { - _handleSharedFiles(context, value); - } - }, onError: (err) { - debugPrint("getImageStream error: $err"); - }); - - ReceiveSharingIntent.getInitialImage().then((List value) { - if (value.isNotEmpty) { - _handleSharedFiles(context, value); + _handleSharedMedia(context, value); } }); } - void _handleSharedText(BuildContext context, String rawText) { - // Sanitize and extract URL from messy text (e.g. Instagram caption + link) - final urlRegex = RegExp(r'https?://[^\s]+'); - final match = urlRegex.firstMatch(rawText); - final url = match?.group(0); - final rawCaption = rawText.replaceFirst(url ?? '', '').trim(); - - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (ctx) => QuickShareSheet( - url: url, - rawCaption: rawCaption.isNotEmpty ? rawCaption : null, - ), - ); - } - - void _handleSharedFiles(BuildContext context, List files) { + void _handleSharedMedia(BuildContext context, List files) { if (files.isEmpty) return; - final firstFile = files.first; - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (ctx) => QuickShareSheet( - imagePath: firstFile.path, - ), - ); + for (final file in files) { + final path = file.path; + if (path.isEmpty) continue; + + // Check if it's an image file + final lower = path.toLowerCase(); + if (file.type == SharedMediaType.image || lower.endsWith('.jpg') || lower.endsWith('.png') || lower.endsWith('.jpeg') || lower.endsWith('.webp')) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (ctx) => QuickShareSheet(imagePath: path), + ); + return; + } + + // Otherwise it's shared text or URL + final urlRegex = RegExp(r'https?://[^\s]+'); + final match = urlRegex.firstMatch(path); + final url = match?.group(0); + final rawCaption = path.replaceFirst(url ?? '', '').trim(); + + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (ctx) => QuickShareSheet( + url: url, + rawCaption: rawCaption.isNotEmpty ? rawCaption : null, + ), + ); + return; + } } void dispose() { diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index cac0d95..13993e6 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -21,12 +21,11 @@ dependencies: flutter_secure_storage: ^9.2.2 # Share Target (Android ACTION_SEND & iOS Share Extension) - receive_sharing_intent: ^1.4.5 + receive_sharing_intent: ^1.8.1 # Camera & Image Ingestion for Cookbook OCR camera: ^0.10.5+9 image_picker: ^1.1.1 - image_cropper: ^5.0.1 # Cook Mode (Keep screen awake while hands are messy) wakelock_plus: ^1.2.5