import 'dart:async'; import 'dart:io'; import 'package:app_usage/app_usage.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart' as K; import 'package:intl/intl.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tasktracker/NewProject.dart'; import 'package:tasktracker/NotificationsManager.dart'; import 'DebugHelper.dart'; import 'main.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'Data.dart'; import 'package:sqflite/sqflite.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart' as SqlFF; import 'package:path_provider/path_provider.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:sqflite_common/sqlite_api.dart'; import 'Tasks.dart'; import 'Dialogs.dart'; bool cacheEnabled = !K.kIsWeb; late http.Response loginResponse; late var cacheDb; late String username; List categories = []; List taskTypes = []; List activities = []; List projects = []; List journal = []; List todos = []; const API_ENDPOINT = 'http://vps.playpoolstudios.com'; bool offline = true; bool registered = false; StreamController refreshStream = StreamController.broadcast(); Future login(String _username, String password) async { final prefs = await SharedPreferences.getInstance(); username = _username; var device_id = await Settings.UUID(); try { loginResponse = (await http.post( Uri.parse('http://vps.playpoolstudios.com/task_tracker/login.php'), body: { "username": _username, "password": password, "device_id": device_id })); if (loginResponse.body.toLowerCase().contains("success")) { offline = false; username = _username; registered = loginResponse.body.toLowerCase().contains("register"); Debug.Log("registered : $registered"); if (registered) { prefs.setBool("registered", true); } } } catch (e) { Debug.LogError("Error while login $e"); } return loginResponse; } Future initUserData() async { if (cacheEnabled) { await initCacheDatabase(); int catCount = Sqflite.firstIntValue( await cacheDb.rawQuery('SELECT COUNT(*) FROM Categories')) ?? 0; int taskCount = Sqflite.firstIntValue( await cacheDb.rawQuery('SELECT COUNT(*) FROM TaskTypes')) ?? 0; if (catCount > 0 && taskCount > 0) { await refreshUserData(forceOffline: true); refreshUserData(); } else { await refreshUserData(); } } BuildBridgeToServer(); InitUsageListener(); Debug.Log('Initializing UserData...'); if (cacheEnabled) { // if (Platform.isAndroid || Platform.isIOS) { // Connectivity().onConnectivityChanged.listen((result) { // offline = (result == ConnectivityResult.none); // if (!offline) { // UserOperations.executeQueries(); // refreshUserData(); // } // }); // } } } Future BuildBridgeToServer() async { final prefs = await SharedPreferences.getInstance(); while (true) { await UserOperations.executeQueries(); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/bridge.php'), body: {"username": username})); Debug.LogResponse("${response.body}", src: 'bridge'); List data = response.body.split(","); Debug.LogResponse( 'Update :\nactivities_rev=${data[0]} tasks_rev=${data[1]} cats_rev=${data[2]} projects_rev=${data[3]}'); bool changedOffline = offline == true; offline = false; if (changedOffline) { refreshStream.add(false); } if (data[4].contains('')) { List ongoingData = data[4].split(""); if (!prefs.containsKey('current_activity')) { StartActivityTimer( ongoingData[0], ongoingData[1], DateTime.parse(ongoingData[2])); } } else { if (prefs.containsKey('current_activity')) CancelOngoingActivity(); } if (prefs.containsKey('rev')) { if (prefs.getString('rev') == response.body) { Debug.Log('We are on the same page'); } else { Debug.Log('Gotta update'); await refreshUserData(); prefs.setString('rev', response.body); } } else { prefs.setString('rev', response.body); await refreshUserData(); } } catch (e) { Debug.LogError("Error with bridge : $e"); bool changedOffline = offline == false; offline = true; if (changedOffline) { refreshStream.add(false); } } await Future.delayed(Duration(seconds: 5)); } } const APP_USAGE_KEY_NAME = "app_usage_data"; Future InitUsageListener() async { final prefs = await SharedPreferences.getInstance(); var delay = Duration(seconds: 10); if(!prefs.containsKey(APP_USAGE_KEY_NAME)){ prefs.setString(APP_USAGE_KEY_NAME, ""); } List app_usage = []; while (true) { List appUsage = await AppUsage().getAppUsage(DateTime.now().subtract(delay), DateTime.now()); List prev_appUsage = jsonDecode(prefs.getString(APP_USAGE_KEY_NAME)!); Debug.Log("Listening to usage"); await Future.delayed(delay); } } bool m_refreshing = false; Future refreshUserData({bool forceOffline = false}) async { Debug.Log('refreshing user data'); if (m_refreshing) { Debug.LogError('Called while refreshing. Return'); return; } m_refreshing = true; if (forceOffline) { refreshStream.add(true); categories = await GetCategories(true); projects = await GetProjects(true); taskTypes = await GetTaskTypes(true); activities = await GetActivities(true); journal = await GetJournals(true); todos = await GetTodos(true); refreshStream.add(false); } else { if (K.kIsWeb) { Debug.LogTest('updating cats ${DateTime.now()}'); categories = await GetCategories(false); Debug.LogTest('updating projs ${DateTime.now()}'); projects = await GetProjects(false); Debug.LogTest('updating tasks ${DateTime.now()}'); taskTypes = await GetTaskTypes(false); Debug.LogTest('updating acts ${DateTime.now()}'); activities = await GetActivities(false); Debug.LogTest('updating journals ${DateTime.now()}'); journal = await GetJournals(false); Debug.LogTest('updating todos ${DateTime.now()}'); todos = await GetTodos(false); Debug.LogTest('done refreshing ${DateTime.now()}'); } else { Debug.LogTest('Doing super update ${DateTime.now()}'); refreshStream.add(true); try { Debug.LogTest('Requesting all data @ ${DateTime.now()}'); http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/grab_all_data.php'), body: { "username": username, "device_id": await Settings.UUID() })); List data = response.body.split(''); Debug.LogTest( 'Got response for all data [${response.contentLength}bytes] @ ${DateTime.now()}'); Debug.LogTest( 'super update items : ${data.length}\nfilling tables\nActivities : ${data[0].length}\nProjects: ${data[1].length}'); Debug.LogResponse(response.body); Debug.LogResponse(data[0], src: 'Activity'); Debug.LogResponse(data[1], src: 'Categories'); Debug.LogResponse(data[2], src: 'Projects'); Debug.LogResponse(data[3], src: 'Journals'); Debug.LogResponse(data[4], src: 'TaskTypes'); Debug.LogResponse(data[5], src: 'Todo'); await fillActivityTable(data[0]); await fillCatsTable(data[1]); await fillJournalsTable(data[2]); await fillProjectsTable(data[3]); await fillTaskTypes(data[4]); await fillTodosTable(data[5]); Debug.LogTest('Done filling @ ${DateTime.now()}'); categories = await GetCategories(true); projects = await GetProjects(true); taskTypes = await GetTaskTypes(true); activities = await GetActivities(true); journal = await GetJournals(true); todos = await GetTodos(true); } catch (e) { Debug.LogError("Error while Super Update $e"); } refreshStream.add(false); Debug.LogTest('Done super update ${DateTime.now()}'); } DateTime now = DateTime.now(); List appUsage = await AppUsage().getAppUsage(now.subtract(Duration(days: 2)), now); Debug.Log("Adding auto logs"); appUsage.forEach((task) { bool foundConflict = false; for (int i = 1; i < activities.length; i++) { Activity act = activities[activities.length - i]; if (isConflicting( act.startTime, act.endTime, task.startDate, task.endDate)) { //Got something here continue; } // UserOperations.addActivity("At work", task.startDate, task.endDate); Debug.LogTest(task); if (act.startTime.isBefore(now.subtract(Duration(days: 2)))) { break; } } }); } m_refreshing = false; if (cacheEnabled) { NotificationManager.RescheduleNotifications(); } } bool isConflicting( DateTime start1, DateTime end1, DateTime start2, DateTime end2) { if (start1.isBefore(end2) && end1.isAfter(end2)) { // 1 starts before 2 and continues after 2 is done return true; } if (end1.isBefore(end2) && end1.isAfter(start2)) { // 1 ends within 2 return true; } if (start1.isAfter(start2) && start1.isBefore(end2)) { //1 starts within 2 return true; } if (start1 == start2 || end1 == end2) { return true; } return false; } Future cacheDbExist() async { if (!K.kIsWeb && Platform.isAndroid || Platform.isIOS) { Directory directory = await getApplicationDocumentsDirectory(); return databaseFactory.databaseExists(directory.path + 'cache.db'); } else { Directory directory = await getApplicationDocumentsDirectory(); return SqlFF.databaseFactoryFfi.databaseExists(directory.path + 'cache.db'); } } Future updateCatsList() async { categories = await GetCategories(false); } Future updateTasksList() async { taskTypes = await GetTaskTypes(false); } Future updateActList() async { activities = await GetActivities(false); } Future updateProjectsList() async { projects = await GetProjects(false); } Future initCacheDatabase() async { Directory directory = await getApplicationDocumentsDirectory(); Debug.LogResponse('database at ' + directory.path + '/cache.db'); if (!K.kIsWeb && Platform.isAndroid || Platform.isIOS) { cacheDb = await openDatabase(directory.path + 'cache.db', version: 1, onCreate: onCacheDatabaseCreate, onUpgrade: onCacheDatabaseUpgrade); } else { cacheDb = await SqlFF.databaseFactoryFfi.openDatabase( directory.path + 'cache.db', options: OpenDatabaseOptions(version: 1, onCreate: onCacheDatabaseCreate)); } await UserOperations.executeQueries(); } void onCacheDatabaseCreate(Database db, int newVersion) async { String CategoriesTableSQL = 'CREATE TABLE Categories(${Category.colCatId} VARCHAR(255) PRIMARY KEY,${Category.colName} TEXT, ${Category.colColor} TEXT, ${Category.colProductive} INTEGER)'; // Debug.Log(CategoriesTableSQL); await db.execute(CategoriesTableSQL); Debug.Log("Initiated Categories Table"); String TaskTableSQL = 'CREATE TABLE TaskTypes(id TEXT PRIMARY KEY, ${TaskType.colName} TEXT, ${TaskType.colCategory} TEXT, ${TaskType.colRelatedProject} TEXT, ' 'FOREIGN KEY (${TaskType.colCategory}) REFERENCES Categories(${Category.colCatId}))'; // Debug.Log(TaskTableSQL); await db.execute(TaskTableSQL); String ActivityTableSQL = 'CREATE TABLE Activities(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Activity.colType} INT, ${Activity.colStartTime} DATETIME, ${Activity.colEndTime} DATETIME, ${Activity.colMetadata} TEXT, ' 'FOREIGN KEY (${Activity.colType}) REFERENCES TaskTypes(id))'; // Debug.Log(ActivityTableSQL); await db.execute(ActivityTableSQL); String ProjectsTableSQL = 'CREATE TABLE Projects(id TEXT PRIMARY KEY, ${Project.colName} TEXT, ${Project.colCat} TEXT, ${Project.colSteps} TEXT, ${Project.colEta} INT, ${Project.colDeadline} DATETIME)'; await db.execute(ProjectsTableSQL); String JournalTableSQL = 'CREATE TABLE Journal(id TEXT PRIMARY KEY, ${Journal.colTitle} TEXT, ${Journal.colDescription})'; await db.execute(JournalTableSQL); String TodoTableSQL = 'CREATE TABLE Todos(id TEXT PRIMARY KEY, ${Todo.colCat} TEXT, ${Todo.colMetadata} TEXT, ${Todo.colDueDate} DATE, ${Todo.colNotificationTime} DATETIME)'; await db.execute(TodoTableSQL); String QueriesTableSQL = 'CREATE TABLE Queries(id INTEGER PRIMARY KEY AUTOINCREMENT, ${Queries.colLink} TEXT,${Queries.colData} TEXT)'; await db.execute(QueriesTableSQL); final prefs = await SharedPreferences.getInstance(); if (prefs.getBool("registered") ?? false) { addInitialDataToCache(); prefs.setBool("registered", false); } // GetCategories(); } Future addInitialDataToCache() async { Dialogs.syncingMessage = "Adding initial data"; Debug.Log("adding init data"); await Future.delayed(const Duration(seconds: 1)); //Insert Initial Entries for (Category element in InitialData.getCategories(username)) { await UserOperations.addCategory( element.name, element.color, element.productive, bulk: true); } Dialogs.syncingMessage = "Just a minute"; for (TaskType element in InitialData.getTaskTypes(username)) { await UserOperations.addTaskType(element.name, element.category, bulk: true); // Map data = { // TaskType.colName: element.name, // TaskType.colCategory: element.category // }; // await cacheDb.insert('TaskTypes', data); } Dialogs.syncingMessage = "Syncing"; await UserOperations.executeQueries(); // await refreshUserData(); } void onCacheDatabaseUpgrade(Database db, int oldVersion, int newVersion) async { //ValidateCacheDB(); Debug.LogResponse( 'Upgrading CacheDB from ver.$oldVersion to ver.$newVersion'); } Future> GetCategories(bool forceOffline) async { if (cacheEnabled) { List _categories = []; if (offline || forceOffline) { //Retreive from cacheDB } else { //Check if server got updated, If not go for cache var android_id = await Settings.UUID(); //Validate device_id to check updates bool catsUpdated = false; // try { // http.Response update_response = (await http.post(Uri.parse(API_ENDPOINT+'/task_tracker/check_update.php'), body: {"username": username, "device_id": android_id})); // final data = update_response.body.split(','); // catsUpdated = data[0] == '1'; // } catch (e) { // Debug.Log(e); // } Debug.Log("Need to update : ${!catsUpdated}"); //Update CacheDB if (!catsUpdated) { await UpdateCategoriesFromServer(); } } List cats = await cacheDb.query('Categories'); Debug.Log('categories :${cats.length}'); for (Map element in cats) { String? catName = element[Category.colName].toString(); String? catColor = element[Category.colColor].toString(); String? catProductive = element[Category.colProductive].toString(); if (catName == null || catColor == null || catProductive == null) { Debug.LogError("Something is null!"); Debug.LogError( "name:{$catName}, color:{$catColor}, prod:{$Category.colProductive}"); continue; } // Debug.Log("name:{$catName}, color:{$catColor}, prod:{$catProductive}"); _categories.add(Category( username + catName, catName, catColor, ParseBool(catProductive))); } categories = _categories; } else { Debug.Log("NC: Updating Categories as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_categories.php'), body: { "username": username, "device_id": await Settings.UUID() })); Debug.LogResponse(response.body, src: 'get_categories'); List data = response.body.split(""); List _categories = []; for (var value in data) { Map cat = jsonDecode(value); _categories.add(Category(cat['category_id'], cat['name'], cat['color'], ParseBool(cat['productive']))); } categories = _categories; } catch (e) { Debug.LogError("Error while cats NC: $e"); } } return categories; } Future UpdateCategoriesFromServer() async { Debug.Log("Updating Categories as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_categories.php'), body: { "username": username, "device_id": await Settings.UUID() })); Debug.LogResponse(response.body); await fillCatsTable(response.body); } catch (e) { Debug.LogError("Error while cats $e"); } } Future fillCatsTable(String response) async { List data = response.split(""); await cacheDb.delete("Categories"); for (var value in data) { Map cat = jsonDecode(value); //Debug.Log(catData); await cacheDb.rawInsert( "INSERT OR REPLACE INTO Categories (${Category.colCatId},${Category.colName},${Category.colProductive},${Category.colColor}) " "VALUES ('${cat['category_id']}','${cat['name']}',${cat['productive']},'${cat['color']}') "); } } Future> GetTaskTypes(bool forceOffline) async { if (cacheEnabled) { List _taskTypes = []; if (offline || forceOffline) { //Retreive from cacheDB } else { //Check if server got updated, If not go for cache var android_id = await Settings.UUID(); bool updated = false; // try { // //Validate device_id to check updates // http.Response update_response = (await http.post(Uri.parse(API_ENDPOINT+'/task_tracker/check_update.php'), body: {"username": username, "device_id": android_id})); // final data = update_response.body.split(','); // updated = data[1] == '1'; // } catch (e) { // Debug.Log(e); // } Debug.Log("Need to update : ${!updated}"); //Update CacheDB if (!updated) { await UpdateTaskTypesFromServer(); } } await Future.delayed(Duration(seconds: 1)); List cats = await cacheDb.query('TaskTypes'); Debug.Log(cats.length); for (Map element in cats) { String? id = element[TaskType.colId].toString(); String? name = element[TaskType.colName].toString(); String? category = element[TaskType.colCategory].toString(); String? related_project = element[TaskType.colRelatedProject].toString(); Category? cat = await getCatFromId(category); if (id == null || name == null || category == null) { Debug.LogError("Something is null!"); Debug.LogError("name:{$name}, cat:{$category}, prod:{$id}"); continue; } Project? relatedProject; if (related_project.isNotEmpty) { relatedProject = await getProjectFromId(related_project); Debug.Log('got a tasktype with project'); } // Debug.Log("name:{$name}, cat:{$category}, prod:{$id}"); _taskTypes.add(TaskType(id, name, category, cat: cat, relatedProject: relatedProject)); } taskTypes = _taskTypes; } else { List _taskTypes = []; Debug.Log("NC: Updating TaskTypes as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_taskTypes.php'), body: { "username": username, "device_id": await Settings.UUID() })); Debug.LogResponse("taskType retreive (try): ${response.body}"); List data = response.body.split(""); for (var value in data) { Map data = jsonDecode(value); Category? cat = await getCatFromId(data['category_id']); _taskTypes.add(TaskType( data['task_id'], data['name'], data['category_id'], cat: cat, relatedProject: data['related_project'])); //Debug.Log(cat); } } catch (e) { Debug.LogError("Error while tasks NC $e"); } taskTypes = _taskTypes; } return taskTypes; } Future UpdateTaskTypesFromServer() async { // await GetCategories(true); Debug.Log("Updating TaskTypes as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_taskTypes.php'), body: { "username": username, "device_id": await Settings.UUID() })); Debug.LogResponse(response.body); await fillTaskTypes(response.body); } catch (e) { Debug.LogError("Error while tasks $e"); } } Future fillTaskTypes(String response) async { List data = response.split(""); await cacheDb.delete("TaskTypes"); for (var value in data) { Map cat = jsonDecode(value); //Debug.Log(cat); await cacheDb.rawInsert( "INSERT OR REPLACE INTO TaskTypes (${TaskType.colId},${TaskType.colName},${TaskType.colCategory},${TaskType.colRelatedProject}) " "VALUES ('${cat['task_id']}','${cat['name']}','${cat['category_id']}', '${cat['related_project']}') "); Debug.LogResponse(await cacheDb.query("TaskTypes")); } } void StartActivityTimer( String taskType, String metadata, DateTime startTime) async { final prefs = await SharedPreferences.getInstance(); prefs.setString('current_activity', "$taskType$metadata${UserOperations.dFormat.format(startTime)}"); NotificationManager.RescheduleNotifications(); UserOperations.startOngoing(prefs.getString('current_activity')!); } Future?> getOngoingData() async { final prefs = await SharedPreferences.getInstance(); if (prefs.containsKey('current_activity')) { List data = []; try { data = prefs.getString('current_activity')!.split(''); return data; } catch (e) {} } else {} } void StopActivityTimer() async { final prefs = await SharedPreferences.getInstance(); try { List data = prefs.getString('current_activity')!.split(""); UserOperations.addActivity(data[0], DateTime.parse(data[2]), DateTime.now(), metadata: data[1]); } catch (e) {} prefs.remove('current_activity'); UserOperations.stopOngoing(); } void CancelOngoingActivity() async { final prefs = await SharedPreferences.getInstance(); prefs.remove('current_activity'); UserOperations.stopOngoing(); } Future> GetActivities(bool forceOffline) async { if (cacheEnabled) { List _activities = []; if (offline || forceOffline) { //Retreive from cacheDB Debug.Log('offline, refreshing activities'); } else { //Check if server got updated, If not go for cache var android_id = await Settings.UUID(); bool updated = false; // try { // //Validate device_id to check updates // http.Response update_response = (await http.post(Uri.parse(API_ENDPOINT+'/task_tracker/check_update.php'), body: {"username": username, "device_id": android_id})); // final data = update_response.body.split(','); // updated = data[2] == '1'; // } catch (e) { // Debug.Log(e); // } Debug.Log("Need to update activities : ${!updated}"); //Update CacheDB if (!updated) { await UpdateActivitiesFromServer(); } } List cats = await cacheDb.rawQuery( 'SELECT * FROM Activities ORDER BY ${Activity.colStartTime} DESC'); Debug.Log(cats.length); for (Map element in cats) { int? id = element['id']; String? type = element[Activity.colType].toString(); String? startTime = element[Activity.colStartTime].toString(); String? endTime = element[Activity.colEndTime].toString(); String? metadata = element[Activity.colMetadata].toString(); TaskType? taskType = await getTaskFromId(type); if (type == null || startTime == null || endTime == null || taskType == null) { Debug.LogError( "Something is null!\ntype:${type == null}, startTime:${startTime == null}, eTime:${endTime == null}, taskType${taskType == null}"); Debug.LogError( "TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}"); continue; } //Debug.Log("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}"); DateTime sTime = DateTime.parse(startTime); DateTime eTime = DateTime.parse(endTime); if (eTime.day != sTime.day) { DateTime midnight = DateTime(eTime.year, eTime.month, eTime.day, 0, 0, 0); int firstHalf = eTime.difference(midnight).inMinutes; int secondHalf = midnight.difference(sTime).inMinutes; // Debug.Log("${taskType.name} first half : $firstHalf -> second half: $secondHalf"); if (firstHalf > 1) { _activities.add(Activity(taskType, midnight, eTime, metadata: metadata, tStartTime: sTime)); } if (secondHalf > 1) { _activities.add(Activity(taskType, sTime, midnight, metadata: metadata, tEndTime: eTime)); } } else { _activities.add(Activity( taskType, DateTime.parse(startTime), DateTime.parse(endTime), metadata: metadata)); } } activities = _activities; } else { Debug.Log("NC :Updating Activities as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_activities.php'), body: { "username": username, "device_id": await Settings.UUID() })); Debug.LogResponse("Activity response: ${response.body}"); List _activities = []; if (response.body.contains("{")) { List data = response.body.split(""); for (var value in data) { Map cat = jsonDecode(value); int? id = cat['id']; String? type = cat['task_id'].toString(); String? startTime = cat['sTime'].toString(); String? endTime = cat['eTime'].toString(); String? metadata = cat['metadata']; TaskType? taskType = await getTaskFromId(type); if (taskType == null) { Debug.LogError('null found'); continue; } //Debug.Log("TaskType:{$type}, Start Time:{$startTime}, endTime:{$endTime}, metadata:${metadata}"); DateTime sTime = DateTime.parse(startTime); DateTime eTime = DateTime.parse(endTime); if (eTime.day != sTime.day) { DateTime midnight = DateTime(eTime.year, eTime.month, eTime.day, 0, 0, 0); int firstHalf = eTime.difference(midnight).inMinutes; int secondHalf = midnight.difference(sTime).inMinutes; // Debug.Log("${taskType.name} first half : $firstHalf -> second half: $secondHalf"); if (firstHalf > 1) { _activities.add(Activity(taskType, midnight, eTime, metadata: metadata, tStartTime: sTime)); } if (secondHalf > 1) { _activities.add(Activity(taskType, sTime, midnight, metadata: metadata, tEndTime: eTime)); } } else { _activities.add(Activity( taskType, DateTime.parse(startTime), DateTime.parse(endTime), metadata: metadata)); } } activities = _activities.reversed.toList(); } else { Debug.LogError("No activities for now"); } } catch (e) { Debug.LogError("Error while acts $e"); } } return activities; } Future UpdateActivitiesFromServer() async { Debug.Log("Updating Activities as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_activities.php'), body: { "username": username, "device_id": await Settings.UUID() })); await fillActivityTable(response.body); // Debug.Log("Activity response: ${response.body}"); } catch (e) { Debug.Log("Error while acts $e"); } } Future fillActivityTable(String response) async { if (response.contains("{")) { await cacheDb.rawDelete("DELETE FROM Activities"); Debug.Log('Truncate Activity Table before'); List data = response.split(""); for (var value in data) { Map cat = jsonDecode(value); //Debug.Log(cat); await cacheDb.rawInsert( "INSERT OR REPLACE INTO Activities (${Activity.colType}, ${Activity.colStartTime}, ${Activity.colEndTime}, ${Activity.colMetadata}) " "VALUES ('${cat['task_id']}', '${cat['sTime']}','${cat['eTime']}', '${cat['metadata'].toString().replaceAll("'", "''")}') "); } } else { Debug.Log("No activities for now"); } } Future> GetProjects(bool forceOffline) async { if (cacheEnabled) { List _projects = []; if (offline || forceOffline) { //Retreive from cacheDB Debug.Log('offline, refreshing projects'); } else { //Check if server got updated, If not go for cache var android_id = await Settings.UUID(); bool updated = false; Debug.Log("Need to update activities : ${!updated}"); //Update CacheDB if (!updated) { await UpdateProjectsFromServer(); } } List cats = await cacheDb.rawQuery('SELECT * FROM Projects'); Debug.Log('projects : ${cats.length}'); for (Map element in cats) { String? name = element[Project.colName]; String? category = element[Project.colCat]; String? stepsJson = element[Project.colSteps]; String? deadline = element[Project.colDeadline]; int? eta = element[Project.colEta]; if (name == null || category == null || stepsJson == null || deadline == null || eta == null) { Debug.LogError( "Something is null!\nname:${name == null}, cat:${category == null}, steps:${stepsJson == null}, deadline${deadline == null}"); Debug.LogError( "TaskType:{$name}, Start Time:{$category}, endTime:{$stepsJson}, metadata:${deadline}"); continue; } Category? cat = await getCatFromId(category); Debug.Log('searching for $category'); if (cat == null) { Debug.LogError('couldnt find cat'); continue; } Debug.LogResponse('steps : $stepsJson'); List _steps = jsonDecode(stepsJson); List steps = []; int m_eta = 0; _steps.forEach((element) { ProjectStep step = ProjectStep.fromJson(element); m_eta += step.eta; steps.add(step); Debug.LogResponse(element); }); eta = (m_eta > 0) ? m_eta : eta; // Debug.Log(steps); _projects.add(Project(name.replaceAll(username, ""), category, steps, eta, DateTime.parse(deadline), cat: cat)); } projects = _projects; } else { Debug.Log("NC :Updating Projects as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_projects.php'), body: { "username": username, "device_id": await Settings.UUID() })); // Debug.Log("Activity response: ${response.body}"); List _projects = []; if (response.body.contains("{")) { List data = response.body.split(""); for (var value in data) { Map cat = jsonDecode(value); int? id = cat['id']; String? type = cat['task_id'].toString(); String? startTime = cat['sTime'].toString(); String? endTime = cat['eTime'].toString(); String? metadata = cat['metadata']; TaskType? taskType = await getTaskFromId(type); if (taskType == null) { Debug.LogError('null task found'); continue; } } projects = _projects; } else { Debug.Log("No activities for now"); } } catch (e) { Debug.LogError("Error : $e @ updating activities"); Debug.LogError("Error while acts $e"); } } return projects; } Future UpdateProjectsFromServer() async { Debug.Log("Updating Projects as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_projects.php'), body: { "username": username, "device_id": await Settings.UUID() })); await fillProjectsTable(response.body); } catch (e) { Debug.LogError("Error while acts $e"); } } Future fillProjectsTable(String response) async { await cacheDb.rawDelete("DELETE FROM Projects"); Debug.Log('Truncate Projects Table before'); Debug.LogResponse("Projects response: ${response}"); if (response.contains("{")) { List data = response.split(""); for (var value in data) { Map cat = jsonDecode(value); Debug.LogResponse(cat, src: 'project data'); await cacheDb.rawInsert( "INSERT OR REPLACE INTO Projects (${Project.colName}, ${Project.colCat}, ${Project.colSteps}, ${Project.colDeadline}, ${Project.colEta}) " "VALUES ('${cat['name']}', '${cat['category']}', '${cat['steps']}', '${cat['deadline']}', ${cat['eta']})"); } } else { Debug.Log("No projects for now"); } } Future> GetJournals(bool forceOffline) async { if (cacheEnabled) { List _journals = []; if (offline || forceOffline) { //Retreive from cacheDB } else { //Check if server got updated, If not go for cache //Validate device_id to check updates bool catsUpdated = false; // try { // http.Response update_response = (await http.post(Uri.parse(API_ENDPOINT+'/task_tracker/check_update.php'), body: {"username": username, "device_id": android_id})); // final data = update_response.body.split(','); // catsUpdated = data[0] == '1'; // } catch (e) { // Debug.Log(e); // } //Update CacheDB if (!catsUpdated) { await UpdateJournalsFromServer(); } } List cats = await cacheDb.query('Journal'); Debug.Log(cats.length); for (Map element in cats) { String? id = element['id'].toString(); String? title = element[Journal.colTitle].toString(); String? text = element[Journal.colDescription].toString(); if (id == null || title == null || text == null) { Debug.LogError("Something is null!"); Debug.LogError("id:{$id}, title:{$title}, text:${text}"); continue; } DateTime day = DateTime.parse(id.replaceAll(username, '')); // Debug.Log("name:{$catName}, color:{$catColor}, prod:{$catProductive}"); _journals.add(Journal(id, day, title: title, description: text)); } journal = _journals; } else { Debug.Log("NC: Updating Categories as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_journals.php'), body: { "username": username, "device_id": await Settings.UUID() })); Debug.LogResponse(response.body); List data = response.body.split(""); List _categories = []; for (var value in data) { Map cat = jsonDecode(value); //Debug.Log(catData); _categories.add(Journal(cat['id'], DateTime.parse(cat['id'].toString().replaceAll(username, '')), title: cat['title'], description: cat['text'])); } journal = _categories; } catch (e) { Debug.LogError("Error while cats NC: $e"); } } journal.sort((a, b) => b.day.compareTo(a.day)); return journal; } Future UpdateJournalsFromServer() async { Debug.Log("Updating Journal as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_journals.php'), body: { "username": username, "device_id": await Settings.UUID() })); await fillJournalsTable(response.body); } catch (e) { Debug.LogError("Error while cats $e"); } } Future fillJournalsTable(String response) async { Debug.LogResponse(response, src: 'Journal'); if (response.isEmpty) { Debug.Log('Empty Journal'); } else { List data = response.split(""); await cacheDb.delete("Journal"); for (var value in data) { Map cat = jsonDecode(value); //Debug.Log(catData); await cacheDb.rawInsert( "INSERT OR REPLACE INTO Journal (id, ${Journal.colTitle},${Journal.colDescription}) " "VALUES ('${cat['id']}','${cat['title'].toString().replaceAll("'", "''")}','${cat['description'].toString().replaceAll("'", "''")}') "); } } } Future> GetTodos(bool forceOffline) async { if (cacheEnabled) { List _todos = []; if (offline || forceOffline) { //Retreive from cacheDB } else { //Check if server got updated, If not go for cache //Validate device_id to check updates bool catsUpdated = false; // try { // http.Response update_response = (await http.post(Uri.parse(API_ENDPOINT+'/task_tracker/check_update.php'), body: {"username": username, "device_id": android_id})); // final data = update_response.body.split(','); // catsUpdated = data[0] == '1'; // } catch (e) { // Debug.Log(e); // } //Update CacheDB if (!catsUpdated) { await UpdateTodosFromServer(); } } List cats = await cacheDb.query('Todos'); Debug.Log(cats.length); for (Map element in cats) { String? id = element['id'].toString(); String? task_id = element[Todo.colCat]; String? metadata = element[Todo.colMetadata]; String? due_date = element[Todo.colDueDate]; String? notification_time = element[Todo.colNotificationTime]; if (id == null || task_id == null || metadata == null || due_date == null) { Debug.LogError("Something is null!"); Debug.LogError( "id:{$id}, task:{$task_id}, metadata:${metadata}, due_date: ${due_date}"); continue; } TaskType? taskType = await getTaskFromId(task_id); if (taskType == null) { Debug.LogError('got null taask for this todo!'); Debug.LogResponse( "id:{$id}, task:{$task_id}, metadata:${metadata}, due_date: ${due_date}"); } DateTime dueDate = DateTime.parse(due_date); DateTime? notificationTime = (notification_time == null) ? null : ((notification_time.isEmpty || notification_time == 'null') ? null : DateTime.parse(notification_time)); // Debug.Log("name:{$catName}, color:{$catColor}, prod:{$catProductive}"); _todos.add(Todo(id, task_id, metadata, dueDate, notificationTime: notificationTime, task: taskType)); } todos = _todos; } else { Debug.Log("NC: Updating todos as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_todos.php'), body: { "username": username, "device_id": await Settings.UUID() })); Debug.LogResponse(response.body); List data = response.body.split(""); List _categories = []; for (var value in data) { Map cat = jsonDecode(value); //Debug.Log(catData); _categories.add(Journal(cat['id'], DateTime.parse(cat['id'].toString().replaceAll(username, '')), title: cat['title'], description: cat['text'])); } journal = _categories; } catch (e) { Debug.LogError("Error while cats NC: $e"); } } // journal.sort((a, b) => b.day.compareTo(a.day)); return todos; } Future UpdateTodosFromServer() async { Debug.Log("Updating Todos as $username"); try { http.Response response = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/get_todos.php'), body: { "username": username, "device_id": await Settings.UUID() })); Debug.LogResponse(response.body); await fillTodosTable(response.body); } catch (e) { Debug.LogError("Error while cats $e"); } } Future fillTodosTable(String response) async { if (response.contains("{")) { List data = response.split(""); await cacheDb.delete("Todos"); for (var value in data) { Map cat = jsonDecode(value); //Debug.Log(catData); await cacheDb.rawInsert( "INSERT OR REPLACE INTO Todos (id, ${Todo.colCat},${Todo.colMetadata},${Todo.colDueDate},${Todo.colNotificationTime}) " "VALUES ('${cat['id'].toString().replaceAll("'", "''")}', '${cat['task_id']}', '${cat['metadata'].toString().replaceAll("'", "''")}', '${cat['due_date']}', '${cat['notification_time']}') "); } } else { Debug.Log('Empty Todos'); } } Future getTaskFromId(String taskId) async { // await GetTaskTypes(false); TaskType? cat = null; for (var element in taskTypes) { if (element.id == taskId) { cat = element; cat?.cat = await getCatFromId((cat?.category ?? '')); } } if (cat == null) { Debug.LogError( 'Got null tasktype for ${taskId} after searching on ${taskTypes.length}'); } return cat; } Future getCatFromId(String catId) async { // await GetTaskTypes(false); Category? cat = null; for (var element in categories) { if (element.category_id == catId) { cat = element; } } return cat; } Future getProjectFromId(String projectId) async { // await GetTaskTypes(false); Project? project = null; for (var element in projects) { if (element.getName() == projectId.replaceAll(username, "")) { project = element; } } if (project == null) { Debug.LogError( 'Got null project for ${projectId} after searching on ${projects.length}'); } return project; } bool journalExists(DateTime date) { int journalId = -1; for (int i = 0; i < journal.length; i++) { // Debug.Log('${journal[i].day } : $date'); if (DateFormat('yyyy-MM-dd').format(journal[i].day) == DateFormat('yyyy-MM-dd').format(date)) { journalId = i; break; } } return (journalId > 0); } //Helpers class Helpers { Future _getId() async { var deviceInfo = DeviceInfoPlugin(); if (Platform.isIOS) { // import 'dart:io' var iosDeviceInfo = await deviceInfo.iosInfo; return iosDeviceInfo.identifierForVendor; // unique ID on iOS } else { var androidDeviceInfo = await deviceInfo.androidInfo; return androidDeviceInfo.androidId; // unique ID on Android } } } bool ParseBool(obj) { return obj.toString().toLowerCase() == "true" || obj.toString() == "1"; } class UserOperations { static DateFormat dFormat = DateFormat("yyyy-MM-dd HH:mm:ss"); static Future addCategory(String name, String color, bool productive, {bool bulk = false}) async { Map queryBody = { 'username': username, 'device_id': await Settings.UUID(), 'name': name, 'color': color, 'productive': productive ? '1' : '0' }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'add_category', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); //update Cache Map data = { Category.colCatId: username + name, Category.colName: name, Category.colColor: color, Category.colProductive: productive }; await cacheDb.insert('Categories', data); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/add_category.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error editing acti $e}'); } //executeQueries(); } if (!bulk) { //Add to server and refresh Cache await executeQueries(); } } static Future addTaskType(String name, String category, {bool bulk = false, String? relatedProject = null}) async { Map queryBody = { 'id': username + name, 'username': username, 'device_id': await Settings.UUID(), 'name': name, 'category': username + category, 'related_project': (relatedProject == null) ? '' : (username + relatedProject) }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'add_taskType', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); //update Cache Map data = { TaskType.colId: username + name, Category.colName: name, Category.colCatId: username + category, }; if (relatedProject != null || relatedProject == 'None') { data.putIfAbsent( TaskType.colRelatedProject, () => relatedProject.toString()); } await cacheDb.insert('TaskTypes', data); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/add_taskType.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error editing acti $e}'); } } if (!bulk) { //Add to server and refresh Cache await executeQueries(); } } static Future editTaskType(String oldName, String name, String category, {bool bulk = false, String? relatedProject = null}) async { Map queryBody = { 'id': username + oldName, 'username': username, 'name': name, 'category': username + category, 'related_project': (relatedProject == null) ? '' : (username + relatedProject) }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'edit_taskType', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); //update Cache await cacheDb.rawUpdate( "UPDATE TaskTypes SET ${TaskType.colId}='${username + name}', ${TaskType.colName}='$name', ${TaskType.colCategory}='${username + category}', ${TaskType.colRelatedProject}='${(relatedProject == 'None') ? '' : relatedProject}' WHERE id='${username + oldName}'"); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/add_taskType.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error editing task $e}'); } } if (!bulk) { //Add to server and refresh Cache await executeQueries(); } } static Future addActivity(String type, DateTime sTime, DateTime eTime, {String metadata = 'null', bool bulk = false, Function(int)? onOverlap}) async { Map queryBody = { 'username': username, 'device_id': await Settings.UUID(), 'type': username + type, 'sTime': dFormat.format(sTime), 'eTime': dFormat.format(eTime), 'metadata': metadata }; Map query = { Queries.colLink: 'add_activity', Queries.colData: jsonEncode(queryBody) }; if (cacheEnabled) { //Check for timeoverlapse activities = await GetActivities(true); int? overlapCount = Sqflite.firstIntValue(await cacheDb.rawQuery( "SELECT COUNT(*) FROM Activities WHERE (((${Activity.colStartTime} < datetime('$sTime')) AND ((${Activity.colEndTime} > datetime('$eTime')) OR (${Activity.colEndTime} < datetime('$eTime') AND ${Activity.colEndTime} > datetime('$sTime')))) OR (${Activity.colStartTime} > datetime('$sTime') AND ${Activity.colStartTime} < datetime('$eTime')) OR (${Activity.colStartTime}=datetime('$sTime') AND ${Activity.colEndTime}=datetime('$eTime')))")); Debug.Log("ActivityOverlaps: $overlapCount"); if (overlapCount! > 0) { onOverlap!(overlapCount); return; } if (metadata.length > 0) {} //Add Query Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); //update Cache Map data = { Activity.colType: username + type, Activity.colStartTime: dFormat.format(sTime), Activity.colEndTime: dFormat.format(eTime), Activity.colMetadata: metadata }; await cacheDb.insert('Activities', data); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/add_activity.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error adding player $e}'); } } if (!bulk) { //Add to server and refresh Cache await executeQueries(); } } static Future editActivity(DateTime init_sTime, DateTime init_eTime, String type, DateTime sTime, DateTime eTime, {String metadata = 'null', bool bulk = false, Function(int)? onOverlap}) async { Map queryBody = { 'username': username, 'device_id': await Settings.UUID(), 'type': username + type, 'init_sTime': dFormat.format(init_sTime), 'init_eTime': dFormat.format(init_eTime), 'sTime': dFormat.format(sTime), 'eTime': dFormat.format(eTime), 'metadata': metadata }; Map query = { Queries.colLink: 'edit_activity', Queries.colData: jsonEncode(queryBody) }; if (cacheEnabled) { //Check for timeoverlapse activities = await GetActivities(true); int? overlapCount = Sqflite.firstIntValue(await cacheDb.rawQuery( "SELECT COUNT(*) FROM Activities WHERE (((${Activity.colStartTime} < datetime('$sTime')) AND ((${Activity.colEndTime} > datetime('$eTime')) OR (${Activity.colEndTime} < datetime('$eTime') AND ${Activity.colEndTime} > datetime('$sTime')))) OR (${Activity.colStartTime} > datetime('$sTime') AND ${Activity.colStartTime} < datetime('$eTime')) OR (${Activity.colStartTime}=datetime('$sTime') AND ${Activity.colEndTime}=datetime('$eTime'))) AND ${Activity.colStartTime}!=datetime('${init_sTime}') AND ${Activity.colEndTime} != datetime('${init_eTime}')")); Debug.Log("ActivityOverlaps: $overlapCount"); if (overlapCount! > 0) { onOverlap!(overlapCount); return; } if (metadata.length > 0) {} //Add Query Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); //TODO //update Cache // Map data = {Activity.colType: username + type, Activity.colStartTime: dFormat.format(sTime), Activity.colEndTime: dFormat.format(eTime), Activity.colMetadata: metadata}; // String updateActQuery = "UPDATE Activities SET ${Activity.colType}="; // await cacheDb.insert('Activities', data); await cacheDb.rawUpdate( "UPDATE Activities SET ${Activity.colType}='${username + type}', ${Activity.colStartTime}=datetime('${dFormat.format(sTime)}'), ${Activity.colEndTime}=datetime('${dFormat.format(eTime)}'), ${Activity.colMetadata}='$metadata' WHERE ${Activity.colStartTime}=datetime('${dFormat.format(init_sTime)}')"); await refreshUserData(forceOffline: true); } else { // queries.add(Queries('edit_activity', jsonEncode(queryBody))); try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/edit_activity.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error editing acti $e}'); } } if (!bulk) { //Add to server and refresh Cache await executeQueries(); } } static Future startOngoing(String activityData) async { Map queryBody = { 'username': username, 'current_activity': activityData, }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'start_ongoing', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/start_ongoing.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error adding ongoing $e}'); } } await executeQueries(); } static Future stopOngoing() async { Map queryBody = { 'username': username, }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'stop_ongoing', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/stop_ongoing.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error adding ongoing $e}'); } } await executeQueries(); } static Future addProject(String name, String category, List steps, int eta, DateTime deadline) async { Map queryBody = { 'name': username + name, 'username': username, 'device_id': await Settings.UUID(), 'category_id': username + category, 'steps': jsonEncode(steps), 'eta': eta.toString(), 'deadline': DateFormat("yyyy-MM-dd").format(deadline) }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'add_project', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); //update Cache Map data = { Project.colName: username + name, Project.colCat: category, Project.colSteps: jsonEncode(steps), Project.colEta: eta, Project.colDeadline: deadline.toString() }; await cacheDb.insert('Projects', data); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/add_project.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error adding prjct $e}'); } } UserOperations.addTaskType(name, category, relatedProject: name); await executeQueries(); } static Future editProject(String oldName, String name, String category, List steps, int eta, DateTime deadline) async { Map queryBody = { 'oldName': username + oldName, 'name': username + name, 'username': username, 'category_id': username + category, 'steps': jsonEncode(steps), 'eta': eta.toString(), 'deadline': DateFormat("yyyy-MM-dd").format(deadline) }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'edit_project', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); //update Cache Map data = { Project.colName: username + name, Project.colCat: category, Project.colSteps: jsonEncode(steps), Project.colEta: eta, Project.colDeadline: deadline.toString() }; await cacheDb.rawUpdate( "UPDATE Projects SET ${Project.colName}='${username + name}', ${Project.colCat}='${username + category}', ${Project.colSteps}='${jsonEncode(steps)}', ${Project.colEta}='${eta}', ${Project.colDeadline}='${deadline.toString()}' WHERE ${Project.colName}='${username + oldName}'"); await cacheDb.rawUpdate( "UPDATE TaskTypes SET ${TaskType.colRelatedProject}='${username + name}' WHERE ${TaskType.colRelatedProject}='${username + oldName}'"); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/edit_project.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error adding prjct $e}'); } } await executeQueries(); } static Future CompleteProjectStep( Project project, ProjectStep step, DateTime finishedDate) async { project.steps.forEach((element) { if (element.stepName == step.stepName) { element.finishedDate = finishedDate; } }); Map queryBody = { 'name': username + project.name, 'username': username, 'steps': jsonEncode(project.steps), }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'update_projectSteps', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); await cacheDb.rawUpdate( "UPDATE Projects SET steps='${jsonEncode(project.steps)}' WHERE ${Project.colName}='${project.name}'"); //update Cache // Map data = {Project.colName: username+name, Project.colCat: category, Project.colSteps: jsonEncode(steps),Project.colEta: eta, Project.colDeadline: deadline.toString()}; // await cacheDb.insert('Projects', data); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/update_projectSteps.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error completing prjctStep $e}'); } } await executeQueries(); } static Future UndoProjectStep(Project project, ProjectStep step) async { project.steps.forEach((element) { if (element.stepName == step.stepName) { element.finishedDate = null; } }); Map queryBody = { 'name': username + project.name, 'username': username, 'steps': jsonEncode(project.steps), }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'update_projectSteps', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); await cacheDb.rawUpdate( "UPDATE Projects SET steps='${jsonEncode(project.steps)}' WHERE ${Project.colName}='${project.name}'"); //update Cache // Map data = {Project.colName: username+name, Project.colCat: category, Project.colSteps: jsonEncode(steps),Project.colEta: eta, Project.colDeadline: deadline.toString()}; // await cacheDb.insert('Projects', data); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/update_projectSteps.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error completing prjctStep $e}'); } } await executeQueries(); } static Future addJournal( DateTime day, String title, String text) async { bool exist = false; for (var element in journal) { if (element.day == day) { //Wat! exist = true; break; } } if (exist) { return; } String id = username + DateFormat('yyyy-MM-dd').format(day); Map queryBody = { 'username': username, 'id': id, 'title': title, 'description': text }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'add_journal', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); //update Cache Map data = { 'id': id, Journal.colTitle: title, Journal.colDescription: text }; await cacheDb.insert('Journal', data); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/add_journal.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error adding journal entry $e}'); } //executeQueries(); } //Add to server and refresh Cache await executeQueries(); } static Future editJournal( DateTime oldDay, DateTime day, String title, String text) async { String oldId = username + DateFormat('yyyy-MM-dd').format(oldDay); String id = username + DateFormat('yyyy-MM-dd').format(day); Map queryBody = { 'username': username, 'old_id': oldId, 'id': id, 'title': title, 'description': text }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'edit_journal', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); await cacheDb.rawUpdate( "UPDATE Journal SET id='$id', ${Journal.colTitle}='${title.toString().replaceAll("'", "''")}', ${Journal.colDescription}='${text.toString().replaceAll("'", "''")}' WHERE id='$oldId'"); //update Cache Map data = { 'id': id, Journal.colTitle: title, Journal.colDescription: text }; // await cacheDb.insert('Journal', data); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/edit_journal.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error adding journal entry $e}'); } //executeQueries(); } //Add to server and refresh Cache await executeQueries(); } static Future addTodo(String taskType, String metadata, DateTime dueDate, DateTime? notificationTime) async { String taskId = username + taskType; if (taskId.contains('[') && taskId.contains(']')) { //has a project related taskId = taskId.substring(0, taskId.indexOf('[') - 1); } String id = taskId + metadata; Map queryBody = { 'username': username, 'task': taskId, 'metadata': metadata, 'due_date': DateFormat('yyyy-MM-dd').format(dueDate), if (notificationTime != null) 'notification_time': DateFormat('yyyy-MM-dd HH:mm').format(notificationTime) }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'add_todo', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); //update Cache Map data = { 'id': id, Todo.colCat: taskId, Todo.colMetadata: metadata, Todo.colDueDate: DateFormat('yyyy-MM-dd').format(dueDate), if (notificationTime != null) Todo.colNotificationTime: DateFormat('yyyy-MM-dd HH:mm').format(notificationTime) }; await cacheDb.insert('Todos', data); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/add_todo.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error adding journal entry $e}'); } //executeQueries(); } //Add to server and refresh Cache await executeQueries(); } static Future editTodo(String oldId, String taskType, String metadata, DateTime dueDate, DateTime? notificationTime) async { String taskId = username + taskType; if (taskId.contains('[') && taskId.contains(']')) { //has a project related taskId = taskId.substring(0, taskId.indexOf('[') - 1); } String id = taskId + metadata; Map queryBody = { 'old_id': oldId, 'username': username, 'task': taskId, 'metadata': metadata, 'due_date': DateFormat('yyyy-MM-dd').format(dueDate), if (notificationTime != null) 'notification_time': DateFormat('yyyy-MM-dd HH:mm').format(notificationTime) }; if (cacheEnabled) { //Add Query Map query = { Queries.colLink: 'edit_todo', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); await cacheDb.insert('Queries', query); String dueDateString = DateFormat('yyyy-MM-dd').format(dueDate); //update Cache // Map data = {'id': id, Todo.colCat: taskId, Todo.colMetadata: metadata, Todo.colDueDate: DateFormat('yyyy-MM-dd').format(dueDate), if(notificationTime!=null)Todo.colNotificationTime:DateFormat('yyyy-MM-dd HH:mm').format(notificationTime)}; // await cacheDb.insert('Todos', data); await cacheDb.rawUpdate( "UPDATE Todos SET id='$id', ${Todo.colCat}='$taskId', ${Todo.colMetadata}='$metadata', ${Todo.colDueDate}='$dueDateString'${(notificationTime != null) ? ", ${Todo.colNotificationTime}='${DateFormat('yyyy-MM-dd HH:mm').format(notificationTime)}'" : ''} WHERE id='$oldId'"); await refreshUserData(forceOffline: true); } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/edit_todo.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error editing todo entry $e}'); } //executeQueries(); } //Add to server and refresh Cache await executeQueries(); } static Future deleteTask(String name, {bulk = false}) async { Map queryBody = { 'id': username + name, 'username': username, 'device_id': await Settings.UUID(), }; //Add Query Map query = { Queries.colLink: 'delete_taskType', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); if (cacheEnabled) { await cacheDb.insert('Queries', query); //update Cache Map data = { TaskType.colId: username + name, Category.colName: name, }; await cacheDb .rawDelete("DELETE FROM TaskTypes WHERE id='${username + name}'"); await refreshUserData(forceOffline: true); //Add to server and refresh Cache } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/delete_taskType.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error editing acti $e}'); } } if (!bulk) { await executeQueries(); } } static Future deleteCategory(String name, {bulk = false}) async { Map queryBody = { 'id': username + name, 'username': username, 'device_id': await Settings.UUID(), }; //Add Query Map query = { Queries.colLink: 'delete_category', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); if (cacheEnabled) { await cacheDb.insert('Queries', query); //update Cache Map data = { TaskType.colId: username + name, Category.colName: name, }; await cacheDb.rawDelete( "DELETE FROM Categories WHERE ${Category.colCatId}='${username + name}'"); await refreshUserData(forceOffline: true); //Add to server and refresh Cache } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/delete_category.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error editing acti $e}'); } } if (!bulk) { await executeQueries(); } } static Future deleteActivity(Activity activity, {bulk = false}) async { Map queryBody = { 'username': username, 'device_id': await Settings.UUID(), 'sTime': activity.trueStartTime.toString(), 'eTime': activity.trueEndTime.toString(), }; //Add Query Map query = { Queries.colLink: 'delete_activity', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); if (cacheEnabled) { await cacheDb.insert('Queries', query); //update Cache String deleteQuery = "DELETE FROM Activities WHERE ${Activity.colStartTime}=datetime('${dFormat.format(activity.trueStartTime)}') AND ${Activity.colEndTime}=datetime('${dFormat.format(activity.trueEndTime)}')"; Debug.LogResponse("delteQuery : $deleteQuery"); await cacheDb.rawDelete(deleteQuery); await refreshUserData(forceOffline: true); //Add to server and refresh Cache } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/delete_activity.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error editing acti $e}'); } } if (!bulk) { await executeQueries(); } } static Future deleteProject(String project, {bulk = false}) async { Map queryBody = { 'username': username, 'name': username + project, }; //Add Query Map query = { Queries.colLink: 'delete_project', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); if (cacheEnabled) { await cacheDb.insert('Queries', query); //update Cache String deleteQuery = "DELETE FROM Projects WHERE ${Project.colName}='${username + project}'"; Debug.LogResponse("delteQuery : $deleteQuery"); await cacheDb.rawDelete(deleteQuery); await refreshUserData(forceOffline: true); //Add to server and refresh Cache } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/delete_project.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error deleting project $e}'); } } if (!bulk) { await executeQueries(); } } static Future deleteJournal(String id, {bulk = false}) async { Map queryBody = { 'username': username, 'id': id, }; //Add Query Map query = { Queries.colLink: 'delete_journal', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); if (cacheEnabled) { await cacheDb.insert('Queries', query); //update Cache String deleteQuery = "DELETE FROM Journal WHERE id='$id'"; Debug.LogResponse("delteQuery : $deleteQuery"); await cacheDb.rawDelete(deleteQuery); await refreshUserData(forceOffline: true); //Add to server and refresh Cache } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/delete_journal.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error deleting journal $e}'); } } if (!bulk) { await executeQueries(); } } static Future deleteTodo(String id, {bulk = false}) async { Map queryBody = { 'username': username, 'id': id, }; //Add Query Map query = { Queries.colLink: 'delete_todo', Queries.colData: jsonEncode(queryBody) }; Debug.LogResponse( "adding new query ${query[Queries.colLink]} : ${jsonEncode(queryBody)}"); if (cacheEnabled) { await cacheDb.insert('Queries', query); //update Cache String deleteQuery = "DELETE FROM Todos WHERE id='$id'"; Debug.LogResponse("delteQuery : $deleteQuery"); await cacheDb.rawDelete(deleteQuery); await refreshUserData(forceOffline: true); //Add to server and refresh Cache } else { try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/delete_todo.php'), body: queryBody)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("success")) { //Success } } catch (e) { Debug.LogError('NC: Error deleting journal $e}'); } } if (!bulk) { await executeQueries(); } } static Future executeQueries() async { if (cacheEnabled) { if (offline) { Debug.Log("Cannot executre queries, Offline!"); return; } List> queries = await cacheDb.query('Queries'); for (Map element in queries) { int id = int.parse(element['id'].toString()); String? file = element[Queries.colLink].toString(); String? data = element[Queries.colData].toString(); if (file == null || data == null) { Debug.LogError("Null query, Ignoring..."); continue; } Debug.LogResponse("Query[\n file:$file, \ndata:$data]"); //Execute the http here Map body = jsonDecode(data); try { http.Response queryResponse = (await http.post( Uri.parse(API_ENDPOINT + '/task_tracker/$file.php'), body: body)); Debug.LogResponse("Query executed : Results{${queryResponse.body}"); if (queryResponse.body.toLowerCase().contains("+") || queryResponse.body.toLowerCase().contains("success")) { await cacheDb.rawDelete('DELETE FROM Queries WHERE id=$id'); } offline = false; } catch (e) { Debug.LogError("Error while query $e"); } } //await refreshUserData(); } else { await refreshUserData(); Debug.LogError( 'Trying to execute queries in no cahce mode, We dont do that here'); } } }