Skip to content

Database cross comm #563

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 4, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ migrate_working_dir/
.pub-cache/
.pub/
/build/
pubspec.lock
/pubspec.lock
# Symbolication related
app.*.symbols

10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -154,6 +154,16 @@ The key reasons for utilizing IsarDb are as follows:

The schema for this data is already described above.

### SQFLITE

SQFLite is a Flutter plugin that allows you to use SQLite databases in your Flutter applications. Using SQLite database we can share alarm data between dart and kotlin or other native languages without the need for calling method channels.

- **Cross Communication Between Dart and Native**: SqLite database can be accessed by any native language with ease, allowing for seamless flow of data between the two.

- **Performance Optimization**: Performance and data retrieval times are improved as need for method channels for fetching data is eliminated.

The schema is same as described above.

### Flutter Secure Storage

The Flutter Secure Storage library is utilized in the "Ultimate Alarm Clock" project for securely storing various settings and preferences. This storage solution employs key-value pairs to manage and access data. Below are the keys and their associated purposes:
1 change: 1 addition & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -73,4 +73,5 @@ dependencies {

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation platform('com.google.firebase:firebase-bom:31.2.3')
implementation 'com.google.firebase:protolite-well-known-types:18.0.0'
}
20 changes: 12 additions & 8 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -16,6 +16,9 @@
<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" />



<application
tools:replace="android:label"
@@ -26,25 +29,26 @@
<service
android:name="com.pravera.flutter_foreground_task.service.ForegroundService" />


<receiver
android:name=".AlarmReceiver"
<receiver android:name=".BootReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<!-- Other necessary actions -->
</intent-filter>
</receiver>


<receiver
android:name=".AlarmReceiver"
android:enabled="true"
android:exported="false">
</receiver>

<receiver
android:name=".TimerReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<!-- Other necessary actions -->
</intent-filter>

</receiver>
<activity
android:name=".MainActivity"
Original file line number Diff line number Diff line change
@@ -18,9 +18,11 @@ class AlarmReceiver : BroadcastReceiver() {

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")
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.example.ultimate_alarm_clock

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.SystemClock
import java.time.LocalTime
import java.time.Duration
import org.json.JSONArray
import java.util.*



class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Open the database
val dbHelper = DatabaseHelper(context)
val db = dbHelper.readableDatabase

// Get the latest alarm
val ringTime = getLatestAlarm(db, true)

// Close the database
db.close()

// Schedule the alarm
if (ringTime != null) {

scheduleAlarm(ringTime, context)

}

}
fun scheduleAlarm(milliSeconds: Long, context: Context) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
context,
1,
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)
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.example.ultimate_alarm_clock
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {

companion object {
private const val DATABASE_VERSION = 1
private const val DATABASE_NAME = "alarms.db"
}

override fun onCreate(db: SQLiteDatabase) {}

override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package com.example.ultimate_alarm_clock

import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import java.text.SimpleDateFormat
import java.time.Duration
import java.time.LocalTime
import java.util.*


fun getLatestAlarm(db: SQLiteDatabase, wantNextAlarm: Boolean): Long? {
val now = Calendar.getInstance()
var nowInMinutes = now.get(Calendar.HOUR_OF_DAY) * 60 + now.get(Calendar.MINUTE)

if (wantNextAlarm) {
nowInMinutes++
}
val currentDay = Calendar.getInstance().get(Calendar.DAY_OF_WEEK)
val currentTime = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date())

val cursor = db.rawQuery(
"""
SELECT * FROM alarms
WHERE isEnabled = 1
AND alarmTime >= ?
AND ((isOneTime = 0 AND (days NOT LIKE '%1%' OR SUBSTR(days, ?, 1) = '1')) OR (isOneTime = 1 AND SUBSTR(days, ?, 4) = 'true'))
ORDER BY ABS(minutesSinceMidnight - ?) ASC
LIMIT 1
""", arrayOf(currentTime,currentDay.toString(),currentDay.toString(),nowInMinutes.toString())
)

return if (cursor.moveToFirst()) {
// Parse the cursor into an AlarmModel object
val alarm = AlarmModel.fromCursor(cursor)
cursor.close()
val latestAlarmTimeOftheDay = stringToTimeOfDay(alarm.alarmTime)
val intervaltoAlarm = getMillisecondsToAlarm(LocalTime.now(),latestAlarmTimeOftheDay)
intervaltoAlarm
} else {
cursor.close()
val selectAllQuery = """
SELECT * FROM alarms
WHERE isEnabled = 1
"""
val allAlarmsCursor = db.rawQuery(selectAllQuery, null)
if (allAlarmsCursor.moveToFirst()){
val alarms = ArrayList<Long>()

do {
var k = 0
for (i in 0..6) {
val dayIndex = ((currentDay - 1) + i) % 6
if (AlarmModel.fromCursor(allAlarmsCursor).days[dayIndex] == '1') {
k = i
break
}

}
val latestAlarmTimeOftheDay =
stringToTimeOfDay(AlarmModel.fromCursor(allAlarmsCursor).alarmTime)
val intervaltoAlarm = getMillisecondsToAlarm(LocalTime.now(), latestAlarmTimeOftheDay)
if(k!=0)
alarms.add(intervaltoAlarm+(86400000*(k)).toLong())
else
alarms.add(intervaltoAlarm+(86400000*(7)).toLong())

}while (allAlarmsCursor.moveToNext())
allAlarmsCursor.close()

alarms.sortWith(Comparator { a, b ->
a.compareTo(b)

})

alarms.first()


} else {
null
}
}
}

fun calculatePriority(days: String, currentDay: Int): Int {
if (days == "0000000") {
return 0
}
for (i in 1..7) {
val dayIndex = (currentDay + i) % 7
if (days[dayIndex] == '1') {
return i
}
}
return 7
}

fun stringToTimeOfDay(time: String): LocalTime {
val parts = time.split(":")
val hour = parts[0].toInt()
val minute = parts[1].toInt()
return LocalTime.of(hour, minute)
}
fun getMillisecondsToAlarm(now: LocalTime, alarmTime: LocalTime): Long {
var adjustedAlarmTime = alarmTime
val duration = Duration.between(now, adjustedAlarmTime)
return duration.toMillis()
}

data class AlarmModel(val id: Int, val minutesSinceMidnight: Int, val alarmTime: String, val days: String, val isOneTime : Int) {
companion object {
fun fromCursor(cursor: Cursor): AlarmModel {
val id = cursor.getInt(cursor.getColumnIndex("id"))
val minutesSinceMidnight = cursor.getInt(cursor.getColumnIndex("minutesSinceMidnight"))
val alarmTime = cursor.getString(cursor.getColumnIndex("alarmTime"))
val days = cursor.getString(cursor.getColumnIndex("days"))
val isOneTime = cursor.getInt(cursor.getColumnIndex("isOneTime"))
return AlarmModel(id, minutesSinceMidnight,alarmTime,days,isOneTime)
}
}
}
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ import android.view.WindowManager
import android.media.Ringtone
import android.media.RingtoneManager
import android.net.Uri
import java.time.LocalTime

class MainActivity : FlutterActivity() {

@@ -37,7 +38,6 @@ class MainActivity : FlutterActivity() {
}



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)
@@ -105,7 +105,7 @@ class MainActivity : FlutterActivity() {
result.success(null)
} else if (call.method == "minimizeApp" ) {
minimizeApp()
result.success(null)
result.success(null)
} else if (call.method == "playDefaultAlarm") {
playDefaultAlarm(this)
result.success(null)
@@ -136,6 +136,7 @@ class MainActivity : FlutterActivity() {


private fun scheduleAlarm(milliSeconds: Int) {

val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
@@ -163,6 +164,7 @@ class MainActivity : FlutterActivity() {

// Schedule the alarm
val triggerTime = SystemClock.elapsedRealtime() + milliSeconds
println(triggerTime)
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime, pendingIntent)
}

Original file line number Diff line number Diff line change
@@ -19,8 +19,8 @@ class TimerReceiver : BroadcastReceiver() {
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", "false")
putExtra("alarmRing", "false")
putExtra("isAlarm","true")
}

println("ANDROID STARTING APP")
102 changes: 101 additions & 1 deletion lib/app/data/models/alarm_model.dart
Original file line number Diff line number Diff line change
@@ -48,7 +48,6 @@ class AlarmModel {
late String note;
late bool deleteAfterGoesOff;
late bool showMotivationalQuote;

late double volMax;
late double volMin;

@@ -157,6 +156,94 @@ class AlarmModel {
volMax = documentSnapshot['volMax'];
volMin = documentSnapshot['volMin'];
}
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'],
);
}

Map<String, dynamic> toSQFliteMap() {
return {
'firestoreId': firestoreId,
'alarmTime': alarmTime,
'alarmID': alarmID,
'isEnabled': isEnabled ? 1 : 0,
'isLocationEnabled': isLocationEnabled ? 1 : 0,
'isSharedAlarmEnabled': isSharedAlarmEnabled ? 1 : 0,
'isWeatherEnabled': isWeatherEnabled ? 1 : 0,
'location': location,
'activityInterval': activityInterval,
'minutesSinceMidnight': minutesSinceMidnight,
'days': boolListToString(days),
'weatherTypes': jsonEncode(weatherTypes),
'isMathsEnabled': isMathsEnabled ? 1 : 0,
'mathsDifficulty': mathsDifficulty,
'numMathsQuestions': numMathsQuestions,
'isShakeEnabled': isShakeEnabled ? 1 : 0,
'shakeTimes': shakeTimes,
'isQrEnabled': isQrEnabled ? 1 : 0,
'qrValue': qrValue,
'isPedometerEnabled': isPedometerEnabled ? 1 : 0,
'numberOfSteps': numberOfSteps,
'intervalToAlarm': intervalToAlarm,
'isActivityEnabled': isActivityEnabled ? 1 : 0,
'sharedUserIds': sharedUserIds != null ? jsonEncode(sharedUserIds) : null,
'ownerId': ownerId,
'ownerName': ownerName,
'lastEditedUserId': lastEditedUserId,
'mutexLock': mutexLock ? 1 : 0,
'mainAlarmTime': mainAlarmTime,
'label': label,
'isOneTime': isOneTime ? 1 : 0,
'snoozeDuration': snoozeDuration,
'gradient': gradient,
'ringtoneName': ringtoneName,
'note': note,
'deleteAfterGoesOff': deleteAfterGoesOff ? 1 : 0,
'showMotivationalQuote': showMotivationalQuote ? 1 : 0,
'volMin': volMin,
'volMax': volMax,
};
}

AlarmModel.fromMap(Map<String, dynamic> alarmData) {
// Making sure the alarms work with the offsets
@@ -260,4 +347,17 @@ 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);
// 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();
}

}
87 changes: 86 additions & 1 deletion lib/app/data/providers/firestore_provider.dart
Original file line number Diff line number Diff line change
@@ -3,13 +3,79 @@ import 'package:flutter/material.dart';
import 'package:ultimate_alarm_clock/app/data/models/alarm_model.dart';
import 'package:ultimate_alarm_clock/app/data/models/user_model.dart';
import 'package:ultimate_alarm_clock/app/utils/utils.dart';
import 'package:sqflite/sqflite.dart';

class FirestoreDb {
static final FirebaseFirestore _firebaseFirestore =
FirebaseFirestore.instance;

static final CollectionReference _usersCollection =
FirebaseFirestore.instance.collection('users');
Future<Database?> getSQLiteDatabase() async {
Database? db;

final dir = await getDatabasesPath();
final dbPath = '${dir}/alarms.db';
print(dir);
db = await openDatabase(dbPath, version: 1, onCreate: _onCreate);
return db;
}

void _onCreate(Database db, int version) async {
// Create tables for alarms and ringtones (modify column types as needed)
await db.execute('''
CREATE TABLE alarms (
id INTEGER PRIMARY KEY AUTOINCREMENT,
firestoreId TEXT,
alarmTime TEXT NOT NULL,
alarmID TEXT NOT NULL UNIQUE,
isEnabled INTEGER NOT NULL DEFAULT 1,
isLocationEnabled INTEGER NOT NULL DEFAULT 0,
isSharedAlarmEnabled INTEGER NOT NULL DEFAULT 0,
isWeatherEnabled INTEGER NOT NULL DEFAULT 0,
location TEXT,
activityInterval INTEGER,
minutesSinceMidnight INTEGER NOT NULL,
days TEXT NOT NULL,
weatherTypes TEXT NOT NULL,
isMathsEnabled INTEGER NOT NULL DEFAULT 0,
mathsDifficulty INTEGER,
numMathsQuestions INTEGER,
isShakeEnabled INTEGER NOT NULL DEFAULT 0,
shakeTimes INTEGER,
isQrEnabled INTEGER NOT NULL DEFAULT 0,
qrValue TEXT,
isPedometerEnabled INTEGER NOT NULL DEFAULT 0,
numberOfSteps INTEGER,
intervalToAlarm INTEGER,
isActivityEnabled INTEGER NOT NULL DEFAULT 0,
sharedUserIds TEXT,
ownerId TEXT NOT NULL,
ownerName TEXT NOT NULL,
lastEditedUserId TEXT,
mutexLock INTEGER NOT NULL DEFAULT 0,
mainAlarmTime TEXT,
label TEXT,
isOneTime INTEGER NOT NULL DEFAULT 0,
snoozeDuration INTEGER,
gradient INTEGER,
ringtoneName TEXT,
note TEXT,
deleteAfterGoesOff INTEGER NOT NULL DEFAULT 0,
showMotivationalQuote INTEGER NOT NULL DEFAULT 0,
volMin REAL,
volMax REAL
)
''');
await db.execute('''
CREATE TABLE ringtones (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ringtoneName TEXT NOT NULL,
ringtonePath TEXT NOT NULL,
currentCounterOfUsage INTEGER NOT NULL DEFAULT 0
)
''');
}

static CollectionReference _alarmsCollection(UserModel? user) {
if (user == null) {
@@ -29,7 +95,14 @@ class FirestoreDb {
}

static addAlarm(UserModel? user, AlarmModel alarmRecord) async {
if (user == null) return alarmRecord;
final sql = await FirestoreDb().getSQLiteDatabase();

if (user == null) {
return alarmRecord;
}
await sql!
.insert('alarms', alarmRecord.toSQFliteMap())
.then((value) => print("insert success"));
await _alarmsCollection(user)
.add(AlarmModel.toMap(alarmRecord))
.then((value) => alarmRecord.firestoreId = value.id);
@@ -189,6 +262,13 @@ class FirestoreDb {
}

static updateAlarm(String? userId, AlarmModel alarmRecord) async {
final sql = await FirestoreDb().getSQLiteDatabase();
await sql!.update(
'alarms',
alarmRecord.toSQFliteMap(),
where: 'alarmID = ?',
whereArgs: [alarmRecord.alarmID],
);
await _firebaseFirestore
.collection('users')
.doc(userId)
@@ -201,6 +281,8 @@ class FirestoreDb {
String? ownerId,
String? firestoreId,
) async {
final sql = await FirestoreDb().getSQLiteDatabase();

try {
// Delete alarm remotely (from Firestore)
await FirebaseFirestore.instance
@@ -209,6 +291,7 @@ class FirestoreDb {
.collection('alarms')
.doc(firestoreId)
.delete();
sql!.delete('alarms', where: 'firestoreId = ?', whereArgs: [firestoreId]);

debugPrint('Alarm deleted successfully from Firestore.');
} catch (e) {
@@ -256,6 +339,8 @@ class FirestoreDb {
}

static deleteAlarm(UserModel? user, String id) async {
final sql = await FirestoreDb().getSQLiteDatabase();
sql!.delete('alarms', where: 'firestoreId = ?', whereArgs: [id]);
await _alarmsCollection(user).doc(id).delete();
}

83 changes: 82 additions & 1 deletion lib/app/data/providers/isar_provider.dart
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import 'package:ultimate_alarm_clock/app/data/models/alarm_model.dart';
import 'package:ultimate_alarm_clock/app/data/models/ringtone_model.dart';
import 'package:ultimate_alarm_clock/app/data/models/timer_model.dart';
import 'package:ultimate_alarm_clock/app/utils/utils.dart';
import 'package:sqflite/sqflite.dart';

class IsarDb {
static final IsarDb _instance = IsarDb._internal();
@@ -18,6 +19,72 @@ class IsarDb {
db = openDB();
}

Future<Database?> getSQLiteDatabase() async {
Database? db;

final dir = await getDatabasesPath();
final dbPath = '${dir}/alarms.db';
print(dir);
db = await openDatabase(dbPath, version: 1, onCreate: _onCreate);
return db;
}

void _onCreate(Database db, int version) async {
// Create tables for alarms and ringtones (modify column types as needed)
await db.execute('''
CREATE TABLE alarms (
id INTEGER PRIMARY KEY AUTOINCREMENT,
firestoreId TEXT,
alarmTime TEXT NOT NULL,
alarmID TEXT NOT NULL UNIQUE,
isEnabled INTEGER NOT NULL DEFAULT 1,
isLocationEnabled INTEGER NOT NULL DEFAULT 0,
isSharedAlarmEnabled INTEGER NOT NULL DEFAULT 0,
isWeatherEnabled INTEGER NOT NULL DEFAULT 0,
location TEXT,
activityInterval INTEGER,
minutesSinceMidnight INTEGER NOT NULL,
days TEXT NOT NULL,
weatherTypes TEXT NOT NULL,
isMathsEnabled INTEGER NOT NULL DEFAULT 0,
mathsDifficulty INTEGER,
numMathsQuestions INTEGER,
isShakeEnabled INTEGER NOT NULL DEFAULT 0,
shakeTimes INTEGER,
isQrEnabled INTEGER NOT NULL DEFAULT 0,
qrValue TEXT,
isPedometerEnabled INTEGER NOT NULL DEFAULT 0,
numberOfSteps INTEGER,
intervalToAlarm INTEGER,
isActivityEnabled INTEGER NOT NULL DEFAULT 0,
sharedUserIds TEXT,
ownerId TEXT NOT NULL,
ownerName TEXT NOT NULL,
lastEditedUserId TEXT,
mutexLock INTEGER NOT NULL DEFAULT 0,
mainAlarmTime TEXT,
label TEXT,
isOneTime INTEGER NOT NULL DEFAULT 0,
snoozeDuration INTEGER,
gradient INTEGER,
ringtoneName TEXT,
note TEXT,
deleteAfterGoesOff INTEGER NOT NULL DEFAULT 0,
showMotivationalQuote INTEGER NOT NULL DEFAULT 0,
volMin REAL,
volMax REAL
)
''');
await db.execute('''
CREATE TABLE ringtones (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ringtoneName TEXT NOT NULL,
ringtonePath TEXT NOT NULL,
currentCounterOfUsage INTEGER NOT NULL DEFAULT 0
)
''');
}

Future<Isar> openDB() async {
final dir = await getApplicationDocumentsDirectory();
if (Isar.instanceNames.isEmpty) {
@@ -32,10 +99,15 @@ class IsarDb {

static Future<AlarmModel> addAlarm(AlarmModel alarmRecord) async {
final isarProvider = IsarDb();
final sql = await IsarDb().getSQLiteDatabase();
final db = await isarProvider.db;
await db.writeTxn(() async {
await db.alarmModels.put(alarmRecord);
});
final sqlmap = alarmRecord.toSQFliteMap();
await sql!
.insert('alarms', sqlmap)
.then((value) => print("insert success"));
return alarmRecord;
}

@@ -145,10 +217,17 @@ class IsarDb {

static Future<void> updateAlarm(AlarmModel alarmRecord) async {
final isarProvider = IsarDb();
final sql = await IsarDb().getSQLiteDatabase();
final db = await isarProvider.db;
await db.writeTxn(() async {
await db.alarmModels.put(alarmRecord);
});
await sql!.update(
'alarms',
alarmRecord.toSQFliteMap(),
where: 'alarmID = ?',
whereArgs: [alarmRecord.alarmID],
);
}

static Future<AlarmModel?> getAlarm(int id) async {
@@ -171,10 +250,12 @@ class IsarDb {
static Future<void> deleteAlarm(int id) async {
final isarProvider = IsarDb();
final db = await isarProvider.db;

final sql = await IsarDb().getSQLiteDatabase();
final tobedeleted = await db.alarmModels.get(id);
await db.writeTxn(() async {
await db.alarmModels.delete(id);
});
sql!.delete('alarms', where: 'alarmID = ?', whereArgs: [tobedeleted!.alarmID]);
}

static Future<void> addCustomRingtone(
Original file line number Diff line number Diff line change
@@ -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) {
@@ -230,7 +230,7 @@ class SplashScreenController extends GetxController {
print("Failed to schedule alarm: ${e.message}");
}
}

SystemNavigator.pop();
Get.offNamed('/bottom-navigation-bar');

alarmChannel.invokeMethod('minimizeApp');
@@ -246,4 +246,4 @@ class SplashScreenController extends GetxController {
}
});
}
}
}
3 changes: 1 addition & 2 deletions pubspec.lock
Original file line number Diff line number Diff line change
@@ -1462,5 +1462,4 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.2.0 <4.0.0"
flutter: ">=3.16.0"
dart: ">=3.2.0 <4.0.0"
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@ dependencies:
uuid: ^4.3.3
pedometer: ^4.0.1
flutter_volume_controller: ^1.3.1
sqflite: ^2.3.2

dev_dependencies:
flutter_lints: ^2.0.3