diff --git a/android/app/build.gradle b/android/app/build.gradle index c3c16bfc2b..fad13d045f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -37,7 +37,7 @@ android { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.apps.blt" minSdkVersion 21 - targetSdkVersion 33 + targetSdkVersion 34 multiDexEnabled true versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9625e105df..7c56964006 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/ios/Podfile b/ios/Podfile index 86ead0d6bb..9fffe176c7 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,3 +1,4 @@ + # Uncomment this line to define a global platform for your project platform :ios, '12.0' @@ -42,4 +43,16 @@ post_install do |installer| config.build_settings['ENABLE_BITCODE'] = 'NO' end end -end \ No newline at end of file + + ################ Awesome Notifications pod modification 1 ################### + awesome_pod_file = File.expand_path(File.join('plugins', 'awesome_notifications', 'ios', 'Scripts', 'AwesomePodFile'), '.symlinks') + require awesome_pod_file + update_awesome_pod_build_settings(installer) + ################ Awesome Notifications pod modification 1 ################### +end + +################ Awesome Notifications pod modification 2 ################### +awesome_pod_file = File.expand_path(File.join('plugins', 'awesome_notifications', 'ios', 'Scripts', 'AwesomePodFile'), '.symlinks') +require awesome_pod_file +update_awesome_main_target_settings('Runner', File.dirname(File.realpath(__FILE__)), flutter_root) +################ Awesome Notifications pod modification 2 ################### diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index a2f46a30ac..6d74e4553b 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -140,6 +140,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, BD4815CBF2E43FB6B6E05F7E /* [CP] Embed Pods Frameworks */, + 3D0D20C01154FDD8C26CF626 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -156,7 +157,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -214,6 +215,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 3D0D20C01154FDD8C26CF626 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 769F2DF4327B9A5B0592592B /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -343,7 +361,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -356,7 +374,9 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; @@ -420,7 +440,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -469,7 +489,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -484,7 +504,9 @@ isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; @@ -506,7 +528,9 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826db27..5e31d3d342 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ String? selectedIssueId; // Added to track selected issue's ID String apiBaseUrl = GeneralEndPoints .apiBaseUrl; // Updated to use the correct apiBaseUrl variable + Timer? _timer; //Added for managing the timer @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); + AwesomeNotifications().isNotificationAllowed().then((isAllowed) { + if (!isAllowed) { + AwesomeNotifications().requestPermissionToSendNotifications(); + } + }); + + _initializeNotifications(); //Initialize awesome notifications } @override void dispose() async { - print('Dispose called: isTimerRunning = $isTimerRunning'); WidgetsBinding.instance.removeObserver(this); + _cancelTimer(); //Cancel the timer when disposing if (isTimerRunning) { - await _stopTimer(); // Await the stopTimer to ensure the request completes before disposing + await stopTimer(); // Await the stopTimer to ensure the request completes before disposing } super.dispose(); } - @override - void didChangeAppLifecycleState(AppLifecycleState state) async { - print('AppLifecycleState changed: $state'); + void _initializeNotifications() { + AwesomeNotifications().initialize( + null, //Notification icon + [ + NotificationChannel( + channelKey: 'sizzle_timer_channel', + channelName: 'Sizzle Timer Notifications', + channelDescription: + 'Notifications for Sizzle Timer', //Added channel description + defaultColor: Color(0xFFFD5D00), + importance: NotificationImportance.High, + channelShowBadge: true, + ) + ], + channelGroups: [ + NotificationChannelGroup( + channelGroupKey: 'sizzle_timer_group', + channelGroupName: 'sizzle Timer Group', //Added channel group name + ) + ], + debug: true, + ); + } - if (state == AppLifecycleState.detached) { - // App is detached (e.g., removed from recent apps) - if (isTimerRunning) { - await _stopTimer(); // Await the stopTimer to ensure the request completes - } - } + Future _showNotification() async { + AwesomeNotifications().createNotification( + content: NotificationContent( + id: 14, + channelKey: 'sizzle_timer_channel', + title: 'Timer Stopped', + body: 'The timer has stopped. Are you still working?', + notificationLayout: NotificationLayout.Default, + ), + ); } @override @@ -91,7 +125,7 @@ class _SizzleHomeState extends ConsumerState WidgetsBinding.instance.addPostFrameCallback((_) async { bool isPop = await launchConfirmationDialog(context); if (isPop) { - await _stopTimer(); + await stopTimer(); } }); } @@ -197,8 +231,8 @@ class _SizzleHomeState extends ConsumerState ), floatingActionButton: FloatingActionButton( onPressed: isTimerRunning - ? _stopTimer - : _startTimer, // Added logic to start/stop the timer + ? stopTimer + : startTimer, // Added logic to start/stop the timer child: Icon(isTimerRunning ? Icons.stop : Icons.play_arrow), // Updated icon based on timer state @@ -208,10 +242,11 @@ class _SizzleHomeState extends ConsumerState ); } - Future _startTimer() async { - // Added method to start the timer + Future startTimer() async { if (selectedIssueUrl == null) return; + selectedIssueId = selectedIssueUrl!.split('/').last; + final response = await http.post( Uri.parse('$apiBaseUrl' + 'timelogs/start/'), // Updated to use the correct $apiBaseUrl variable @@ -232,6 +267,7 @@ class _SizzleHomeState extends ConsumerState timeLogId = data['id']; // Store the returned time log ID isTimerRunning = true; // Update the state to indicate the timer is running + _startCountdownTimer(); //Start the countdown for 5 minutes }); } } else { @@ -244,9 +280,20 @@ class _SizzleHomeState extends ConsumerState } } - Future _stopTimer() async { - print(timeLogId); - // Added method to stop the timer + void _startCountdownTimer() { + _cancelTimer(); //Cancel any existing timer + _timer = Timer(Duration(minutes: 30), () async { + await stopTimer(); //Automatically stop the timer after 5 minutes + await _showNotification(); //Show a notification to remind the user + }); + } + + void _cancelTimer() { + _timer?.cancel(); //Cancel the timer + _timer = null; + } + + Future stopTimer() async { if (timeLogId == null) return; final response = await http.post( @@ -266,6 +313,7 @@ class _SizzleHomeState extends ConsumerState false; // Update the state to indicate the timer has stopped timeLogId = null; // Clear the time log ID selectedIssueId = null; // Clear the selected issue ID + _cancelTimer(); //Cancel the countdown timer }); } } else { diff --git a/lib/src/pages/sizzle/sizzle_state_provider.dart b/lib/src/pages/sizzle/sizzle_state_provider.dart index c9403de58f..eba8d2cab8 100644 --- a/lib/src/pages/sizzle/sizzle_state_provider.dart +++ b/lib/src/pages/sizzle/sizzle_state_provider.dart @@ -1,3 +1,4 @@ -import 'package:blt/src/components/components_import.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +// Define your providers here final usernameProvider = StateProvider((ref) => null); diff --git a/pubspec.yaml b/pubspec.yaml index a6f87d9644..f7ad968020 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,6 +37,7 @@ dependencies: lottie: ^3.1.2 webview_flutter: ^3.0.4 permission_handler: ^11.3.1 + awesome_notifications: ^0.9.3+1 dev_dependencies: flutter_launcher_icons: ">=0.9.0 <0.13.0"