diff --git a/android/app/build.gradle b/android/app/build.gradle index efd8f3d1..6c55d97e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,8 +26,13 @@ apply plugin: 'com.google.gms.google-services' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} android { - compileSdkVersion rootProject.ext.compileSdkVersion + compileSdkVersion rootProject.ext.compileSdkVersion ndkVersion flutter.ndkVersion compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -44,7 +49,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.ultimate_alarm_clock" + applicationId "com.ccextractor.ultimate_alarm_clock" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdkVersion 23 @@ -53,14 +58,21 @@ android { versionName flutterVersionName multiDexEnabled true } - + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. minifyEnabled true shrinkResources true - signingConfig signingConfigs.debug + signingConfig signingConfigs.release } } } diff --git a/android/app/google-services.json b/android/app/google-services.json index b743baac..b487a8d6 100644 --- a/android/app/google-services.json +++ b/android/app/google-services.json @@ -1,41 +1,86 @@ { "project_info": { - "project_number": "951082036741", - "project_id": "ulticock-c13a2", - "storage_bucket": "ulticock-c13a2.appspot.com" + "project_number": "127901953489", + "project_id": "uac2-7d0f9", + "storage_bucket": "uac2-7d0f9.appspot.com" }, "client": [ { "client_info": { - "mobilesdk_app_id": "1:951082036741:android:45bc3756a62c480f71766c", + "mobilesdk_app_id": "1:127901953489:android:1c0dea09b93c2b573fc4f0", + "android_client_info": { + "package_name": "com.ccextractor.ultimate_alarm_clock" + } + }, + "oauth_client": [ + { + "client_id": "127901953489-132kstrs7vl5j5jnubjktu0qodgcn9ml.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.ccextractor.ultimate_alarm_clock", + "certificate_hash": "30bf4033c248d9a3ecccbe3615c8baec5f4ed31a" + } + }, + { + "client_id": "127901953489-hgjdtpa0jo2gdrh5vl3s0km66g81v66o.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.ccextractor.ultimate_alarm_clock", + "certificate_hash": "5463a1d268da62e33b869a41760d31cd5ffc1e5d" + } + }, + { + "client_id": "127901953489-lnsmj324f5eutudkjvaidotj99bq1l47.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCEaWUdYF_PnGFu0uJL8Zl_BlT8knDVeHg" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "127901953489-lnsmj324f5eutudkjvaidotj99bq1l47.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:127901953489:android:02cb55ff82004bb03fc4f0", "android_client_info": { "package_name": "com.example.ultimate_alarm_clock" } }, "oauth_client": [ { - "client_id": "951082036741-q9jfduqcvikipre5ubf7774o9b2l822h.apps.googleusercontent.com", + "client_id": "127901953489-09r774m4cup6mlt341i2v9fpbhngmq2h.apps.googleusercontent.com", "client_type": 1, "android_info": { "package_name": "com.example.ultimate_alarm_clock", - "certificate_hash": "af289e1ac935477a575746d95dea1c78156db532" + "certificate_hash": "30bf4033c248d9a3ecccbe3615c8baec5f4ed31a" } }, { - "client_id": "951082036741-5c8vh71vidd27rjihimnemnbdquq1tp2.apps.googleusercontent.com", + "client_id": "127901953489-lnsmj324f5eutudkjvaidotj99bq1l47.apps.googleusercontent.com", "client_type": 3 } ], "api_key": [ { - "current_key": "AIzaSyCEgfAAOgj5oLlX7LtXn_vCoW7AkMj7Qv4" + "current_key": "AIzaSyCEaWUdYF_PnGFu0uJL8Zl_BlT8knDVeHg" } ], "services": { "appinvite_service": { "other_platform_oauth_client": [ { - "client_id": "951082036741-5c8vh71vidd27rjihimnemnbdquq1tp2.apps.googleusercontent.com", + "client_id": "127901953489-lnsmj324f5eutudkjvaidotj99bq1l47.apps.googleusercontent.com", "client_type": 3 } ] diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 52455519..b7fcc27c 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,5 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.example.ultimate_alarm_clock"> + package="com.ccextractor.ultimate_alarm_clock"> <!-- The INTERNET permission is required for development. Specifically, the Flutter tool needs it to communicate with the running application to allow setting breakpoints, to provide hot reload, etc. diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 26cc1170..d27b4e68 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" - package="com.example.ultimate_alarm_clock"> + package="com.ccextractor.ultimate_alarm_clock"> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> @@ -13,95 +14,97 @@ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> - <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" /> - <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE"/> + <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WRITE_SETTINGS" + tools:ignore="ProtectedPermissions" /> + <queries> + <intent> + <action android:name="android.intent.action.VIEW" /> + <data android:scheme="https" /> + </intent> + <intent> + <action android:name="android.intent.action.VIEW" /> + + <data android:scheme="http" /> + </intent> + </queries> <application - tools:replace="android:label" - android:label="Ultimate Alarm Clock" android:name="${applicationName}" - android:icon="@mipmap/launcher_icon"> - + android:icon="@mipmap/launcher_icon" + android:label="Ultimate Alarm Clock" + tools:replace="android:label"> <service - android:name="com.pravera.flutter_foreground_task.service.ForegroundService" /> + android:name=".ScreenMonitorService" + android:enabled="true" + android:exported="true"></service> + <service android:name="com.pravera.flutter_foreground_task.service.ForegroundService" /> - <receiver android:name=".BootReceiver" + <receiver + android:name=".BootReceiver" android:enabled="true" android:exported="false"> - <intent-filter> + <intent-filter android:priority="999"> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> - <receiver android:name=".TimerNotification" android:enabled="true" - android:exported="false"> - </receiver> - - + android:exported="false"></receiver> <receiver android:name=".AlarmReceiver" android:enabled="true" - android:exported="false"> - </receiver> - + android:exported="false"></receiver> <receiver android:name=".TimerReceiver" android:enabled="true" - android:exported="false"> - - </receiver> - + android:exported="false"></receiver> <activity android:name=".MainActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:exported="true" + android:hardwareAccelerated="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" - android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" - android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> - <!-- Specifies an Android theme to apply to this Activity as soon as + + <!-- + Specifies an Android theme to apply to this Activity as soon as the Android process has started. This theme is visible to the user while the Flutter UI initializes. After that, this theme continues - to determine the Window background behind the Flutter UI. --> + to determine the Window background behind the Flutter UI. + --> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> + <intent-filter> <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> -<activity - android:name="io.flutter.embedding.android.FlutterActivity" - android:theme="@style/LaunchTheme" - android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" - android:hardwareAccelerated="true" - android:windowSoftInputMode="adjustResize" - /> - <!-- Don't delete the meta-data below. - This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> + <activity + android:name="io.flutter.embedding.android.FlutterActivity" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" + android:hardwareAccelerated="true" + android:theme="@style/LaunchTheme" + android:windowSoftInputMode="adjustResize" /> + <!-- + Don't delete the meta-data below. + This is used by the Flutter tool to generate GeneratedPluginRegistrant.java + --> <meta-data android:name="flutterEmbedding" android:value="2" /> - - </application> - <queries> - <intent> - <action android:name="android.intent.action.VIEW" /> - <data android:scheme="https" /> - </intent> - <intent> - <action android:name="android.intent.action.VIEW" /> - <data android:scheme="http" /> - </intent> - </queries> -</manifest> + +</manifest> \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/AlarmReceiver.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/AlarmReceiver.kt new file mode 100644 index 00000000..b778aa5a --- /dev/null +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/AlarmReceiver.kt @@ -0,0 +1,35 @@ +package com.ccextractor.ultimate_alarm_clock + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent + + +class AlarmReceiver : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (context == null || intent == null) { + return + } + + + val flutterIntent = Intent(context, MainActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) + + putExtra("initialRoute", "/") + putExtra("alarmRing", "true") + putExtra("isAlarm", "true") + + } + val sharedPreferences = + context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE) + + val screenOnTimeInMillis = sharedPreferences.getLong("flutter.is_screen_on", 0L) + val screenOffTimeInMillis = sharedPreferences.getLong("flutter.is_screen_off", 0L) + val activityCheckIntent = Intent(context, ScreenMonitorService::class.java) + context.stopService(activityCheckIntent) + if (Math.abs(screenOnTimeInMillis - screenOffTimeInMillis) < 180000 || screenOnTimeInMillis - screenOffTimeInMillis == 0L) { + println("ANDROID STARTING APP") + context.startActivity(flutterIntent) + } + } +} diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/BootReceiver.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/BootReceiver.kt similarity index 64% rename from android/app/src/main/kotlin/com/example/ultimate_alarm_clock/BootReceiver.kt rename to android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/BootReceiver.kt index a935253f..b1693ea0 100644 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/BootReceiver.kt +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/BootReceiver.kt @@ -1,5 +1,6 @@ -package com.example.ultimate_alarm_clock +package com.ccextractor.ultimate_alarm_clock +import android.annotation.SuppressLint import android.app.AlarmManager import android.app.PendingIntent import android.content.BroadcastReceiver @@ -11,12 +12,14 @@ import android.app.NotificationManager import android.os.Build import android.os.CountDownTimer import androidx.core.app.NotificationCompat +import com.ccextractor.ultimate_alarm_clocks.getLatestTimer class BootReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { - if (intent.action == Intent.ACTION_BOOT_COMPLETED){ + + if (intent.action == Intent.ACTION_BOOT_COMPLETED) { val dbHelper = DatabaseHelper(context) val db = dbHelper.readableDatabase @@ -26,29 +29,28 @@ class BootReceiver : BroadcastReceiver() { scheduleAlarm(ringTime, context) } - val timerdbhelper = TimerDatabaseHelper(context) - val timerdb = timerdbhelper.readableDatabase - val time = getLatestTimer(timerdb) - timerdb.close() - var notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - val commonTimer = CommonTimerManager.getCommonTimer(object : TimerListener { - override fun onTick(millisUntilFinished: Long) { - println(millisUntilFinished) - showTimerNotification(millisUntilFinished,"Timer",context) - - } - - override fun onFinish() { - notificationManager.cancel(1) - } - }) + val timerdbhelper = TimerDatabaseHelper(context) + val timerdb = timerdbhelper.readableDatabase + val time = getLatestTimer(timerdb) + timerdb.close() + var notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val commonTimer = CommonTimerManager.getCommonTimer(object : TimerListener { + override fun onTick(millisUntilFinished: Long) { + println(millisUntilFinished) + showTimerNotification(millisUntilFinished, "Timer", context) + } + override fun onFinish() { + notificationManager.cancel(1) + } + }) createNotificationChannel(context) - if (time!=null){ + if (time != null) { // Start or stop the timer based on your requirements commonTimer.startTimer(time.second) @@ -56,7 +58,9 @@ class BootReceiver : BroadcastReceiver() { } - }} + } + } + fun scheduleAlarm(milliSeconds: Long, context: Context) { val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager val intent = Intent(context, AlarmReceiver::class.java) @@ -71,6 +75,7 @@ class BootReceiver : BroadcastReceiver() { val triggerTime = SystemClock.elapsedRealtime() + milliSeconds alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime, pendingIntent) } + private fun createNotificationChannel(context: Context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -86,21 +91,23 @@ class BootReceiver : BroadcastReceiver() { } - private fun showTimerNotification(milliseconds: Long,timerName:String,context: Context){ - var notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - val deleteIntent = Intent(context,TimerNotification::class.java) - deleteIntent.action = "com.example.ultimate_alarm_clock.STOP_TIMERNOTIF" - val deletePendingIntent = PendingIntent.getBroadcast(context, 5, deleteIntent, - PendingIntent.FLAG_IMMUTABLE) + private fun showTimerNotification(milliseconds: Long, timerName: String, context: Context) { + var notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val deleteIntent = Intent(context, TimerNotification::class.java) + deleteIntent.action = "com.ccextractor.ultimate_alarm_clock.STOP_TIMERNOTIF" + val deletePendingIntent = PendingIntent.getBroadcast( + context, 5, deleteIntent, + PendingIntent.FLAG_IMMUTABLE + ) val notification = NotificationCompat.Builder(context, TimerService.TIMER_CHANNEL_ID) .setSmallIcon(R.mipmap.launcher_icon) .setContentText("$timerName") .setContentText(formatDuration(milliseconds)) .setOnlyAlertOnce(true) .setDeleteIntent(deletePendingIntent) - . - build() - notificationManager.notify(1,notification) + .build() + notificationManager.notify(1, notification) } private fun formatDuration(milliseconds: Long): String { @@ -116,8 +123,4 @@ class BootReceiver : BroadcastReceiver() { } - - - - } diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/CommonTimerManager.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/CommonTimerManager.kt similarity index 95% rename from android/app/src/main/kotlin/com/example/ultimate_alarm_clock/CommonTimerManager.kt rename to android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/CommonTimerManager.kt index e860b1bb..80de1099 100644 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/CommonTimerManager.kt +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/CommonTimerManager.kt @@ -1,4 +1,4 @@ -package com.example.ultimate_alarm_clock +package com.ccextractor.ultimate_alarm_clock import android.os.CountDownTimer diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/DatabaseHelper.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/DatabaseHelper.kt similarity index 91% rename from android/app/src/main/kotlin/com/example/ultimate_alarm_clock/DatabaseHelper.kt rename to android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/DatabaseHelper.kt index d3145d71..2793cf7e 100644 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/DatabaseHelper.kt +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/DatabaseHelper.kt @@ -1,4 +1,4 @@ -package com.example.ultimate_alarm_clock +package com.ccextractor.ultimate_alarm_clock import android.content.Context import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/GetLatestAlarm.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/GetLatestAlarm.kt similarity index 98% rename from android/app/src/main/kotlin/com/example/ultimate_alarm_clock/GetLatestAlarm.kt rename to android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/GetLatestAlarm.kt index 52e80b78..2ed243de 100644 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/GetLatestAlarm.kt +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/GetLatestAlarm.kt @@ -1,4 +1,4 @@ -package com.example.ultimate_alarm_clock +package com.ccextractor.ultimate_alarm_clock import android.database.Cursor import android.database.sqlite.SQLiteDatabase diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/MainActivity.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/MainActivity.kt similarity index 62% rename from android/app/src/main/kotlin/com/example/ultimate_alarm_clock/MainActivity.kt rename to android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/MainActivity.kt index 92448da9..65b18f0c 100644 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/MainActivity.kt +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/MainActivity.kt @@ -1,4 +1,4 @@ -package com.example.ultimate_alarm_clock +package com.ccextractor.ultimate_alarm_clock import android.app.ActivityManager import android.app.AlarmManager @@ -10,8 +10,10 @@ import android.content.IntentFilter import android.media.Ringtone import android.media.RingtoneManager import android.net.Uri +import android.os.Build import android.os.Bundle import android.os.SystemClock +import android.provider.Settings import android.view.WindowManager import androidx.annotation.NonNull import io.flutter.embedding.android.FlutterActivity @@ -19,15 +21,14 @@ import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel -class MainActivity : FlutterActivity() { - +class MainActivity : FlutterActivity() { companion object { const val CHANNEL1 = "ulticlock" const val CHANNEL2 = "timer" - const val ACTION_START_FLUTTER_APP = "com.example.ultimate_alarm_clock" + const val ACTION_START_FLUTTER_APP = "com.ccextractor.ultimate_alarm_clock" const val EXTRA_KEY = "alarmRing" const val ALARM_TYPE = "isAlarm" - private var isAlarm :String? = "true" + private var isAlarm: String? = "true" val alarmConfig = hashMapOf("shouldAlarmRing" to false, "alarmIgnore" to false) private var ringtone: Ringtone? = null } @@ -35,15 +36,12 @@ class MainActivity : FlutterActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) var intentFilter = IntentFilter() - intentFilter.addAction("com.example.ultimate_alarm_clock.START_TIMERNOTIF") - intentFilter.addAction("com.example.ultimate_alarm_clock.STOP_TIMERNOTIF") - context.registerReceiver(TimerNotification(),intentFilter) + intentFilter.addAction("com.ccextractor.ultimate_alarm_clock.START_TIMERNOTIF") + intentFilter.addAction("com.ccextractor.ultimate_alarm_clock.STOP_TIMERNOTIF") + context.registerReceiver(TimerNotification(), intentFilter) } - - - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) @@ -64,54 +62,36 @@ class MainActivity : FlutterActivity() { println("NATIVE SAID NO") } - if(isAlarm == "true") - { + if (isAlarm == "true") { methodChannel1.invokeMethod("appStartup", alarmConfig) } - else if(isAlarm == "false") - { - methodChannel2.invokeMethod("appStartup", alarmConfig) - } - methodChannel2.setMethodCallHandler{ call, result -> - if(call.method == "scheduleTimer") - { - val seconds = call.argument<Int>("milliSeconds") - scheduleTimer(seconds ?: 0) - result.success(null) - } else if (call.method == "cancelTimer") { - println("FLUTTER CALLED CANCEL ALARMS") - cancelAllScheduledTimers() - result.success(null) - } else if (call.method == "bringAppToForeground") { - bringAppToForeground(this) - result.success(null) - } else if (call.method == "playDefaultAlarm") { - playDefaultAlarm(this) - result.success(null) - } else if (call.method == "stopDefaultAlarm") { - stopDefaultAlarm() - result.success(null) - } else if(call.method == "runtimerNotif") - { - val startTimerIntent = Intent("com.example.ultimate_alarm_clock.START_TIMERNOTIF") - context.sendBroadcast(startTimerIntent) - - }else if(call.method == "clearTimerNotif"){ - val stopTimerIntent = Intent("com.example.ultimate_alarm_clock.STOP_TIMERNOTIF") - context.sendBroadcast(stopTimerIntent) - var notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - notificationManager.cancel(1) - } - else - { - result.notImplemented() - } + methodChannel2.setMethodCallHandler { call, result -> + if (call.method == "playDefaultAlarm") { + playDefaultAlarm(this) + result.success(null) + } else if (call.method == "stopDefaultAlarm") { + stopDefaultAlarm() + result.success(null) + } else if (call.method == "runtimerNotif") { + val startTimerIntent = Intent("com.ccextractor.ultimate_alarm_clock.START_TIMERNOTIF") + context.sendBroadcast(startTimerIntent) + + } else if (call.method == "clearTimerNotif") { + val stopTimerIntent = Intent("com.ccextractor.ultimate_alarm_clock.STOP_TIMERNOTIF") + context.sendBroadcast(stopTimerIntent) + var notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.cancel(1) + } else { + result.notImplemented() + } } methodChannel1.setMethodCallHandler { call, result -> if (call.method == "scheduleAlarm") { val seconds = call.argument<Int>("milliSeconds") + val activityCheck = call.argument<Int>("activityMonitor") println("FLUTTER CALLED SCHEDULE") - scheduleAlarm(seconds ?: 0) + scheduleAlarm(seconds ?: 0, activityCheck ?: 0) result.success(null) } else if (call.method == "cancelAllScheduledAlarms") { println("FLUTTER CALLED CANCEL ALARMS") @@ -120,7 +100,7 @@ class MainActivity : FlutterActivity() { } else if (call.method == "bringAppToForeground") { bringAppToForeground(this) result.success(null) - } else if (call.method == "minimizeApp" ) { + } else if (call.method == "minimizeApp") { minimizeApp() result.success(null) } else if (call.method == "playDefaultAlarm") { @@ -136,10 +116,6 @@ class MainActivity : FlutterActivity() { } - - - - fun bringAppToForeground(context: Context) { val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager? val appTasks = activityManager?.appTasks @@ -157,7 +133,7 @@ class MainActivity : FlutterActivity() { } - private fun scheduleAlarm(milliSeconds: Int) { + private fun scheduleAlarm(milliSeconds: Int, activityMonitor: Int) { val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager val intent = Intent(this, AlarmReceiver::class.java) @@ -167,26 +143,33 @@ class MainActivity : FlutterActivity() { intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE ) - - // Schedule the alarm - val triggerTime = SystemClock.elapsedRealtime() + milliSeconds - alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime, pendingIntent) - } - - private fun scheduleTimer(milliSeconds: Int) { - - val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager - val intent = Intent(this, TimerReceiver::class.java) - val pendingIntent = PendingIntent.getBroadcast( + val activityCheckIntent = Intent(this, ScreenMonitorService::class.java) + val pendingActivityCheckIntent = PendingIntent.getService( this, - 1, - intent, + 4, + activityCheckIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE ) - // Schedule the alarm + val tenMinutesInMilliseconds = 600000L + val preTriggerTime = + SystemClock.elapsedRealtime() + (milliSeconds - tenMinutesInMilliseconds) val triggerTime = SystemClock.elapsedRealtime() + milliSeconds - println(triggerTime) + if (activityMonitor == 1) { + alarmManager.setExact( + AlarmManager.ELAPSED_REALTIME_WAKEUP, + preTriggerTime, + pendingActivityCheckIntent + ) + } else { + val sharedPreferences = + getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE) + val editor = sharedPreferences.edit() + editor.putLong("flutter.is_screen_off", 0L) + editor.apply() + editor.putLong("flutter.is_screen_on", 0L) + editor.apply() + } alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime, pendingIntent) } @@ -201,23 +184,20 @@ class MainActivity : FlutterActivity() { PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE ) - // Cancel any existing alarms by providing the same pending intent - alarmManager.cancel(pendingIntent) - pendingIntent.cancel() - } - private fun cancelAllScheduledTimers() { - val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager - val intent = Intent(this, TimerReceiver::class.java) - val pendingIntent = PendingIntent.getBroadcast( + val activityCheckIntent = Intent(this, ScreenMonitorService::class.java) + val pendingActivityCheckIntent = PendingIntent.getService( this, - 1, - intent, + 4, + activityCheckIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE ) // Cancel any existing alarms by providing the same pending intent alarmManager.cancel(pendingIntent) pendingIntent.cancel() + alarmManager.cancel(pendingActivityCheckIntent) + pendingActivityCheckIntent.cancel() + } private fun playDefaultAlarm(context: Context) { @@ -229,4 +209,12 @@ class MainActivity : FlutterActivity() { private fun stopDefaultAlarm() { ringtone?.stop() } + + private fun openAndroidPermissionsMenu() { + val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS) + intent.data = Uri.parse("package:${packageName}") + startActivity(intent) + } + + } diff --git a/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/ScreenMonitorService.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/ScreenMonitorService.kt new file mode 100644 index 00000000..cff24dc0 --- /dev/null +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/ScreenMonitorService.kt @@ -0,0 +1,132 @@ +package com.ccextractor.ultimate_alarm_clock + +import android.app.Service +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.hardware.display.DisplayManager +import android.os.IBinder +import android.util.Log +import android.view.Display +import java.util.Calendar +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent + +import android.content.SharedPreferences + +import androidx.core.app.NotificationCompat +import java.util.Date + +class ScreenMonitorService : Service() { + + private val CHANNEL_ID = "wake_up_activity_monitor_channel" + private val notificationId = 3 + + private lateinit var receiver: ScreenBroadcastReceiver + private lateinit var sharedPreferences: SharedPreferences + private lateinit var displayManager: DisplayManager + + override fun onCreate() { + super.onCreate() + + sharedPreferences = getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE) + displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager + + createNotificationChannel() + + val intentFilter = IntentFilter(Intent.ACTION_SCREEN_ON).apply { + addAction(Intent.ACTION_SCREEN_OFF) + } + receiver = ScreenBroadcastReceiver() + registerReceiver(receiver, intentFilter) + val currentDate = Date() + val currentTimeMillis = currentDate.time + Log.d("ScreenMonitorService", "time: $currentTimeMillis") + // Check initial screen state on service creation + if (displayManager.getDisplay(0).getState() == Display.STATE_ON) { + updateScreenStatus(currentTimeMillis, true) + } else { + updateScreenStatus(currentTimeMillis, false) + } + } + + private fun createNotificationChannel() { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + val name = "Wake up activity" + val description = "Checking if user awake" + val importance = NotificationManager.IMPORTANCE_MIN + + val channel = NotificationChannel(CHANNEL_ID, name, importance) + channel.description = description + + // Register the channel with the system; you can also configure its behavior (e.g., sound) here + val notificationManager = + getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.createNotificationChannel(channel) + } + } + + private fun updateScreenStatus(time: Long, isScreenOn: Boolean) { + val editor = sharedPreferences.edit() + if (isScreenOn) { + editor.putLong("flutter.is_screen_on", time) + } else { + editor.putLong("flutter.is_screen_off", time) + } + editor.apply() + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + startForeground(notificationId, getNotification()) + return START_STICKY + } + + private fun getNotification(): Notification { + val intent = Intent(this, MainActivity::class.java) // Replace with your main activity + val pendingIntent = + PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE) + + val notification = NotificationCompat.Builder(this, CHANNEL_ID) + .setContentTitle("Wake up activity") + .setContentText("Checking if user is awake") + .setSmallIcon(R.mipmap.launcher_icon) // Replace with your icon drawable + .setContentIntent(pendingIntent) + .setOngoing(true) + .setCategory(Notification.CATEGORY_SERVICE) + + return notification.build() + } + + override fun onDestroy() { + super.onDestroy() + unregisterReceiver(receiver) + } + + override fun onBind(p0: Intent?): IBinder? { + return null + } + + +} + +class ScreenBroadcastReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val action = intent.action + val sharedPreferences = + context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE) + val currentDate = Date() + val mSec = currentDate.time + val editor = sharedPreferences.edit() + Log.d("ScreenBroadcastReceiver", "time: $mSec") + if (action == Intent.ACTION_SCREEN_ON) { + editor.putLong("flutter.is_screen_on", mSec) + editor.apply() + } else if (action == Intent.ACTION_SCREEN_OFF) { + editor.putLong("flutter.is_screen_off", mSec) + editor.apply() + } + } +} diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerFunctions.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerBroadcasts/TimerFunctions.kt similarity index 62% rename from android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerFunctions.kt rename to android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerBroadcasts/TimerFunctions.kt index d6e9fbdb..41d08445 100644 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerFunctions.kt +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerBroadcasts/TimerFunctions.kt @@ -1,16 +1,17 @@ -package com.example.ultimate_alarm_clock - +package com.ccextractor.ultimate_alarm_clocks import android.content.ContentValues import android.database.Cursor import android.database.sqlite.SQLiteDatabase +import android.database.sqlite.SQLiteException import java.text.SimpleDateFormat import java.util.* fun getLatestTimer(db: SQLiteDatabase): Triple<Int, Long, String>? { - val cursor = db.rawQuery( - """ + try { + val cursor = db.rawQuery( + """ SELECT id, timerValue, timeElapsed, timerName, startedOn FROM timers WHERE isPaused = 0 @@ -18,20 +19,31 @@ fun getLatestTimer(db: SQLiteDatabase): Triple<Int, Long, String>? { ORDER BY (timerValue - timeElapsed) ASC LIMIT 1; """, null - ) + ) + return if (cursor.moveToFirst()) { + val timer = TimerModel.fromCursor(cursor) + cursor.close() + val intervalToTimer = isFutureDatetimeWithMillis(timer.startedOn, timer.timerValue.toLong()) + Triple(timer.id, intervalToTimer.toLong(), timer.timerName) - return if (cursor.moveToFirst()) { - val timer = TimerModel.fromCursor(cursor) - cursor.close() - val intervalToTimer = isFutureDatetimeWithMillis(timer.startedOn,timer.timerValue.toLong()) - Triple(timer.id, intervalToTimer.toLong(),timer.timerName) + } else { + cursor.close() + null + } - } else - { - cursor.close() - null + } catch (e: SQLiteException) { + db.rawQuery(""" create table timers ( + id integer primary key autoincrement, + startedOn text not null, + timerValue integer not null, + timeElapsed integer not null, + ringtoneName text not null, + timerName text not null, + isPaused integer not null)""",null) } + return null } + fun pauseTimer(db: SQLiteDatabase, timerId: Int): Boolean { val contentValues = ContentValues() contentValues.put("isPaused", 1) @@ -60,8 +72,13 @@ fun isFutureDatetimeWithMillis(datetimeString: String, milliseconds: Long): Long } - -private data class TimerModel(val id: Int, val timerValue: Int, val timeElapsed : Int, val timerName: String, val startedOn: String) { +private data class TimerModel( + val id: Int, + val timerValue: Int, + val timeElapsed: Int, + val timerName: String, + val startedOn: String +) { companion object { fun fromCursor(cursor: Cursor): TimerModel { val id = cursor.getInt(cursor.getColumnIndex("id")) @@ -69,7 +86,7 @@ private data class TimerModel(val id: Int, val timerValue: Int, val timeElapsed val timeElapsed = cursor.getInt(cursor.getColumnIndex("timeElapsed")) val timerName = cursor.getString(cursor.getColumnIndex("timerName")) val startedOn = cursor.getString(cursor.getColumnIndex("startedOn")) - return TimerModel(id, timerValue, timeElapsed,timerName,startedOn) + return TimerModel(id, timerValue, timeElapsed, timerName, startedOn) } } } diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerNotification.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerBroadcasts/TimerNotification.kt similarity index 60% rename from android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerNotification.kt rename to android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerBroadcasts/TimerNotification.kt index 28a0338e..aa203e0c 100644 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerNotification.kt +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerBroadcasts/TimerNotification.kt @@ -1,4 +1,4 @@ -package com.example.ultimate_alarm_clock +package com.ccextractor.ultimate_alarm_clock import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent @@ -7,16 +7,20 @@ import android.content.Context import android.content.Intent import android.os.Build import androidx.core.app.NotificationCompat +import com.ccextractor.ultimate_alarm_clocks.getLatestTimer -class TimerNotification: BroadcastReceiver() { + +class TimerNotification : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val timerdbhelper = TimerDatabaseHelper(context) val timerdb = timerdbhelper.readableDatabase val time = getLatestTimer(timerdb) - var notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + timerdb.close() + var notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val commonTimer = CommonTimerManager.getCommonTimer(object : TimerListener { override fun onTick(millisUntilFinished: Long) { - showTimerNotification(millisUntilFinished,"Timer",context) + showTimerNotification(millisUntilFinished, "Timer", context) } override fun onFinish() { @@ -24,13 +28,12 @@ class TimerNotification: BroadcastReceiver() { } }) - if(intent.action =="com.example.ultimate_alarm_clock.START_TIMERNOTIF" || intent.action == Intent.ACTION_BOOT_COMPLETED ) - { + if (intent.action == "com.ccextractor.ultimate_alarm_clock.START_TIMERNOTIF" || intent.action == Intent.ACTION_BOOT_COMPLETED) { createNotificationChannel(context) - if (time!=null){ + if (time != null) { // Start or stop the timer based on your requirements commonTimer.startTimer(time.second) @@ -38,15 +41,16 @@ class TimerNotification: BroadcastReceiver() { } } - if(intent.action=="com.example.ultimate_alarm_clock.STOP_TIMERNOTIF"){ + if (intent.action == "com.ccextractor.ultimate_alarm_clock.STOP_TIMERNOTIF") { - commonTimer.stopTimer() + commonTimer.stopTimer() } } -private fun createNotificationChannel(context: Context) { + + private fun createNotificationChannel(context: Context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( @@ -61,24 +65,26 @@ private fun createNotificationChannel(context: Context) { } - private fun showTimerNotification(milliseconds: Long,timerName:String,context: Context){ - var notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - val deleteIntent = Intent(context,TimerNotification::class.java) - deleteIntent.action = "com.example.ultimate_alarm_clock.STOP_TIMERNOTIF" - val deletePendingIntent = PendingIntent.getBroadcast(context, 5, deleteIntent, - PendingIntent.FLAG_IMMUTABLE) + private fun showTimerNotification(milliseconds: Long, timerName: String, context: Context) { + var notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val deleteIntent = Intent(context, TimerNotification::class.java) + deleteIntent.action = "com.ccextractor.ultimate_alarm_clock.STOP_TIMERNOTIF" + val deletePendingIntent = PendingIntent.getBroadcast( + context, 5, deleteIntent, + PendingIntent.FLAG_IMMUTABLE + ) val notification = NotificationCompat.Builder(context, TimerService.TIMER_CHANNEL_ID) .setSmallIcon(R.mipmap.launcher_icon) .setContentText("$timerName") .setContentText(formatDuration(milliseconds)) .setOnlyAlertOnce(true) .setDeleteIntent(deletePendingIntent) - . - build() - notificationManager.notify(1,notification) + .build() + notificationManager.notify(1, notification) } - private fun formatDuration(milliseconds: Long): String { + private fun formatDuration(milliseconds: Long): String { val seconds = (milliseconds / 1000) % 60 val minutes = (milliseconds / (1000 * 60)) % 60 val hours = (milliseconds / (1000 * 60 * 60)) % 24 @@ -91,6 +97,4 @@ private fun createNotificationChannel(context: Context) { } - - } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerDatabaseHelper.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerDatabaseHelper.kt similarity index 57% rename from android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerDatabaseHelper.kt rename to android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerDatabaseHelper.kt index 09a2a795..7b103b99 100644 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerDatabaseHelper.kt +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerDatabaseHelper.kt @@ -1,4 +1,4 @@ -package com.example.ultimate_alarm_clock +package com.ccextractor.ultimate_alarm_clock import android.content.Context import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper @@ -11,14 +11,7 @@ class TimerDatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE } override fun onCreate(db: SQLiteDatabase) { - db.rawQuery(""" create table timers ( - id integer primary key autoincrement, - startedOn text not null, - timerValue integer not null, - timeElapsed integer not null, - ringtoneName text not null, - timerName text not null, - isPaused integer not null)""",null) + } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerReceiver.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerReceiver.kt similarity index 90% rename from android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerReceiver.kt rename to android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerReceiver.kt index 4ff4a999..7ff8a3c4 100644 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerReceiver.kt +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerReceiver.kt @@ -1,4 +1,4 @@ -package com.example.ultimate_alarm_clock +package com.ccextractor.ultimate_alarm_clock import android.content.BroadcastReceiver import android.content.Context @@ -20,7 +20,7 @@ class TimerReceiver : BroadcastReceiver() { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) putExtra("initialRoute", "/") putExtra("alarmRing", "false") - putExtra("isAlarm","true") + putExtra("isAlarm", "true") } println("ANDROID STARTING APP") diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerService.kt b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerService.kt similarity index 68% rename from android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerService.kt rename to android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerService.kt index e5371589..0c2a055b 100644 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerService.kt +++ b/android/app/src/main/kotlin/com/ccextractor/ultimate_alarm_clock/ultimate_alarm_clock/TimerService.kt @@ -1,4 +1,4 @@ -package com.example.ultimate_alarm_clock +package com.ccextractor.ultimate_alarm_clock class TimerService { companion object{ diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/AlarmReceiver.kt b/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/AlarmReceiver.kt deleted file mode 100644 index ff940a5c..00000000 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/AlarmReceiver.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.example.ultimate_alarm_clock - -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.os.Handler -import android.os.Looper -import io.flutter.embedding.android.FlutterActivity -import android.os.Bundle - - -class AlarmReceiver : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - if (context == null || intent == null) { - return - } - - - val flutterIntent = Intent(context, MainActivity::class.java).apply { - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) - - putExtra("initialRoute", "/") - putExtra("alarmRing", "true") - putExtra("isAlarm","true") - - } - - println("ANDROID STARTING APP") - context.startActivity(flutterIntent) - } -} diff --git a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerBroadcasts/CancelTimer.kt b/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerBroadcasts/CancelTimer.kt deleted file mode 100644 index 7bd9ced1..00000000 --- a/android/app/src/main/kotlin/com/example/ultimate_alarm_clock/TimerBroadcasts/CancelTimer.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.example.ultimate_alarm_clock.TimerBroadcasts - -import android.app.NotificationManager -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import com.example.ultimate_alarm_clock.CommonTimerManager -import com.example.ultimate_alarm_clock.TimerListener - -class CancelTimer : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent?) { - var notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - val commonTimer = CommonTimerManager.getCommonTimer(object : TimerListener { - override fun onTick(millisUntilFinished: Long) { - } - override fun onFinish() { - notificationManager.cancel(1) - } - }) - commonTimer.stopTimer() - } -} \ No newline at end of file diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index 52455519..b7fcc27c 100644 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,5 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.example.ultimate_alarm_clock"> + package="com.ccextractor.ultimate_alarm_clock"> <!-- The INTERNET permission is required for development. Specifically, the Flutter tool needs it to communicate with the running application to allow setting breakpoints, to provide hot reload, etc. diff --git a/lib/app/data/models/alarm_model.dart b/lib/app/data/models/alarm_model.dart index 5cb9db96..5d8d9493 100644 --- a/lib/app/data/models/alarm_model.dart +++ b/lib/app/data/models/alarm_model.dart @@ -50,51 +50,51 @@ class AlarmModel { late bool showMotivationalQuote; late double volMax; late double volMin; - + late int activityMonitor; @ignore Map? offsetDetails; - AlarmModel({ - required this.alarmTime, - required this.alarmID, - this.sharedUserIds = const [], - required this.ownerId, - required this.ownerName, - required this.lastEditedUserId, - required this.mutexLock, - this.isEnabled = true, - required this.days, - required this.intervalToAlarm, - required this.isActivityEnabled, - required this.minutesSinceMidnight, - required this.isLocationEnabled, - required this.isSharedAlarmEnabled, - required this.isWeatherEnabled, - required this.location, - required this.weatherTypes, - required this.isMathsEnabled, - required this.mathsDifficulty, - required this.numMathsQuestions, - required this.isShakeEnabled, - required this.shakeTimes, - required this.isQrEnabled, - required this.qrValue, - required this.isPedometerEnabled, - required this.numberOfSteps, - required this.activityInterval, - this.offsetDetails = const {}, - required this.mainAlarmTime, - required this.label, - required this.isOneTime, - required this.snoozeDuration, - required this.gradient, - required this.ringtoneName, - required this.note, - required this.deleteAfterGoesOff, - required this.showMotivationalQuote, - required this.volMax, - required this.volMin, - }); + AlarmModel( + {required this.alarmTime, + required this.alarmID, + this.sharedUserIds = const [], + required this.ownerId, + required this.ownerName, + required this.lastEditedUserId, + required this.mutexLock, + this.isEnabled = true, + required this.days, + required this.intervalToAlarm, + required this.isActivityEnabled, + required this.minutesSinceMidnight, + required this.isLocationEnabled, + required this.isSharedAlarmEnabled, + required this.isWeatherEnabled, + required this.location, + required this.weatherTypes, + required this.isMathsEnabled, + required this.mathsDifficulty, + required this.numMathsQuestions, + required this.isShakeEnabled, + required this.shakeTimes, + required this.isQrEnabled, + required this.qrValue, + required this.isPedometerEnabled, + required this.numberOfSteps, + required this.activityInterval, + this.offsetDetails = const {}, + required this.mainAlarmTime, + required this.label, + required this.isOneTime, + required this.snoozeDuration, + required this.gradient, + required this.ringtoneName, + required this.note, + required this.deleteAfterGoesOff, + required this.showMotivationalQuote, + required this.volMax, + required this.volMin, + required this.activityMonitor}); AlarmModel.fromDocumentSnapshot({ required firestore.DocumentSnapshot documentSnapshot, @@ -155,50 +155,52 @@ class AlarmModel { volMax = documentSnapshot['volMax']; volMin = documentSnapshot['volMin']; + + activityMonitor = documentSnapshot['activityMonitor']; } AlarmModel fromMapSQFlite(Map<String, dynamic> map) { return AlarmModel( - alarmTime: map['alarmTime'], - alarmID: map['alarmID'], - isEnabled: map['isEnabled'] == 1, - isLocationEnabled: map['isLocationEnabled'] == 1, - isSharedAlarmEnabled: map['isSharedAlarmEnabled'] == 1, - isWeatherEnabled: map['isWeatherEnabled'] == 1, - location: map['location'], - activityInterval: map['activityInterval'], - minutesSinceMidnight: map['minutesSinceMidnight'], - days: stringToBoolList(map['days']), - weatherTypes: List<int>.from(jsonDecode(map['weatherTypes'])), - isMathsEnabled: map['isMathsEnabled'] == 1, - mathsDifficulty: map['mathsDifficulty'], - numMathsQuestions: map['numMathsQuestions'], - isShakeEnabled: map['isShakeEnabled'] == 1, - shakeTimes: map['shakeTimes'], - isQrEnabled: map['isQrEnabled'] == 1, - qrValue: map['qrValue'], - isPedometerEnabled: map['isPedometerEnabled'] == 1, - numberOfSteps: map['numberOfSteps'], - intervalToAlarm: map['intervalToAlarm'], - isActivityEnabled: map['isActivityEnabled'] == 1, - sharedUserIds: map['sharedUserIds'] != null - ? List<String>.from(jsonDecode(map['sharedUserIds'])) - : null, - ownerId: map['ownerId'], - ownerName: map['ownerName'], - lastEditedUserId: map['lastEditedUserId'], - mutexLock: map['mutexLock'] == 1, - mainAlarmTime: map['mainAlarmTime'], - label: map['label'], - isOneTime: map['isOneTime'] == 1, - snoozeDuration: map['snoozeDuration'], - gradient: map['gradient'], - ringtoneName: map['ringtoneName'], - note: map['note'], - deleteAfterGoesOff: map['deleteAfterGoesOff'] == 1, - showMotivationalQuote: map['showMotivationalQuote'] == 1, - volMin: map['volMin'], - volMax: map['volMax'], - ); + alarmTime: map['alarmTime'], + alarmID: map['alarmID'], + isEnabled: map['isEnabled'] == 1, + isLocationEnabled: map['isLocationEnabled'] == 1, + isSharedAlarmEnabled: map['isSharedAlarmEnabled'] == 1, + isWeatherEnabled: map['isWeatherEnabled'] == 1, + location: map['location'], + activityInterval: map['activityInterval'], + minutesSinceMidnight: map['minutesSinceMidnight'], + days: stringToBoolList(map['days']), + weatherTypes: List<int>.from(jsonDecode(map['weatherTypes'])), + isMathsEnabled: map['isMathsEnabled'] == 1, + mathsDifficulty: map['mathsDifficulty'], + numMathsQuestions: map['numMathsQuestions'], + isShakeEnabled: map['isShakeEnabled'] == 1, + shakeTimes: map['shakeTimes'], + isQrEnabled: map['isQrEnabled'] == 1, + qrValue: map['qrValue'], + isPedometerEnabled: map['isPedometerEnabled'] == 1, + numberOfSteps: map['numberOfSteps'], + intervalToAlarm: map['intervalToAlarm'], + isActivityEnabled: map['isActivityEnabled'] == 1, + sharedUserIds: map['sharedUserIds'] != null + ? List<String>.from(jsonDecode(map['sharedUserIds'])) + : null, + ownerId: map['ownerId'], + ownerName: map['ownerName'], + lastEditedUserId: map['lastEditedUserId'], + mutexLock: map['mutexLock'] == 1, + mainAlarmTime: map['mainAlarmTime'], + label: map['label'], + isOneTime: map['isOneTime'] == 1, + snoozeDuration: map['snoozeDuration'], + gradient: map['gradient'], + ringtoneName: map['ringtoneName'], + note: map['note'], + deleteAfterGoesOff: map['deleteAfterGoesOff'] == 1, + showMotivationalQuote: map['showMotivationalQuote'] == 1, + volMin: map['volMin'], + volMax: map['volMax'], + activityMonitor: map['activityMonitor']); } Map<String, dynamic> toSQFliteMap() { @@ -242,6 +244,7 @@ class AlarmModel { 'showMotivationalQuote': showMotivationalQuote ? 1 : 0, 'volMin': volMin, 'volMax': volMax, + 'activityMonitor' : activityMonitor }; } @@ -289,6 +292,7 @@ class AlarmModel { volMin = alarmData['volMin']; volMax = alarmData['volMax']; + activityMonitor = alarmData['activityMonitor']; } AlarmModel.fromJson(String alarmData, UserModel? user) { @@ -339,6 +343,7 @@ class AlarmModel { 'showMotivationalQuote': alarmRecord.showMotivationalQuote, 'volMin': alarmRecord.volMin, 'volMax': alarmRecord.volMax, + 'activityMonitor' : alarmRecord.activityMonitor }; if (alarmRecord.isSharedAlarmEnabled) { @@ -347,17 +352,19 @@ class AlarmModel { } return alarmMap; } + String boolListToString(List<bool> boolList) { // Rotate the list to start with Sunday - var rotatedList = [boolList.last] + boolList.sublist(0, boolList.length - 1); + var rotatedList = + [boolList.last] + boolList.sublist(0, boolList.length - 1); // Convert the list of bools to a string of 1s and 0s return rotatedList.map((b) => b ? '1' : '0').join(); } + List<bool> stringToBoolList(String s) { // Rotate the string to start with Monday final rotatedString = s.substring(1) + s[0]; // Convert the rotated string to a list of boolean values return rotatedString.split('').map((c) => c == '1').toList(); } - } diff --git a/lib/app/data/models/alarm_model.g.dart b/lib/app/data/models/alarm_model.g.dart index 2be2a3e0..d42a0f12 100644 --- a/lib/app/data/models/alarm_model.g.dart +++ b/lib/app/data/models/alarm_model.g.dart @@ -22,193 +22,198 @@ const AlarmModelSchema = CollectionSchema( name: r'activityInterval', type: IsarType.long, ), - r'alarmID': PropertySchema( + r'activityMonitor': PropertySchema( id: 1, + name: r'activityMonitor', + type: IsarType.long, + ), + r'alarmID': PropertySchema( + id: 2, name: r'alarmID', type: IsarType.string, ), r'alarmTime': PropertySchema( - id: 2, + id: 3, name: r'alarmTime', type: IsarType.string, ), r'days': PropertySchema( - id: 3, + id: 4, name: r'days', type: IsarType.boolList, ), r'deleteAfterGoesOff': PropertySchema( - id: 4, + id: 5, name: r'deleteAfterGoesOff', type: IsarType.bool, ), r'firestoreId': PropertySchema( - id: 5, + id: 6, name: r'firestoreId', type: IsarType.string, ), r'gradient': PropertySchema( - id: 6, + id: 7, name: r'gradient', type: IsarType.long, ), r'intervalToAlarm': PropertySchema( - id: 7, + id: 8, name: r'intervalToAlarm', type: IsarType.long, ), r'isActivityEnabled': PropertySchema( - id: 8, + id: 9, name: r'isActivityEnabled', type: IsarType.bool, ), r'isEnabled': PropertySchema( - id: 9, + id: 10, name: r'isEnabled', type: IsarType.bool, ), r'isLocationEnabled': PropertySchema( - id: 10, + id: 11, name: r'isLocationEnabled', type: IsarType.bool, ), r'isMathsEnabled': PropertySchema( - id: 11, + id: 12, name: r'isMathsEnabled', type: IsarType.bool, ), r'isOneTime': PropertySchema( - id: 12, + id: 13, name: r'isOneTime', type: IsarType.bool, ), r'isPedometerEnabled': PropertySchema( - id: 13, + id: 14, name: r'isPedometerEnabled', type: IsarType.bool, ), r'isQrEnabled': PropertySchema( - id: 14, + id: 15, name: r'isQrEnabled', type: IsarType.bool, ), r'isShakeEnabled': PropertySchema( - id: 15, + id: 16, name: r'isShakeEnabled', type: IsarType.bool, ), r'isSharedAlarmEnabled': PropertySchema( - id: 16, + id: 17, name: r'isSharedAlarmEnabled', type: IsarType.bool, ), r'isWeatherEnabled': PropertySchema( - id: 17, + id: 18, name: r'isWeatherEnabled', type: IsarType.bool, ), r'label': PropertySchema( - id: 18, + id: 19, name: r'label', type: IsarType.string, ), r'lastEditedUserId': PropertySchema( - id: 19, + id: 20, name: r'lastEditedUserId', type: IsarType.string, ), r'location': PropertySchema( - id: 20, + id: 21, name: r'location', type: IsarType.string, ), r'mainAlarmTime': PropertySchema( - id: 21, + id: 22, name: r'mainAlarmTime', type: IsarType.string, ), r'mathsDifficulty': PropertySchema( - id: 22, + id: 23, name: r'mathsDifficulty', type: IsarType.long, ), r'minutesSinceMidnight': PropertySchema( - id: 23, + id: 24, name: r'minutesSinceMidnight', type: IsarType.long, ), r'mutexLock': PropertySchema( - id: 24, + id: 25, name: r'mutexLock', type: IsarType.bool, ), r'note': PropertySchema( - id: 25, + id: 26, name: r'note', type: IsarType.string, ), r'numMathsQuestions': PropertySchema( - id: 26, + id: 27, name: r'numMathsQuestions', type: IsarType.long, ), r'numberOfSteps': PropertySchema( - id: 27, + id: 28, name: r'numberOfSteps', type: IsarType.long, ), r'ownerId': PropertySchema( - id: 28, + id: 29, name: r'ownerId', type: IsarType.string, ), r'ownerName': PropertySchema( - id: 29, + id: 30, name: r'ownerName', type: IsarType.string, ), r'qrValue': PropertySchema( - id: 30, + id: 31, name: r'qrValue', type: IsarType.string, ), r'ringtoneName': PropertySchema( - id: 31, + id: 32, name: r'ringtoneName', type: IsarType.string, ), r'shakeTimes': PropertySchema( - id: 32, + id: 33, name: r'shakeTimes', type: IsarType.long, ), r'sharedUserIds': PropertySchema( - id: 33, + id: 34, name: r'sharedUserIds', type: IsarType.stringList, ), r'showMotivationalQuote': PropertySchema( - id: 34, + id: 35, name: r'showMotivationalQuote', type: IsarType.bool, ), r'snoozeDuration': PropertySchema( - id: 35, + id: 36, name: r'snoozeDuration', type: IsarType.long, ), r'volMax': PropertySchema( - id: 36, + id: 37, name: r'volMax', type: IsarType.double, ), r'volMin': PropertySchema( - id: 37, + id: 38, name: r'volMin', type: IsarType.double, ), r'weatherTypes': PropertySchema( - id: 38, + id: 39, name: r'weatherTypes', type: IsarType.longList, ) @@ -279,44 +284,45 @@ void _alarmModelSerialize( Map<Type, List<int>> allOffsets, ) { writer.writeLong(offsets[0], object.activityInterval); - writer.writeString(offsets[1], object.alarmID); - writer.writeString(offsets[2], object.alarmTime); - writer.writeBoolList(offsets[3], object.days); - writer.writeBool(offsets[4], object.deleteAfterGoesOff); - writer.writeString(offsets[5], object.firestoreId); - writer.writeLong(offsets[6], object.gradient); - writer.writeLong(offsets[7], object.intervalToAlarm); - writer.writeBool(offsets[8], object.isActivityEnabled); - writer.writeBool(offsets[9], object.isEnabled); - writer.writeBool(offsets[10], object.isLocationEnabled); - writer.writeBool(offsets[11], object.isMathsEnabled); - writer.writeBool(offsets[12], object.isOneTime); - writer.writeBool(offsets[13], object.isPedometerEnabled); - writer.writeBool(offsets[14], object.isQrEnabled); - writer.writeBool(offsets[15], object.isShakeEnabled); - writer.writeBool(offsets[16], object.isSharedAlarmEnabled); - writer.writeBool(offsets[17], object.isWeatherEnabled); - writer.writeString(offsets[18], object.label); - writer.writeString(offsets[19], object.lastEditedUserId); - writer.writeString(offsets[20], object.location); - writer.writeString(offsets[21], object.mainAlarmTime); - writer.writeLong(offsets[22], object.mathsDifficulty); - writer.writeLong(offsets[23], object.minutesSinceMidnight); - writer.writeBool(offsets[24], object.mutexLock); - writer.writeString(offsets[25], object.note); - writer.writeLong(offsets[26], object.numMathsQuestions); - writer.writeLong(offsets[27], object.numberOfSteps); - writer.writeString(offsets[28], object.ownerId); - writer.writeString(offsets[29], object.ownerName); - writer.writeString(offsets[30], object.qrValue); - writer.writeString(offsets[31], object.ringtoneName); - writer.writeLong(offsets[32], object.shakeTimes); - writer.writeStringList(offsets[33], object.sharedUserIds); - writer.writeBool(offsets[34], object.showMotivationalQuote); - writer.writeLong(offsets[35], object.snoozeDuration); - writer.writeDouble(offsets[36], object.volMax); - writer.writeDouble(offsets[37], object.volMin); - writer.writeLongList(offsets[38], object.weatherTypes); + writer.writeLong(offsets[1], object.activityMonitor); + writer.writeString(offsets[2], object.alarmID); + writer.writeString(offsets[3], object.alarmTime); + writer.writeBoolList(offsets[4], object.days); + writer.writeBool(offsets[5], object.deleteAfterGoesOff); + writer.writeString(offsets[6], object.firestoreId); + writer.writeLong(offsets[7], object.gradient); + writer.writeLong(offsets[8], object.intervalToAlarm); + writer.writeBool(offsets[9], object.isActivityEnabled); + writer.writeBool(offsets[10], object.isEnabled); + writer.writeBool(offsets[11], object.isLocationEnabled); + writer.writeBool(offsets[12], object.isMathsEnabled); + writer.writeBool(offsets[13], object.isOneTime); + writer.writeBool(offsets[14], object.isPedometerEnabled); + writer.writeBool(offsets[15], object.isQrEnabled); + writer.writeBool(offsets[16], object.isShakeEnabled); + writer.writeBool(offsets[17], object.isSharedAlarmEnabled); + writer.writeBool(offsets[18], object.isWeatherEnabled); + writer.writeString(offsets[19], object.label); + writer.writeString(offsets[20], object.lastEditedUserId); + writer.writeString(offsets[21], object.location); + writer.writeString(offsets[22], object.mainAlarmTime); + writer.writeLong(offsets[23], object.mathsDifficulty); + writer.writeLong(offsets[24], object.minutesSinceMidnight); + writer.writeBool(offsets[25], object.mutexLock); + writer.writeString(offsets[26], object.note); + writer.writeLong(offsets[27], object.numMathsQuestions); + writer.writeLong(offsets[28], object.numberOfSteps); + writer.writeString(offsets[29], object.ownerId); + writer.writeString(offsets[30], object.ownerName); + writer.writeString(offsets[31], object.qrValue); + writer.writeString(offsets[32], object.ringtoneName); + writer.writeLong(offsets[33], object.shakeTimes); + writer.writeStringList(offsets[34], object.sharedUserIds); + writer.writeBool(offsets[35], object.showMotivationalQuote); + writer.writeLong(offsets[36], object.snoozeDuration); + writer.writeDouble(offsets[37], object.volMax); + writer.writeDouble(offsets[38], object.volMin); + writer.writeLongList(offsets[39], object.weatherTypes); } AlarmModel _alarmModelDeserialize( @@ -327,45 +333,46 @@ AlarmModel _alarmModelDeserialize( ) { final object = AlarmModel( activityInterval: reader.readLong(offsets[0]), - alarmID: reader.readString(offsets[1]), - alarmTime: reader.readString(offsets[2]), - days: reader.readBoolList(offsets[3]) ?? [], - deleteAfterGoesOff: reader.readBool(offsets[4]), - gradient: reader.readLong(offsets[6]), - intervalToAlarm: reader.readLong(offsets[7]), - isActivityEnabled: reader.readBool(offsets[8]), - isEnabled: reader.readBoolOrNull(offsets[9]) ?? true, - isLocationEnabled: reader.readBool(offsets[10]), - isMathsEnabled: reader.readBool(offsets[11]), - isOneTime: reader.readBool(offsets[12]), - isPedometerEnabled: reader.readBool(offsets[13]), - isQrEnabled: reader.readBool(offsets[14]), - isShakeEnabled: reader.readBool(offsets[15]), - isSharedAlarmEnabled: reader.readBool(offsets[16]), - isWeatherEnabled: reader.readBool(offsets[17]), - label: reader.readString(offsets[18]), - lastEditedUserId: reader.readString(offsets[19]), - location: reader.readString(offsets[20]), - mainAlarmTime: reader.readStringOrNull(offsets[21]), - mathsDifficulty: reader.readLong(offsets[22]), - minutesSinceMidnight: reader.readLong(offsets[23]), - mutexLock: reader.readBool(offsets[24]), - note: reader.readString(offsets[25]), - numMathsQuestions: reader.readLong(offsets[26]), - numberOfSteps: reader.readLong(offsets[27]), - ownerId: reader.readString(offsets[28]), - ownerName: reader.readString(offsets[29]), - qrValue: reader.readString(offsets[30]), - ringtoneName: reader.readString(offsets[31]), - shakeTimes: reader.readLong(offsets[32]), - sharedUserIds: reader.readStringList(offsets[33]), - showMotivationalQuote: reader.readBool(offsets[34]), - snoozeDuration: reader.readLong(offsets[35]), - volMax: reader.readDouble(offsets[36]), - volMin: reader.readDouble(offsets[37]), - weatherTypes: reader.readLongList(offsets[38]) ?? [], + activityMonitor: reader.readLong(offsets[1]), + alarmID: reader.readString(offsets[2]), + alarmTime: reader.readString(offsets[3]), + days: reader.readBoolList(offsets[4]) ?? [], + deleteAfterGoesOff: reader.readBool(offsets[5]), + gradient: reader.readLong(offsets[7]), + intervalToAlarm: reader.readLong(offsets[8]), + isActivityEnabled: reader.readBool(offsets[9]), + isEnabled: reader.readBoolOrNull(offsets[10]) ?? true, + isLocationEnabled: reader.readBool(offsets[11]), + isMathsEnabled: reader.readBool(offsets[12]), + isOneTime: reader.readBool(offsets[13]), + isPedometerEnabled: reader.readBool(offsets[14]), + isQrEnabled: reader.readBool(offsets[15]), + isShakeEnabled: reader.readBool(offsets[16]), + isSharedAlarmEnabled: reader.readBool(offsets[17]), + isWeatherEnabled: reader.readBool(offsets[18]), + label: reader.readString(offsets[19]), + lastEditedUserId: reader.readString(offsets[20]), + location: reader.readString(offsets[21]), + mainAlarmTime: reader.readStringOrNull(offsets[22]), + mathsDifficulty: reader.readLong(offsets[23]), + minutesSinceMidnight: reader.readLong(offsets[24]), + mutexLock: reader.readBool(offsets[25]), + note: reader.readString(offsets[26]), + numMathsQuestions: reader.readLong(offsets[27]), + numberOfSteps: reader.readLong(offsets[28]), + ownerId: reader.readString(offsets[29]), + ownerName: reader.readString(offsets[30]), + qrValue: reader.readString(offsets[31]), + ringtoneName: reader.readString(offsets[32]), + shakeTimes: reader.readLong(offsets[33]), + sharedUserIds: reader.readStringList(offsets[34]), + showMotivationalQuote: reader.readBool(offsets[35]), + snoozeDuration: reader.readLong(offsets[36]), + volMax: reader.readDouble(offsets[37]), + volMin: reader.readDouble(offsets[38]), + weatherTypes: reader.readLongList(offsets[39]) ?? [], ); - object.firestoreId = reader.readStringOrNull(offsets[5]); + object.firestoreId = reader.readStringOrNull(offsets[6]); object.isarId = id; return object; } @@ -380,25 +387,25 @@ P _alarmModelDeserializeProp<P>( case 0: return (reader.readLong(offset)) as P; case 1: - return (reader.readString(offset)) as P; + return (reader.readLong(offset)) as P; case 2: return (reader.readString(offset)) as P; case 3: - return (reader.readBoolList(offset) ?? []) as P; + return (reader.readString(offset)) as P; case 4: - return (reader.readBool(offset)) as P; + return (reader.readBoolList(offset) ?? []) as P; case 5: - return (reader.readStringOrNull(offset)) as P; + return (reader.readBool(offset)) as P; case 6: - return (reader.readLong(offset)) as P; + return (reader.readStringOrNull(offset)) as P; case 7: return (reader.readLong(offset)) as P; case 8: - return (reader.readBool(offset)) as P; + return (reader.readLong(offset)) as P; case 9: - return (reader.readBoolOrNull(offset) ?? true) as P; - case 10: return (reader.readBool(offset)) as P; + case 10: + return (reader.readBoolOrNull(offset) ?? true) as P; case 11: return (reader.readBool(offset)) as P; case 12: @@ -414,27 +421,27 @@ P _alarmModelDeserializeProp<P>( case 17: return (reader.readBool(offset)) as P; case 18: - return (reader.readString(offset)) as P; + return (reader.readBool(offset)) as P; case 19: return (reader.readString(offset)) as P; case 20: return (reader.readString(offset)) as P; case 21: - return (reader.readStringOrNull(offset)) as P; + return (reader.readString(offset)) as P; case 22: - return (reader.readLong(offset)) as P; + return (reader.readStringOrNull(offset)) as P; case 23: return (reader.readLong(offset)) as P; case 24: - return (reader.readBool(offset)) as P; + return (reader.readLong(offset)) as P; case 25: - return (reader.readString(offset)) as P; + return (reader.readBool(offset)) as P; case 26: - return (reader.readLong(offset)) as P; + return (reader.readString(offset)) as P; case 27: return (reader.readLong(offset)) as P; case 28: - return (reader.readString(offset)) as P; + return (reader.readLong(offset)) as P; case 29: return (reader.readString(offset)) as P; case 30: @@ -442,18 +449,20 @@ P _alarmModelDeserializeProp<P>( case 31: return (reader.readString(offset)) as P; case 32: - return (reader.readLong(offset)) as P; + return (reader.readString(offset)) as P; case 33: - return (reader.readStringList(offset)) as P; + return (reader.readLong(offset)) as P; case 34: - return (reader.readBool(offset)) as P; + return (reader.readStringList(offset)) as P; case 35: - return (reader.readLong(offset)) as P; + return (reader.readBool(offset)) as P; case 36: - return (reader.readDouble(offset)) as P; + return (reader.readLong(offset)) as P; case 37: return (reader.readDouble(offset)) as P; case 38: + return (reader.readDouble(offset)) as P; + case 39: return (reader.readLongList(offset) ?? []) as P; default: throw IsarError('Unknown property with id $propertyId'); @@ -611,6 +620,62 @@ extension AlarmModelQueryFilter }); } + QueryBuilder<AlarmModel, AlarmModel, QAfterFilterCondition> + activityMonitorEqualTo(int value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'activityMonitor', + value: value, + )); + }); + } + + QueryBuilder<AlarmModel, AlarmModel, QAfterFilterCondition> + activityMonitorGreaterThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'activityMonitor', + value: value, + )); + }); + } + + QueryBuilder<AlarmModel, AlarmModel, QAfterFilterCondition> + activityMonitorLessThan( + int value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'activityMonitor', + value: value, + )); + }); + } + + QueryBuilder<AlarmModel, AlarmModel, QAfterFilterCondition> + activityMonitorBetween( + int lower, + int upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'activityMonitor', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + QueryBuilder<AlarmModel, AlarmModel, QAfterFilterCondition> alarmIDEqualTo( String value, { bool caseSensitive = true, @@ -3508,6 +3573,19 @@ extension AlarmModelQuerySortBy }); } + QueryBuilder<AlarmModel, AlarmModel, QAfterSortBy> sortByActivityMonitor() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'activityMonitor', Sort.asc); + }); + } + + QueryBuilder<AlarmModel, AlarmModel, QAfterSortBy> + sortByActivityMonitorDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'activityMonitor', Sort.desc); + }); + } + QueryBuilder<AlarmModel, AlarmModel, QAfterSortBy> sortByAlarmID() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'alarmID', Sort.asc); @@ -3964,6 +4042,19 @@ extension AlarmModelQuerySortThenBy }); } + QueryBuilder<AlarmModel, AlarmModel, QAfterSortBy> thenByActivityMonitor() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'activityMonitor', Sort.asc); + }); + } + + QueryBuilder<AlarmModel, AlarmModel, QAfterSortBy> + thenByActivityMonitorDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'activityMonitor', Sort.desc); + }); + } + QueryBuilder<AlarmModel, AlarmModel, QAfterSortBy> thenByAlarmID() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'alarmID', Sort.asc); @@ -4425,6 +4516,12 @@ extension AlarmModelQueryWhereDistinct }); } + QueryBuilder<AlarmModel, AlarmModel, QDistinct> distinctByActivityMonitor() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'activityMonitor'); + }); + } + QueryBuilder<AlarmModel, AlarmModel, QDistinct> distinctByAlarmID( {bool caseSensitive = true}) { return QueryBuilder.apply(this, (query) { @@ -4690,6 +4787,12 @@ extension AlarmModelQueryProperty }); } + QueryBuilder<AlarmModel, int, QQueryOperations> activityMonitorProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'activityMonitor'); + }); + } + QueryBuilder<AlarmModel, String, QQueryOperations> alarmIDProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'alarmID'); diff --git a/lib/app/data/providers/isar_provider.dart b/lib/app/data/providers/isar_provider.dart index 9125e158..f5440da9 100644 --- a/lib/app/data/providers/isar_provider.dart +++ b/lib/app/data/providers/isar_provider.dart @@ -38,7 +38,7 @@ class IsarDb { version: 1, onCreate: (Database db, int version) async { await db.execute(''' - create table timers ( + CREATE TABLE timers ( id integer primary key autoincrement, startedOn text not null, timerValue integer not null, @@ -95,7 +95,8 @@ class IsarDb { deleteAfterGoesOff INTEGER NOT NULL DEFAULT 0, showMotivationalQuote INTEGER NOT NULL DEFAULT 0, volMin REAL, - volMax REAL + volMax REAL, + activityMonitor INTEGER ) '''); await db.execute(''' @@ -338,7 +339,7 @@ class IsarDb { 'timerName', 'isPaused', ]); - if (maps.length > 0) { + if ( maps.length > 0) { return maps.map((timer) => TimerModel.fromMap(timer)).toList(); } return []; diff --git a/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart b/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart index d7340cc1..fdecee49 100644 --- a/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart +++ b/lib/app/modules/addOrUpdateAlarm/controllers/add_or_update_alarm_controller.dart @@ -34,6 +34,7 @@ class AddOrUpdateAlarmController extends GetxController { final selectedTime = DateTime.now().add(const Duration(minutes: 1)).obs; final mainAlarmTime = DateTime.now().add(const Duration(minutes: 1)).obs; final isActivityenabled = false.obs; + final isActivityMonitorenabled = 0.obs; final activityInterval = 0.obs; final isLocationEnabled = false.obs; final isSharedAlarmEnabled = false.obs; @@ -88,6 +89,7 @@ class AddOrUpdateAlarmController extends GetxController { final deleteAfterGoesOff = false.obs; final RxBool showMotivationalQuote = false.obs; + final RxBool useScreenActivity = false.obs; final RxInt gradient = 0.obs; final RxDouble selectedGradientDouble = 0.0.obs; final RxDouble volMin = 0.0.obs; @@ -1036,6 +1038,7 @@ class AddOrUpdateAlarmController extends GetxController { ringtoneName: customRingtoneName.value, note: note.value, showMotivationalQuote: showMotivationalQuote.value, + activityMonitor: isActivityMonitorenabled.value ); } diff --git a/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart b/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart index e9e1fd56..8d457859 100644 --- a/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart +++ b/lib/app/modules/addOrUpdateAlarm/views/add_or_update_alarm_view.dart @@ -164,6 +164,7 @@ class AddOrUpdateAlarmView extends GetView<AddOrUpdateAlarmController> { controller.isPedometerEnabled.value, numberOfSteps: controller.numberOfSteps.value, ringtoneName: controller.customRingtoneName.value, + activityMonitor: controller.isActivityMonitorenabled.value ); // Adding offset details to the database if diff --git a/lib/app/modules/addOrUpdateAlarm/views/screen_activity_tile.dart b/lib/app/modules/addOrUpdateAlarm/views/screen_activity_tile.dart index f80b2423..dc54dc7e 100644 --- a/lib/app/modules/addOrUpdateAlarm/views/screen_activity_tile.dart +++ b/lib/app/modules/addOrUpdateAlarm/views/screen_activity_tile.dart @@ -49,6 +49,16 @@ class ScreenActivityTile extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ + Switch.adaptive( + value: controller.useScreenActivity.value, + activeColor: ksecondaryColor, + onChanged: (value) { + if (value == false) + controller.isActivityMonitorenabled.value = 0; + else + controller.isActivityMonitorenabled.value = 1; + }, + ), NumberPicker( value: controller.activityInterval.value, minValue: 0, @@ -96,6 +106,7 @@ class ScreenActivityTile extends StatelessWidget { }, child: ListTile( title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ FittedBox( alignment: Alignment.centerLeft, @@ -109,54 +120,19 @@ class ScreenActivityTile extends StatelessWidget { ), ), ), - IconButton( - icon: Icon( - Icons.info_sharp, - size: 21, - color: themeController.isLightMode.value - ? kLightPrimaryTextColor.withOpacity(0.45) - : kprimaryTextColor.withOpacity(0.3), - ), - onPressed: () { - Utils.showModal( - context: context, - title: 'Screen activity based cancellation'.tr, - // description: 'This feature will automatically cancel' - // " the alarm if you've been using your device" - // ' for a set number of minutes.', - description: 'screenDescription'.tr, - iconData: Icons.screen_lock_portrait_outlined, - isLightMode: themeController.isLightMode.value, - ); - }, - ), - ], - ), - trailing: Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - children: [ Obx( - () => Text( - controller.activityInterval.value > 0 - ? '${controller.activityInterval.value} min' - : 'Off'.tr, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: (controller.isActivityenabled.value == false) - ? themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor - : themeController.isLightMode.value - ? kLightPrimaryTextColor - : kprimaryTextColor, - ), + () => Switch.adaptive( + value: controller.useScreenActivity.value, + activeColor: ksecondaryColor, + onChanged: (value) { + controller.useScreenActivity.value = value; + if (value == false) + controller.isActivityMonitorenabled.value = 0; + else + controller.isActivityMonitorenabled.value = 1; + }, ), - ), - Icon( - Icons.chevron_right, - color: themeController.isLightMode.value - ? kLightPrimaryDisabledTextColor - : kprimaryDisabledTextColor, - ), + ) ], ), ), diff --git a/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart b/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart index 23c96171..03d82b26 100644 --- a/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart +++ b/lib/app/modules/alarmRing/controllers/alarm_ring_controller.dart @@ -266,8 +266,10 @@ class AlarmControlController extends GetxController { ); try { - await alarmChannel - .invokeMethod('scheduleAlarm', {'milliSeconds': intervaltoAlarm}); + await alarmChannel.invokeMethod('scheduleAlarm', { + 'milliSeconds': intervaltoAlarm, + 'activityMonitor': latestAlarm.activityMonitor + }); print("Scheduled..."); } on PlatformException catch (e) { print("Failed to schedule alarm: ${e.message}"); diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 27a27848..0ccd6848 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -25,7 +25,7 @@ class Pair<T, U> { Pair(this.first, this.second); } -class HomeController extends GetxController { +class HomeController extends GetxController { MethodChannel alarmChannel = const MethodChannel('ulticlock'); Stream<QuerySnapshot>? firestoreStreamAlarms; @@ -359,8 +359,10 @@ class HomeController extends GetxController { Utils.timeOfDayToDateTime(latestAlarmTimeOfDay), ); try { - await alarmChannel - .invokeMethod('scheduleAlarm', {'milliSeconds': intervaltoAlarm}); + await alarmChannel.invokeMethod('scheduleAlarm', { + 'milliSeconds': intervaltoAlarm, + 'activityMonitor': latestAlarm.activityMonitor, + }); print("Scheduled..."); } on PlatformException catch (e) { print("Failed to schedule alarm: ${e.message}"); diff --git a/lib/app/modules/splashScreen/controllers/splash_screen_controller.dart b/lib/app/modules/splashScreen/controllers/splash_screen_controller.dart index 2d0896fa..dc4db820 100644 --- a/lib/app/modules/splashScreen/controllers/splash_screen_controller.dart +++ b/lib/app/modules/splashScreen/controllers/splash_screen_controller.dart @@ -27,11 +27,11 @@ class SplashScreenController extends GetxController { UserModel? _userModel = await SecureStorageProvider().retrieveUserModel(); AlarmModel _alarmRecord = Utils.genFakeAlarmModel(); AlarmModel isarLatestAlarm = - await IsarDb.getLatestAlarm(_alarmRecord, false); + await IsarDb.getLatestAlarm(_alarmRecord, false); AlarmModel firestoreLatestAlarm = - await FirestoreDb.getLatestAlarm(_userModel, _alarmRecord, false); + await FirestoreDb.getLatestAlarm(_userModel, _alarmRecord, false); AlarmModel latestAlarm = - Utils.getFirstScheduledAlarm(isarLatestAlarm, firestoreLatestAlarm); + Utils.getFirstScheduledAlarm(isarLatestAlarm, firestoreLatestAlarm); debugPrint('CURRENT RINGING : ${latestAlarm.alarmTime}'); return latestAlarm; @@ -41,24 +41,24 @@ class SplashScreenController extends GetxController { UserModel? _userModel = await SecureStorageProvider().retrieveUserModel(); AlarmModel _alarmRecord = Utils.genFakeAlarmModel(); AlarmModel isarLatestAlarm = - await IsarDb.getLatestAlarm(_alarmRecord, true); + await IsarDb.getLatestAlarm(_alarmRecord, true); AlarmModel firestoreLatestAlarm = - await FirestoreDb.getLatestAlarm(_userModel, _alarmRecord, true); + await FirestoreDb.getLatestAlarm(_userModel, _alarmRecord, true); AlarmModel latestAlarm = - Utils.getFirstScheduledAlarm(isarLatestAlarm, firestoreLatestAlarm); + Utils.getFirstScheduledAlarm(isarLatestAlarm, firestoreLatestAlarm); debugPrint('LATEST : ${latestAlarm.alarmTime}'); return latestAlarm; } Future<bool> checkWeatherCondition( - LatLng location, - List<int> weatherTypeInt, - ) async { + LatLng location, + List<int> weatherTypeInt, + ) async { List<WeatherTypes> weatherTypes = - Utils.getWeatherTypesFromInt(weatherTypeInt); + Utils.getWeatherTypesFromInt(weatherTypeInt); String? apiKey = - await SecureStorageProvider().retrieveApiKey(ApiKeys.openWeatherMap); + await SecureStorageProvider().retrieveApiKey(ApiKeys.openWeatherMap); WeatherFactory weatherFactory = WeatherFactory(apiKey!); try { Weather weatherData = await weatherFactory.currentWeatherByLocation( @@ -140,9 +140,9 @@ class SplashScreenController extends GetxController { LatLng source = Utils.stringToLatLng(latestAlarm.location); destination = await FlLocation.getLocationStream().first.then( (value) => Utils.stringToLatLng( - '${value.latitude}, ${value.longitude}', - ), - ); + '${value.latitude}, ${value.longitude}', + ), + ); if (Utils.isWithinRadius(source, destination, 500)) { shouldAlarmRing = false; @@ -155,9 +155,9 @@ class SplashScreenController extends GetxController { currentLocation = await FlLocation.getLocationStream().first.then( (value) => Utils.stringToLatLng( - '${value.latitude}, ${value.longitude}', - ), - ); + '${value.latitude}, ${value.longitude}', + ), + ); bool isWeatherTypeMatching = await checkWeatherCondition( currentLocation, latestAlarm.weatherTypes, @@ -209,7 +209,7 @@ class SplashScreenController extends GetxController { AlarmModel latestAlarm = await getNextAlarm(); TimeOfDay latestAlarmTimeOfDay = - Utils.stringToTimeOfDay(latestAlarm.alarmTime); + Utils.stringToTimeOfDay(latestAlarm.alarmTime); // This condition will never satisfy because this will only occur if fake mode // is returned as latest alarm if (latestAlarm.isEnabled == false) { @@ -223,8 +223,10 @@ class SplashScreenController extends GetxController { ); try { - await alarmChannel.invokeMethod( - 'scheduleAlarm', {'milliSeconds': intervaltoAlarm}); + await alarmChannel.invokeMethod('scheduleAlarm', { + 'milliSeconds': intervaltoAlarm, + 'activityMonitor': latestAlarm.activityMonitor + }); print("Scheduled..."); } on PlatformException catch (e) { print("Failed to schedule alarm: ${e.message}"); @@ -246,4 +248,4 @@ class SplashScreenController extends GetxController { } }); } -} \ No newline at end of file +} diff --git a/lib/app/utils/utils.dart b/lib/app/utils/utils.dart index 58c4630f..00421119 100644 --- a/lib/app/utils/utils.dart +++ b/lib/app/utils/utils.dart @@ -427,6 +427,7 @@ class Utils { ringtoneName: 'Default', note: '', showMotivationalQuote: false, + activityMonitor: 0 ); }