From 7d3d8e834607235e134148f99e435dc64cc7fc52 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 06:38:29 +0530 Subject: [PATCH 01/47] feat: add taskchampion sync --- lib/api_service.dart | 490 ++++++++++++++++++ .../home/controllers/home_controller.dart | 1 + .../controllers/settings_controller.dart | 3 + .../settings/views/settings_page_body.dart | 16 +- .../views/settings_page_taskchampion.dart | 29 ++ lib/app/utils/language/english_sentences.dart | 7 + lib/app/utils/language/hindi_sentences.dart | 7 + lib/app/utils/language/marathi_sentences.dart | 7 + lib/app/utils/language/sentences.dart | 3 + lib/app/utils/taskchampion/taskchampion.dart | 182 +++++++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 24 + pubspec.yaml | 1 + 13 files changed, 771 insertions(+), 1 deletion(-) create mode 100644 lib/api_service.dart create mode 100644 lib/app/modules/settings/views/settings_page_taskchampion.dart create mode 100644 lib/app/utils/taskchampion/taskchampion.dart diff --git a/lib/api_service.dart b/lib/api_service.dart new file mode 100644 index 00000000..a6b9f668 --- /dev/null +++ b/lib/api_service.dart @@ -0,0 +1,490 @@ +// ignore_for_file: depend_on_referenced_packages, unnecessary_null_in_if_null_operators + +import 'dart:convert'; +import 'package:flutter/foundation.dart'; +import 'package:http/http.dart' as http; +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; +import 'package:taskwarrior/app/utils/taskchampion/taskchampion.dart'; + +class Tasks { + final int id; + final String description; + final String? project; + final String status; + final String? uuid; + final double? urgency; + final String? priority; + final String? due; + final String? end; + final String entry; + final String? modified; + + Tasks({ + required this.id, + required this.description, + required this.project, + required this.status, + required this.uuid, + required this.urgency, + required this.priority, + required this.due, + required this.end, + required this.entry, + required this.modified, + }); + + factory Tasks.fromJson(Map json) { + return Tasks( + id: json['id'], + description: json['description'], + project: json['project'], + status: json['status'], + uuid: json['uuid'], + urgency: json['urgency'].toDouble(), + priority: json['priority'], + due: json['due'], + end: json['end'], + entry: json['entry'], + modified: json['modified'], + ); + } + + Map toJson() { + return { + 'id': id, + 'description': description, + 'project': project, + 'status': status, + 'uuid': uuid, + 'urgency': urgency, + 'priority': priority, + 'due': due, + 'end': end, + 'entry': entry, + 'modified': modified, + }; + } +} + +String baseUrl = 'YOUR_IP'; +String origin = 'CONTAINER_ORIGIN'; + +Future> fetchTasks(String uuid, String encryptionSecret) async { + String url = + '$baseUrl/tasks?email=$origin&origin=$origin&UUID=$uuid&encryptionSecret=$encryptionSecret'; + + var response = await http.get(Uri.parse(url), headers: { + "Content-Type": "application/json", + }).timeout(const Duration(seconds: 10000)); + if (response.statusCode == 200) { + List allTasks = jsonDecode(response.body); + debugPrint(allTasks.toString()); + return allTasks.map((task) => Tasks.fromJson(task)).toList(); + } else { + throw Exception('Failed to load tasks'); + } +} + +Future updateTasksInDatabase(List tasks) async { + var taskDatabase = TaskDatabase(); + await taskDatabase.open(); + // find tasks without UUID + List tasksWithoutUUID = await taskDatabase.findTasksWithoutUUIDs(); + + //add tasks without UUID to the server and delete them from database + for (var task in tasksWithoutUUID) { + try { + await addTaskAndDeleteFromDatabase( + task.description, task.project!, task.due!, task.priority!); + } catch (e) { + debugPrint('Failed to add task without UUID to server: $e'); + } + } + + // update existing tasks in db + for (var task in tasks) { + var existingTask = await taskDatabase.getTaskByUuid(task.uuid!); + if (existingTask != null) { + if (task.modified!.compareTo(existingTask.modified!) > 0) { + await taskDatabase.updateTask(task); + } + } else { + // add new tasks to db + await taskDatabase.insertTask(task); + } + } + + var localTasks = await taskDatabase.fetchTasksFromDatabase(); + var localTasksMap = {for (var task in localTasks) task.uuid: task}; + + for (var serverTask in tasks) { + var localTask = localTasksMap[serverTask.uuid]; + + if (localTask == null) { + // Task doesn't exist in the local database, insert it + await taskDatabase.insertTask(serverTask); + } else { + var serverTaskModifiedDate = DateTime.parse(serverTask.modified!); + var localTaskModifiedDate = DateTime.parse(localTask.modified!); + + if (serverTaskModifiedDate.isAfter(localTaskModifiedDate)) { + // Server task is newer, update local database + await taskDatabase.updateTask(serverTask); + } else if (serverTaskModifiedDate.isBefore(localTaskModifiedDate)) { + // local task is newer, update server + await modifyTaskOnTaskwarrior( + localTask.description, + localTask.project!, + localTask.due!, + localTask.priority!, + localTask.status, + localTask.uuid!, + ); + } + } + } +} + +Future deleteTask( + String email, String encryptionSecret, String uuid, String taskUuid) async { + final url = Uri.parse('$baseUrl/delete-task'); + final body = jsonEncode({ + 'email': email, + 'encryptionSecret': encryptionSecret, + 'UUID': uuid, + 'taskuuid': taskUuid, + }); + + try { + final response = await http.post( + url, + headers: { + 'Content-Type': 'application/json', + }, + body: body, + ); + + if (response.statusCode == 200) { + debugPrint('Task deleted successfully on server'); + } else { + debugPrint('Failed to delete task: ${response.statusCode}'); + } + } catch (e) { + debugPrint('Error deleting task: $e'); + } +} + +Future completeTask( + String email, String encryptionSecret, String uuid, String taskUuid) async { + final url = Uri.parse('$baseUrl/complete-task'); + final body = jsonEncode({ + 'email': email, + 'encryptionSecret': encryptionSecret, + 'UUID': uuid, + 'taskuuid': taskUuid, + }); + + try { + final response = await http.post( + url, + headers: { + 'Content-Type': 'application/json', + }, + body: body, + ); + + if (response.statusCode == 200) { + debugPrint('Task completed successfully on server'); + } else { + debugPrint('Failed to complete task: ${response.statusCode}'); + } + } catch (e) { + debugPrint('Error completing task: $e'); + } +} + +Future addTaskAndDeleteFromDatabase( + String description, String project, String due, String priority) async { + String apiUrl = '$baseUrl/add-task'; + var c = await CredentialsStorage.getClientId(); + var e = await CredentialsStorage.getEncryptionSecret(); + debugPrint(c); + debugPrint(e); + await http.post( + Uri.parse(apiUrl), + headers: { + 'Content-Type': 'text/plain', + }, + body: jsonEncode({ + 'email': 'email', + 'encryptionSecret': e, + 'UUID': c, + 'description': description, + 'project': project, + 'due': due, + 'priority': priority, + }), + ); + + var taskDatabase = TaskDatabase(); + await taskDatabase.open(); + await taskDatabase._database!.delete( + 'Tasks', + where: 'description = ? AND due = ? AND project = ? AND priority = ?', + whereArgs: [description, due, project, priority], + ); +} + +Future modifyTaskOnTaskwarrior(String description, String project, + String due, String priority, String status, String taskuuid) async { + String apiUrl = '$baseUrl/modify-task'; + var c = await CredentialsStorage.getClientId(); + var e = await CredentialsStorage.getEncryptionSecret(); + debugPrint(c); + debugPrint(e); + await http.post( + Uri.parse(apiUrl), + headers: { + 'Content-Type': 'text/plain', + }, + body: jsonEncode({ + "email": "e", + "encryptionSecret": e, + "UUID": c, + "description": description, + "priority": priority, + "project": project, + "due": due, + "status": status, + "taskuuid": taskuuid, + }), + ); + + var taskDatabase = TaskDatabase(); + await taskDatabase.open(); + await taskDatabase._database!.delete( + 'Tasks', + where: 'description = ? AND due = ? AND project = ? AND priority = ?', + whereArgs: [description, due, project, priority], + ); +} + +class TaskDatabase { + Database? _database; + + Future open() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, 'tasks.db'); + + _database = await openDatabase(path, version: 1, + onCreate: (Database db, version) async { + await db.execute(''' + CREATE TABLE Tasks ( + uuid TEXT PRIMARY KEY, + id INTEGER, + description TEXT, + project TEXT, + status TEXT, + urgency REAL, + priority TEXT, + due TEXT, + end TEXT, + entry TEXT, + modified TEXT + ) + '''); + }); + } + + Future ensureDatabaseIsOpen() async { + if (_database == null) { + await open(); + } + } + + Future> fetchTasksFromDatabase() async { + await ensureDatabaseIsOpen(); + + final List> maps = await _database!.query('Tasks'); + var a = List.generate(maps.length, (i) { + return Tasks( + id: maps[i]['id'], + description: maps[i]['description'], + project: maps[i]['project'], + status: maps[i]['status'], + uuid: maps[i]['uuid'], + urgency: maps[i]['urgency'], + priority: maps[i]['priority'], + due: maps[i]['due'], + end: maps[i]['end'], + entry: maps[i]['entry'], + modified: maps[i]['modified'], + ); + }); + // debugPrint('Tasks from db'); + // debugPrint(a.toString()); + return a; + } + + Future deleteAllTasksInDB() async { + await ensureDatabaseIsOpen(); + + await _database!.delete('Tasks'); + debugPrint('Deleted all tasks'); + await open(); + debugPrint('Created new task table'); + } + + Future printDatabaseContents() async { + await ensureDatabaseIsOpen(); + + List> maps = await _database!.query('Tasks'); + for (var map in maps) { + map.forEach((key, value) { + debugPrint('Key: $key, Value: $value, Type: ${value.runtimeType}'); + }); + } + } + + Future insertTask(Tasks task) async { + await ensureDatabaseIsOpen(); + + await _database!.insert( + 'Tasks', + task.toJson(), + conflictAlgorithm: ConflictAlgorithm.replace, + ); + } + + Future updateTask(Tasks task) async { + await ensureDatabaseIsOpen(); + + await _database!.update( + 'Tasks', + task.toJson(), + where: 'uuid = ?', + whereArgs: [task.uuid], + ); + } + + Future getTaskByUuid(String uuid) async { + await ensureDatabaseIsOpen(); + + List> maps = await _database!.query( + 'Tasks', + where: 'uuid = ?', + whereArgs: [uuid], + ); + + if (maps.isNotEmpty) { + return Tasks.fromJson(maps.first); + } else { + return null; + } + } + + Future markTaskAsCompleted(String uuid) async { + await ensureDatabaseIsOpen(); + + await _database!.update( + 'Tasks', + {'modified': (DateTime.now()).toIso8601String(), 'status': 'completed'}, + where: 'uuid = ?', + whereArgs: [uuid], + ); + debugPrint('task${uuid}completed'); + debugPrint({DateTime.now().toIso8601String()}.toString()); + } + + Future markTaskAsDeleted(String uuid) async { + await ensureDatabaseIsOpen(); + + await _database!.update( + 'Tasks', + {'status': 'deleted'}, + where: 'uuid = ?', + whereArgs: [uuid], + ); + debugPrint('task${uuid}deleted'); + } + + Future saveEditedTaskInDB( + String uuid, + String newDescription, + String newProject, + String newStatus, + String newPriority, + String newDue, + ) async { + await ensureDatabaseIsOpen(); + + debugPrint('task${uuid}deleted'); + await _database!.update( + 'Tasks', + { + 'description': newDescription, + 'project': newProject, + 'status': newStatus, + 'priority': newPriority, + 'due': newDue, + }, + where: 'uuid = ?', + whereArgs: [uuid], + ); + debugPrint('task${uuid}edited'); + } + + Future> findTasksWithoutUUIDs() async { + await ensureDatabaseIsOpen(); + + List> maps = await _database!.query( + 'Tasks', + where: 'uuid IS NULL OR uuid = ?', + whereArgs: [''], + ); + + return List.generate(maps.length, (i) { + return Tasks.fromJson(maps[i]); + }); + } + + Future> getTasksByProject(String project) async { + List> maps = await _database!.query( + 'Tasks', + where: 'project = ?', + whereArgs: [project], + ); + + return List.generate(maps.length, (i) { + return Tasks( + uuid: maps[i]['uuid'], + id: maps[i]['id'], + description: maps[i]['description'], + project: maps[i]['project'], + status: maps[i]['status'], + urgency: maps[i]['urgency'], + priority: maps[i]['priority'], + due: maps[i]['due'], + end: maps[i]['end'], + entry: maps[i]['entry'], + modified: maps[i]['modified'], + ); + }); + } + + Future> searchTasks(String query) async { + final List> maps = await _database!.query( + 'tasks', + where: 'description LIKE ? OR project LIKE ?', + whereArgs: ['%$query%', '%$query%'], + ); + return List.generate(maps.length, (i) { + return Tasks.fromJson(maps[i]); + }); + } + + Future close() async { + await _database!.close(); + } +} diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 466feb62..701a9bf2 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -435,6 +435,7 @@ class HomeController extends GetxController { RxBool syncOnTaskCreate = false.obs; RxBool delaytask = false.obs; RxBool change24hr = false.obs; + RxBool taskchampion = false.obs; // dialogue box diff --git a/lib/app/modules/settings/controllers/settings_controller.dart b/lib/app/modules/settings/controllers/settings_controller.dart index 9e08f687..c1f89163 100644 --- a/lib/app/modules/settings/controllers/settings_controller.dart +++ b/lib/app/modules/settings/controllers/settings_controller.dart @@ -4,6 +4,7 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:get/get_rx/get_rx.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -163,6 +164,7 @@ class SettingsController extends GetxController { RxBool isSyncOnTaskCreateActivel = false.obs; RxBool delaytask = false.obs; RxBool change24hr = false.obs; + RxBool taskchampion = false.obs; RxBool isDarkModeOn = false.obs; void initDarkMode() { @@ -177,6 +179,7 @@ class SettingsController extends GetxController { prefs.getBool('sync-OnTaskCreate') ?? false; delaytask.value = prefs.getBool('delaytask') ?? false; change24hr.value = prefs.getBool('24hourformate') ?? false; + taskchampion.value = prefs.getBool('taskc') ?? false; initDarkMode(); baseDirectory.value = await getBaseDirectory(); super.onInit(); diff --git a/lib/app/modules/settings/views/settings_page_body.dart b/lib/app/modules/settings/views/settings_page_body.dart index c69bbe0f..207c1e64 100644 --- a/lib/app/modules/settings/views/settings_page_body.dart +++ b/lib/app/modules/settings/views/settings_page_body.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:taskwarrior/app/modules/settings/views/settings_page_taskchampion.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; @@ -23,7 +24,7 @@ import 'package:taskwarrior/app/utils/theme/app_settings.dart'; class SettingsPageBody extends StatelessWidget { final SettingsController controller; - + const SettingsPageBody({required this.controller, super.key}); @override @@ -115,6 +116,19 @@ class SettingsPageBody extends StatelessWidget { controller: controller, ), ), + SettingsPageListTile( + title: SentenceManager( + currentLanguage: controller.selectedLanguage.value) + .sentences + .taskchampionTileTitle, + subTitle: SentenceManager( + currentLanguage: controller.selectedLanguage.value) + .sentences + .taskchampionTileDescription, + trailing: SettingsPageTaskchampionTileListTileTrailing( + controller: controller, + ), + ), const Divider(), SettingsPageListTile( title: SentenceManager( diff --git a/lib/app/modules/settings/views/settings_page_taskchampion.dart b/lib/app/modules/settings/views/settings_page_taskchampion.dart new file mode 100644 index 00000000..2582cd00 --- /dev/null +++ b/lib/app/modules/settings/views/settings_page_taskchampion.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +import 'package:get/get.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart'; + +import '../controllers/settings_controller.dart'; + +class SettingsPageTaskchampionTileListTileTrailing extends StatelessWidget { + final SettingsController controller; + const SettingsPageTaskchampionTileListTileTrailing( + {required this.controller, super.key}); + + @override + Widget build(BuildContext context) { + return Obx( + () => Switch( + value: controller.taskchampion.value, + onChanged: (bool value) async { + controller.taskchampion.value = value; + + final SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setBool('taskc', value); + Get.find().taskchampion.value = value; + }, + ), + ); + } +} diff --git a/lib/app/utils/language/english_sentences.dart b/lib/app/utils/language/english_sentences.dart index e4334550..197b48df 100644 --- a/lib/app/utils/language/english_sentences.dart +++ b/lib/app/utils/language/english_sentences.dart @@ -187,4 +187,11 @@ class EnglishSentences extends Sentences { String get reportsPageNoTasksFound => 'No Tasks Found'; @override String get reportsPageAddTasksToSeeReports => 'Add Tasks To See Reports'; + + @override + String get taskchampionTileDescription => + 'Switch to TaskWarrior sync with CCSync or Taskchampion Sync Server'; + + @override + String get taskchampionTileTitle => 'Taskchampion sync'; } diff --git a/lib/app/utils/language/hindi_sentences.dart b/lib/app/utils/language/hindi_sentences.dart index d60f036a..f34c6c28 100644 --- a/lib/app/utils/language/hindi_sentences.dart +++ b/lib/app/utils/language/hindi_sentences.dart @@ -188,4 +188,11 @@ class HindiSentences extends Sentences { @override String get reportsPageAddTasksToSeeReports => 'रिपोर्ट देखने के लिए कार्य जोड़ें'; + + @override + String get taskchampionTileDescription => + 'CCSync या Taskchampion सिंक सर्वर के साथ TaskWarrior सिंक पर स्विच करें'; + + @override + String get taskchampionTileTitle => 'Taskchampion सिंक'; } diff --git a/lib/app/utils/language/marathi_sentences.dart b/lib/app/utils/language/marathi_sentences.dart index 41b9d53f..d5382917 100644 --- a/lib/app/utils/language/marathi_sentences.dart +++ b/lib/app/utils/language/marathi_sentences.dart @@ -187,4 +187,11 @@ class MarathiSentences extends Sentences { String get reportsPageNoTasksFound => 'कोणतेही काम सापडले नाहीत'; @override String get reportsPageAddTasksToSeeReports => 'अहवाल पाहण्यासाठी काम जोडा'; + + @override + String get taskchampionTileDescription => + 'CCSync किंवा Taskchampion Sync Server सह TaskWarrior सिंक वर स्विच करा'; + + @override + String get taskchampionTileTitle => 'Taskchampion सिंक'; } diff --git a/lib/app/utils/language/sentences.dart b/lib/app/utils/language/sentences.dart index ac050117..29ef47c0 100644 --- a/lib/app/utils/language/sentences.dart +++ b/lib/app/utils/language/sentences.dart @@ -33,6 +33,9 @@ abstract class Sentences { String get settingsPageEnable24hrFormatTitle; String get settingsPageEnable24hrFormatDescription; + String get taskchampionTileTitle; + String get taskchampionTileDescription; + String get settingsPageSelectLanguage; String get settingsPageToggleNativeLanguage; diff --git a/lib/app/utils/taskchampion/taskchampion.dart b/lib/app/utils/taskchampion/taskchampion.dart new file mode 100644 index 00000000..2047aff9 --- /dev/null +++ b/lib/app/utils/taskchampion/taskchampion.dart @@ -0,0 +1,182 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/theme/app_settings.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class ManageTaskChampionCreds extends StatefulWidget { + const ManageTaskChampionCreds({super.key}); + + @override + State createState() => + _ManageTaskChampionCredsState(); +} + +class _ManageTaskChampionCredsState extends State { + String encryptionSecret = ''; + String clientId = ''; + + final TextEditingController _encryptionSecretController = + TextEditingController(); + final TextEditingController _clientIdController = TextEditingController(); + + @override + void initState() { + super.initState(); + _loadCredentials(); + } + + Future _loadCredentials() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + setState(() { + encryptionSecret = prefs.getString('encryptionSecret') ?? ''; + clientId = prefs.getString('clientId') ?? ''; + _encryptionSecretController.text = encryptionSecret; + _clientIdController.text = clientId; + }); + } + + Future _saveCredentials() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString('encryptionSecret', _encryptionSecretController.text); + await prefs.setString('clientId', _clientIdController.text); + } + + @override + void dispose() { + _encryptionSecretController.dispose(); + _clientIdController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: TaskWarriorColors.kprimaryBackgroundColor, + titleSpacing: 0, + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Configure TaskChampion", + style: GoogleFonts.poppins( + color: TaskWarriorColors.white, + fontSize: TaskWarriorFonts.fontSizeLarge, + ), + ), + ], + ), + actions: [ + IconButton( + icon: Icon( + Icons.info, + color: TaskWarriorColors.white, + ), + onPressed: () async { + String url = "https://github.com/its-me-abhishek/ccsync"; + if (!await launchUrl(Uri.parse(url))) { + throw Exception('Could not launch $url'); + } + }, + ), + ], + leading: BackButton( + color: TaskWarriorColors.white, + ), + ), + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryBackgroundColor + : TaskWarriorColors.kLightPrimaryBackgroundColor, + body: Padding( + padding: const EdgeInsets.only(left: 20, right: 20), + child: ListView( + children: [ + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextField( + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + controller: _encryptionSecretController, + decoration: InputDecoration( + labelText: 'Encryption Secret', + labelStyle: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + border: const OutlineInputBorder(), + ), + ), + const SizedBox(height: 10), + TextField( + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + controller: _clientIdController, + decoration: InputDecoration( + labelText: 'Client ID', + labelStyle: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + border: const OutlineInputBorder(), + ), + ), + const SizedBox(height: 20), + ElevatedButton( + onPressed: () async { + await _saveCredentials(); + // ignore: use_build_context_synchronously + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Credentials saved successfully')), + ); + }, + child: const Text('Save Credentials'), + ), + const SizedBox(height: 10), + Text( + 'Tip: Click on the info icon in the top right corner to get your credentials', + style: TextStyle( + fontSize: 15, + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} + +class CredentialsStorage { + static const String _encryptionSecretKey = 'encryptionSecret'; + static const String _clientIdKey = 'clientId'; + + static Future getEncryptionSecret() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString(_encryptionSecretKey); + } + + static Future getClientId() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString(_clientIdKey); + } +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index b21ae466..9d87193a 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -14,6 +14,7 @@ import package_info_plus import path_provider_foundation import permission_handler_apple import shared_preferences_foundation +import sqflite import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { @@ -26,5 +27,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PermissionHandlerPlugin.register(with: registry.registrar(forPlugin: "PermissionHandlerPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index c8a884d7..14d42c7e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -640,6 +640,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.6.0" + in_app_update: + dependency: "direct main" + description: + name: in_app_update + sha256: "489572accaa55b51518b2d64676ca8c3c6d4c989fa53cf718001882237691a3c" + url: "https://pub.dev" + source: hosted + version: "4.2.3" intl: dependency: "direct main" description: @@ -1066,6 +1074,22 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + sqflite: + dependency: "direct main" + description: + name: sqflite + sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d + url: "https://pub.dev" + source: hosted + version: "2.3.3+1" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4" + url: "https://pub.dev" + source: hosted + version: "2.5.4" stack_trace: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c0e89b43..86c46f43 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -51,6 +51,7 @@ dependencies: shared_preferences: ^2.2.2 shared_preferences_web: ^2.0.3 sizer: ^2.0.15 + sqflite: ^2.3.3+1 syncfusion_flutter_charts: ^23.2.7 timezone: ^0.9.2 tuple: ^2.0.0 From 121596a41ce92aff2fd4927ed00ddc2959186922 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 06:46:53 +0530 Subject: [PATCH 02/47] feat: add ccsync credentials to drawer --- lib/app/modules/home/views/nav_drawer.dart | 45 ++++++++++++++----- lib/app/utils/language/english_sentences.dart | 4 +- lib/app/utils/language/hindi_sentences.dart | 3 ++ lib/app/utils/language/marathi_sentences.dart | 3 ++ lib/app/utils/language/sentences.dart | 1 + 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/lib/app/modules/home/views/nav_drawer.dart b/lib/app/modules/home/views/nav_drawer.dart index cb9f4c62..35191bf5 100644 --- a/lib/app/modules/home/views/nav_drawer.dart +++ b/lib/app/modules/home/views/nav_drawer.dart @@ -10,6 +10,7 @@ import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; import 'package:taskwarrior/app/utils/constants/utilites.dart'; import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; +import 'package:taskwarrior/app/utils/taskchampion/taskchampion.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; class NavDrawer extends StatelessWidget { @@ -41,9 +42,11 @@ class NavDrawer extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - SentenceManager(currentLanguage: homeController.selectedLanguage.value) - .sentences - .homePageMenu, + SentenceManager( + currentLanguage: + homeController.selectedLanguage.value) + .sentences + .homePageMenu, style: TextStyle( fontSize: TaskWarriorFonts.fontSizeExtraLarge, fontWeight: TaskWarriorFonts.bold, @@ -115,6 +118,22 @@ class NavDrawer extends StatelessWidget { }, ), ), + Visibility( + visible: homeController.taskchampion.value, + child: NavDrawerMenuItem( + icon: Icons.task_alt, + text: SentenceManager( + currentLanguage: homeController.selectedLanguage.value, + ).sentences.ccsyncCredentials, + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const ManageTaskChampionCreds(), + ), + ); + }, + ), + ), Obx( () => NavDrawerMenuItem( icon: Icons.settings, @@ -162,7 +181,8 @@ class NavDrawer extends StatelessWidget { builder: (BuildContext context) { return Utils.showAlertDialog( title: Text( - SentenceManager(currentLanguage: homeController.selectedLanguage.value) + SentenceManager( + currentLanguage: homeController.selectedLanguage.value) .sentences .homePageExitApp, style: TextStyle( @@ -172,7 +192,8 @@ class NavDrawer extends StatelessWidget { ), ), content: Text( - SentenceManager(currentLanguage: homeController.selectedLanguage.value) + SentenceManager( + currentLanguage: homeController.selectedLanguage.value) .sentences .homePageAreYouSureYouWantToExit, style: TextStyle( @@ -184,9 +205,10 @@ class NavDrawer extends StatelessWidget { actions: [ TextButton( child: Text( - SentenceManager(currentLanguage: homeController.selectedLanguage.value) - .sentences - .homePageCancel, + SentenceManager( + currentLanguage: homeController.selectedLanguage.value) + .sentences + .homePageCancel, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -199,9 +221,10 @@ class NavDrawer extends StatelessWidget { ), TextButton( child: Text( - SentenceManager(currentLanguage: homeController.selectedLanguage.value) - .sentences - .homePageExit, + SentenceManager( + currentLanguage: homeController.selectedLanguage.value) + .sentences + .homePageExit, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white diff --git a/lib/app/utils/language/english_sentences.dart b/lib/app/utils/language/english_sentences.dart index 197b48df..866e7e4d 100644 --- a/lib/app/utils/language/english_sentences.dart +++ b/lib/app/utils/language/english_sentences.dart @@ -191,7 +191,9 @@ class EnglishSentences extends Sentences { @override String get taskchampionTileDescription => 'Switch to TaskWarrior sync with CCSync or Taskchampion Sync Server'; - @override String get taskchampionTileTitle => 'Taskchampion sync'; + + @override + String get ccsyncCredentials => 'CCync credentials'; } diff --git a/lib/app/utils/language/hindi_sentences.dart b/lib/app/utils/language/hindi_sentences.dart index f34c6c28..87ce9d39 100644 --- a/lib/app/utils/language/hindi_sentences.dart +++ b/lib/app/utils/language/hindi_sentences.dart @@ -195,4 +195,7 @@ class HindiSentences extends Sentences { @override String get taskchampionTileTitle => 'Taskchampion सिंक'; + + @override + String get ccsyncCredentials => 'CCync क्रेडेन्शियल'; } diff --git a/lib/app/utils/language/marathi_sentences.dart b/lib/app/utils/language/marathi_sentences.dart index d5382917..7111029e 100644 --- a/lib/app/utils/language/marathi_sentences.dart +++ b/lib/app/utils/language/marathi_sentences.dart @@ -194,4 +194,7 @@ class MarathiSentences extends Sentences { @override String get taskchampionTileTitle => 'Taskchampion सिंक'; + + @override + String get ccsyncCredentials => 'CCync क्रेडेन्शियल'; } diff --git a/lib/app/utils/language/sentences.dart b/lib/app/utils/language/sentences.dart index 29ef47c0..2ad3b3f0 100644 --- a/lib/app/utils/language/sentences.dart +++ b/lib/app/utils/language/sentences.dart @@ -46,6 +46,7 @@ abstract class Sentences { String get navDrawerReports; String get navDrawerAbout; String get navDrawerSettings; + String get ccsyncCredentials; String get navDrawerExit; String get detailPageDescription; From 3aa305fd38d97f04709a797e28beaa3a60f1e74f Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 07:37:59 +0530 Subject: [PATCH 03/47] feat: add task views for taskc --- .../modules/home/views/home_page_app_bar.dart | 136 ++++++-- .../modules/home/views/home_page_body.dart | 39 ++- lib/app/modules/home/views/show_details.dart | 320 +++++++++++++++++ lib/app/modules/home/views/show_tasks.dart | 327 ++++++++++++++++++ 4 files changed, 789 insertions(+), 33 deletions(-) create mode 100644 lib/app/modules/home/views/show_details.dart create mode 100644 lib/app/modules/home/views/show_tasks.dart diff --git a/lib/app/modules/home/views/home_page_app_bar.dart b/lib/app/modules/home/views/home_page_app_bar.dart index b739aa8f..460087e7 100644 --- a/lib/app/modules/home/views/home_page_app_bar.dart +++ b/lib/app/modules/home/views/home_page_app_bar.dart @@ -1,11 +1,14 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:taskwarrior/api_service.dart'; +import 'package:taskwarrior/app/modules/home/views/home_view.dart'; import 'package:taskwarrior/app/routes/app_pages.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/gen/fonts.gen.dart'; import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; +import 'package:taskwarrior/app/utils/taskchampion/taskchampion.dart'; import 'package:taskwarrior/app/utils/taskserver/taskserver.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; @@ -55,14 +58,69 @@ class HomePageAppBar extends StatelessWidget implements PreferredSizeWidget { builder: (context) => IconButton( key: controller.refreshKey, icon: Icon(Icons.refresh, color: TaskWarriorColors.white), - onPressed: () { - if (server != null || credentials != null) { - controller.synchronize(context, true); - } else { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Obx( - () => Text( + onPressed: () async { + if (controller.taskchampion.value) { + var c = await CredentialsStorage.getClientId(); + var e = await CredentialsStorage.getEncryptionSecret(); + if (c != null && e != null) { + try { + List tasks = await fetchTasks(c, e); + print(tasks.toList()); + await updateTasksInDatabase(tasks); + print('Tasks updated successfully'); + Navigator.pushReplacement( + context, + PageRouteBuilder( + pageBuilder: (context, animation1, animation2) => + const HomeView(), + transitionDuration: Duration.zero, + reverseTransitionDuration: Duration.zero, + )); + } catch (e) { + print('Failed to update tasks: $e'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.ksecondaryBackgroundColor + : TaskWarriorColors.kLightSecondaryBackgroundColor, + content: Text( + SentenceManager( + currentLanguage: + controller.selectedLanguage.value) + .sentences + .homePageTaskWarriorNotConfigured, + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + action: SnackBarAction( + label: SentenceManager( + currentLanguage: + controller.selectedLanguage.value) + .sentences + .homePageSetup, + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => + const ManageTaskChampionCreds(), + )).then((value) {}); + }, + textColor: TaskWarriorColors.purple, + ), + ), + ); + } + } else if (c == null || e == null) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.ksecondaryBackgroundColor + : TaskWarriorColors.kLightSecondaryBackgroundColor, + content: Text( SentenceManager( currentLanguage: controller.selectedLanguage.value) @@ -74,20 +132,58 @@ class HomePageAppBar extends StatelessWidget implements PreferredSizeWidget { : TaskWarriorColors.black, ), ), + action: SnackBarAction( + label: SentenceManager( + currentLanguage: + controller.selectedLanguage.value) + .sentences + .homePageSetup, + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => const ManageTaskChampionCreds(), + )).then((value) {}); + }, + textColor: TaskWarriorColors.purple, + ), ), - action: SnackBarAction( - label: SentenceManager( - currentLanguage: - controller.selectedLanguage.value) - .sentences - .homePageSetup, - onPressed: () { - Get.toNamed(Routes.MANAGE_TASK_SERVER); - }, - textColor: TaskWarriorColors.purple, + ); + } + } else { + if (server != null || credentials != null) { + controller.synchronize(context, true); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Obx( + () => Text( + SentenceManager( + currentLanguage: + controller.selectedLanguage.value) + .sentences + .homePageTaskWarriorNotConfigured, + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + ), + action: SnackBarAction( + label: SentenceManager( + currentLanguage: + controller.selectedLanguage.value) + .sentences + .homePageSetup, + onPressed: () { + Get.toNamed(Routes.MANAGE_TASK_SERVER); + }, + textColor: TaskWarriorColors.purple, + ), ), - ), - ); + ); + } } }, ), diff --git a/lib/app/modules/home/views/home_page_body.dart b/lib/app/modules/home/views/home_page_body.dart index 404cf341..7341270c 100644 --- a/lib/app/modules/home/views/home_page_body.dart +++ b/lib/app/modules/home/views/home_page_body.dart @@ -2,6 +2,7 @@ import 'package:double_back_to_close_app/double_back_to_close_app.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:taskwarrior/app/modules/home/views/show_tasks.dart'; import 'package:taskwarrior/app/modules/home/views/tasks_builder.dart'; import 'package:taskwarrior/app/utils/constants/palette.dart'; @@ -88,23 +89,35 @@ class HomePageBody extends StatelessWidget { hintText: 'Search', ), ), - Expanded( - child: Scrollbar( - child: Obx( - () => TasksBuilder( - // darkmode: AppSettings.isDarkMode, - useDelayTask: controller.useDelayTask.value, - taskData: controller.searchedTasks, - pendingFilter: controller.pendingFilter.value, - waitingFilter: controller.waitingFilter.value, - searchVisible: controller.searchVisible.value, - selectedLanguage: controller.selectedLanguage.value, - scrollController: controller.scrollController, - showbtn: controller.showbtn.value, + Visibility( + visible: !controller.taskchampion.value, + child: Expanded( + child: Scrollbar( + child: Obx( + () => TasksBuilder( + // darkmode: AppSettings.isDarkMode, + useDelayTask: controller.useDelayTask.value, + taskData: controller.searchedTasks, + pendingFilter: controller.pendingFilter.value, + waitingFilter: controller.waitingFilter.value, + searchVisible: controller.searchVisible.value, + selectedLanguage: controller.selectedLanguage.value, + scrollController: controller.scrollController, + showbtn: controller.showbtn.value, + ), ), ), ), ), + Visibility( + visible: controller.taskchampion.value, + child: Expanded( + child: Scrollbar( + child: TaskViewBuilder( + pendingFilter: controller.pendingFilter.value, + selectedSort: controller.selectedSort.value, + ), + ))) ], ), ), diff --git a/lib/app/modules/home/views/show_details.dart b/lib/app/modules/home/views/show_details.dart new file mode 100644 index 00000000..55688375 --- /dev/null +++ b/lib/app/modules/home/views/show_details.dart @@ -0,0 +1,320 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:intl/intl.dart'; +import 'package:taskwarrior/api_service.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; +import 'package:taskwarrior/app/utils/constants/utilites.dart'; +import 'package:taskwarrior/app/utils/theme/app_settings.dart'; + +class TaskDetails extends StatelessWidget { + final Tasks task; + const TaskDetails({super.key, required this.task}); + + @override + Widget build(BuildContext context) { + String description = task.description; + String project = task.project ?? ''; + String status = task.status; + String priority = task.priority ?? ''; + String due = task.due ?? '-'; + due = _buildDate(due); + bool hasChanges = false; + + return Scaffold( + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryBackgroundColor + : TaskWarriorColors.kLightPrimaryBackgroundColor, + appBar: AppBar( + foregroundColor: TaskWarriorColors.lightGrey, + backgroundColor: TaskWarriorColors.kprimaryBackgroundColor, + title: Text( + 'Task: ${task.description}', + style: GoogleFonts.poppins(color: TaskWarriorColors.white), + ), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: ListView( + children: [ + _buildEditableDetail(context, 'Description:', description, (value) { + description = value; + hasChanges = true; + }), + _buildEditableDetail(context, 'Project:', project, (value) { + project = value; + hasChanges = true; + }), + _buildSelectableDetail( + context, 'Status:', status, ['pending', 'completed'], (value) { + status = value; + hasChanges = true; + }), + _buildSelectableDetail( + context, 'Priority:', priority, ['H', 'M', 'L'], (value) { + priority = value; + hasChanges = true; + }), + _buildDatePickerDetail(context, 'Due:', due, (value) { + due = value; + hasChanges = true; + }), + _buildDetail('UUID:', task.uuid!), + _buildDetail('Urgency:', task.urgency.toString()), + _buildDetail('End:', _buildDate(task.end)), + _buildDetail('Entry:', _buildDate(task.entry)), + _buildDetail('Modified:', _buildDate(task.modified)), + ], + ), + ), + floatingActionButton: hasChanges + ? FloatingActionButton( + onPressed: () async { + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + await taskDatabase.saveEditedTaskInDB( + task.uuid!, description, project, status, priority, due); + hasChanges = false; + modifyTaskOnTaskwarrior( + description, project, due, priority, status, task.uuid!); + }, + child: const Icon(Icons.save), + ) + : null, + ); + } + + Widget _buildEditableDetail(BuildContext context, String label, String value, + Function(String) onChanged) { + return InkWell( + onTap: () async { + final result = await _showEditDialog(context, label, value); + if (result != null) { + onChanged(result); + } + }, + child: _buildDetail(label, value), + ); + } + + Widget _buildSelectableDetail(BuildContext context, String label, + String value, List options, Function(String) onChanged) { + return InkWell( + onTap: () async { + final result = await _showSelectDialog(context, label, value, options); + if (result != null) { + onChanged(result); + } + }, + child: _buildDetail(label, value), + ); + } + + Widget _buildDatePickerDetail(BuildContext context, String label, + String value, Function(String) onChanged) { + return InkWell( + onTap: () async { + final DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: value != '-' ? DateTime.parse(value) : DateTime.now(), + firstDate: DateTime(2000), + lastDate: DateTime(2101), + builder: (BuildContext context, Widget? child) { + return Theme( + data: Theme.of(context).copyWith( + colorScheme: AppSettings.isDarkMode + ? ColorScheme.dark( + primary: TaskWarriorColors.white, + onPrimary: TaskWarriorColors.black, + onSurface: TaskWarriorColors.white, + ) + : ColorScheme.light( + primary: TaskWarriorColors.black, + onPrimary: TaskWarriorColors.white, + onSurface: TaskWarriorColors.black, + ), + ), + child: child!, + ); + }, + ); + if (pickedDate != null) { + final TimeOfDay? pickedTime = await showTimePicker( + context: context, + initialTime: TimeOfDay.fromDateTime( + value != '-' ? DateTime.parse(value) : DateTime.now()), + ); + if (pickedTime != null) { + final DateTime fullDateTime = DateTime( + pickedDate.year, + pickedDate.month, + pickedDate.day, + pickedTime.hour, + pickedTime.minute); + onChanged(DateFormat('yyyy-MM-dd HH:mm:ss').format(fullDateTime)); + } + } + }, + child: _buildDetail(label, value), + ); + } + + Widget _buildDetail(String label, String value) { + return Container( + width: double.infinity, + decoration: BoxDecoration( + color: AppSettings.isDarkMode + ? TaskWarriorColors.ksecondaryBackgroundColor + : TaskWarriorColors.kLightSecondaryBackgroundColor, + borderRadius: BorderRadius.circular(8.0), + boxShadow: const [ + BoxShadow( + color: Colors.black12, + blurRadius: 4.0, + offset: Offset(0, 2), + ), + ], + ), + padding: const EdgeInsets.all(16.0), + margin: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + label, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18, + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightSecondaryTextColor, + ), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + value, + style: TextStyle( + fontSize: 18, + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightSecondaryTextColor, + ), + ), + ), + ], + ), + ); + } + + Future _showEditDialog( + BuildContext context, String label, String initialValue) async { + final TextEditingController controller = + TextEditingController(text: initialValue); + return await showDialog( + context: context, + builder: (context) { + return Utils.showAlertDialog( + title: Text( + 'Edit $label', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor), + ), + content: TextField( + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor), + controller: controller, + decoration: InputDecoration( + hintText: 'Enter new $label', + hintStyle: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor), + ), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text( + 'Cancel', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor), + ), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(controller.text); + }, + child: Text( + 'Save', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor), + ), + ), + ], + ); + }, + ); + } + + Future _showSelectDialog(BuildContext context, String label, + String initialValue, List options) async { + return await showDialog( + context: context, + builder: (context) { + return Utils.showAlertDialog( + title: Text( + 'Select $label', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor), + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: options.map((option) { + return RadioListTile( + title: Text( + option, + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor), + ), + value: option, + groupValue: initialValue, + onChanged: (value) { + Navigator.of(context).pop(value); + }, + ); + }).toList(), + ), + ); + }, + ); + } + + String _buildDate(String? dateString) { + if (dateString == null || dateString.isEmpty || dateString == '-') { + return '-'; + } + + try { + DateTime parsedDate = DateTime.parse(dateString); + return DateFormat('yyyy-MM-dd HH:mm:ss').format(parsedDate); + } catch (e) { + debugPrint('Error parsing date: $dateString'); + return '-'; + } + } +} diff --git a/lib/app/modules/home/views/show_tasks.dart b/lib/app/modules/home/views/show_tasks.dart new file mode 100644 index 00000000..2cbd4448 --- /dev/null +++ b/lib/app/modules/home/views/show_tasks.dart @@ -0,0 +1,327 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:taskwarrior/api_service.dart'; +import 'package:taskwarrior/app/modules/home/views/show_details.dart'; +import 'package:taskwarrior/app/utils/constants/palette.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/taskchampion/taskchampion.dart'; +import 'package:taskwarrior/app/utils/theme/app_settings.dart'; + +class TaskViewBuilder extends StatelessWidget { + const TaskViewBuilder({ + super.key, + this.project, + required this.pendingFilter, + required this.selectedSort, + }); + + final String selectedSort; + final bool pendingFilter; + final String? project; + + Future _loadCredentials( + Function(TaskDatabase, String, String) callback) async { + String uuid = (await CredentialsStorage.getClientId()) ?? ''; + String encryptionSecret = + (await CredentialsStorage.getEncryptionSecret()) ?? ''; + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + callback(taskDatabase, uuid, encryptionSecret); + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: _loadCredentials((taskDatabase, uuid, encryptionSecret) {}), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); + } else { + return FutureBuilder( + future: _fetchTasks(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); + } else if (!snapshot.hasData || snapshot.data!.isEmpty) { + return const Center(child: Text('No tasks available')); + } else { + // Sorting tasks by ID in ascending order + List tasks = List.from(snapshot.data!); + tasks.sort((a, b) => b.id.compareTo(a.id)); + + _updateTasksInDatabase(tasks); + _findTasksWithoutUUIDs(); + + tasks = tasks.where((task) { + if (pendingFilter) { + return task.status == 'pending'; + } else { + return task.status == 'completed'; + } + }).toList(); + + // Apply sorting based on selectedSort + tasks.sort((a, b) { + switch (selectedSort) { + case 'Created+': + return a.entry.compareTo(b.entry); + case 'Created-': + return b.entry.compareTo(a.entry); + case 'Modified+': + return a.modified!.compareTo(b.modified!); + case 'Modified-': + return b.modified!.compareTo(a.modified!); + case 'Due till+': + return a.due!.compareTo(b.due!); + case 'Due till-': + return b.due!.compareTo(a.due!); + case 'Priority-': + return b.priority!.compareTo(a.priority!); + case 'Priority+': + return a.priority!.compareTo(b.priority!); + case 'Project+': + return a.project!.compareTo(b.project!); + case 'Project-': + return b.project!.compareTo(a.project!); + case 'Urgency-': + return b.urgency!.compareTo(a.urgency!); + case 'Urgency+': + return a.urgency!.compareTo(b.urgency!); + default: + return 0; + } + }); + + // Filter tasks based on the pendingFilter + tasks = tasks.where((task) { + if (pendingFilter) { + return task.status == 'pending'; + } else { + return task.status == 'completed'; + } + }).toList(); + + return Scaffold( + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryBackgroundColor + : TaskWarriorColors.kLightPrimaryBackgroundColor, + body: tasks.isEmpty + ? Padding( + padding: const EdgeInsets.all(16.0), + child: Center( + child: Text( + 'Click on the bottom right button to start adding tasks', + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + fontSize: TaskWarriorFonts.fontSizeLarge, + color: AppSettings.isDarkMode + ? TaskWarriorColors + .kLightPrimaryBackgroundColor + : TaskWarriorColors.kprimaryBackgroundColor, + ), + ), + ), + ) + : ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.only( + top: 4, + left: 2, + right: 2, + bottom: MediaQuery.of(context).size.height * 0.1, + ), + itemCount: tasks.length, + itemBuilder: (context, index) { + Tasks task = tasks[index]; + return Slidable( + startActionPane: ActionPane( + motion: const BehindMotion(), + children: [ + SlidableAction( + onPressed: (context) { + _markTaskAsCompleted(task.uuid!); + ScaffoldMessenger.of(context) + .showSnackBar( + SnackBar( + content: Text( + 'Task Marked As Completed. Refresh to view changes!', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors + .kprimaryTextColor + : TaskWarriorColors + .kLightPrimaryTextColor, + ), + ), + ), + ); + }, + icon: Icons.done, + label: "COMPLETE", + backgroundColor: TaskWarriorColors.green, + ), + ], + ), + endActionPane: ActionPane( + motion: const DrawerMotion(), + children: [ + SlidableAction( + onPressed: (context) { + _markTaskAsDeleted(task.uuid!); + ScaffoldMessenger.of(context) + .showSnackBar( + SnackBar( + content: Text( + 'Task Marked As Deleted. Refresh to view changes!', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors + .kprimaryTextColor + : TaskWarriorColors + .kLightPrimaryTextColor, + ), + ), + ), + ); + }, + icon: Icons.delete, + label: "DELETE", + backgroundColor: TaskWarriorColors.red, + ), + ], + ), + child: Card( + color: AppSettings.isDarkMode + ? Palette.kToDark + : TaskWarriorColors.white, + child: InkWell( + splashColor: AppSettings.isDarkMode + ? TaskWarriorColors.black + : TaskWarriorColors.borderColor, + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + TaskDetails(task: task), + ), + ), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: AppSettings.isDarkMode + ? TaskWarriorColors.borderColor + : TaskWarriorColors.black, + ), + color: AppSettings.isDarkMode + ? Palette.kToDark + : TaskWarriorColors.white, + borderRadius: BorderRadius.circular(8.0), + boxShadow: const [ + BoxShadow( + color: Colors.black12, + blurRadius: 4.0, + offset: Offset(0, 2), + ), + ], + ), + child: ListTile( + leading: CircleAvatar( + backgroundColor: + _getPriorityColor(task.priority!), + radius: 8, + ), + title: Text( + task.description, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: GoogleFonts.poppins( + color: AppSettings.isDarkMode + ? TaskWarriorColors + .kLightDialogBackGroundColor + : TaskWarriorColors + .kprimaryBackgroundColor, + ), + ), + subtitle: Text( + 'Urgency: ${task.urgency!.floorToDouble()} | Status: ${task.status}', + style: GoogleFonts.poppins( + color: AppSettings.isDarkMode + ? TaskWarriorColors + .ksecondaryTextColor + : TaskWarriorColors + .kLightSecondaryTextColor, + ), + ), + ), + ), + ), + ), + ); + }, + ), + ); + } + }, + ); + } + }, + ); + } + + Future _fetchTasks() async { + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + return await taskDatabase.fetchTasksFromDatabase(); + } + + void _updateTasksInDatabase(List tasks) async { + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + // Perform update logic + } + + void _findTasksWithoutUUIDs() async { + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + // Perform find logic + } + + void _markTaskAsCompleted(String uuid) async { + String clientId = (await CredentialsStorage.getClientId()) ?? ''; + String encryptionSecret = + (await CredentialsStorage.getEncryptionSecret()) ?? ''; + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + taskDatabase.markTaskAsCompleted(uuid); + completeTask('email', encryptionSecret, clientId, uuid); + } + + void _markTaskAsDeleted(String uuid) async { + String clientId = (await CredentialsStorage.getClientId()) ?? ''; + String encryptionSecret = + (await CredentialsStorage.getEncryptionSecret()) ?? ''; + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + taskDatabase.markTaskAsDeleted(uuid); + deleteTask('email', encryptionSecret, clientId, uuid); + } + + Color _getPriorityColor(String priority) { + switch (priority) { + case 'H': + return Colors.red; + case 'M': + return Colors.yellow; + case 'L': + return Colors.green; + default: + return Colors.grey; + } + } +} From 5d59d038268d395f74a0da4af7da17936c082a30 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 08:29:15 +0530 Subject: [PATCH 04/47] feat: add task --- .../home/controllers/home_controller.dart | 7 +- .../views/add_task_to_taskc_bottom_sheet.dart | 417 ++++++++++++++++++ .../home_page_floating_action_button.dart | 32 +- lib/app/modules/home/views/home_view.dart | 4 +- 4 files changed, 447 insertions(+), 13 deletions(-) create mode 100644 lib/app/modules/home/views/add_task_to_taskc_bottom_sheet.dart diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 701a9bf2..248abe68 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -66,6 +66,12 @@ class HomeController extends GetxController { if (Platform.isAndroid) { handleHomeWidgetClicked(); } + _loadTaskChampion(); + } + + Future _loadTaskChampion() async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + taskchampion.value = prefs.getBool('taskchampion') ?? false; } void addListenerToScrollController() { @@ -438,7 +444,6 @@ class HomeController extends GetxController { RxBool taskchampion = false.obs; // dialogue box - final formKey = GlobalKey(); final namecontroller = TextEditingController(); var due = Rxn(); diff --git a/lib/app/modules/home/views/add_task_to_taskc_bottom_sheet.dart b/lib/app/modules/home/views/add_task_to_taskc_bottom_sheet.dart new file mode 100644 index 00000000..30d6a9c8 --- /dev/null +++ b/lib/app/modules/home/views/add_task_to_taskc_bottom_sheet.dart @@ -0,0 +1,417 @@ +// ignore_for_file: use_build_context_synchronously, file_names +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:intl/intl.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:taskwarrior/api_service.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/theme/app_settings.dart'; + +class AddTaskToTaskcBottomSheet extends StatefulWidget { + const AddTaskToTaskcBottomSheet({super.key}); + + @override + State createState() => + _AddTaskToTaskcBottomSheetState(); +} + +class _AddTaskToTaskcBottomSheetState extends State { + final formKey = GlobalKey(); + final namecontroller = TextEditingController(); + DateTime? due; + String dueString = ''; + String priority = 'M'; + final projectController = TextEditingController(); + String project = ''; + bool inThePast = false; + bool change24hr = false; + late TaskDatabase taskdb; + + Future checkto24hr() async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + setState(() { + change24hr = prefs.getBool('24hourformate') ?? false; + }); + } + + @override + void initState() { + super.initState(); + checkto24hr(); + taskdb = TaskDatabase(); + taskdb.open(); + } + + @override + void dispose() { + projectController.dispose(); + namecontroller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + const title = 'Add Task'; + return Scaffold( + backgroundColor: Colors.transparent, + body: Center( + child: SingleChildScrollView( + child: AlertDialog( + surfaceTintColor: AppSettings.isDarkMode + ? TaskWarriorColors.kdialogBackGroundColor + : TaskWarriorColors.kLightDialogBackGroundColor, + shadowColor: AppSettings.isDarkMode + ? TaskWarriorColors.kdialogBackGroundColor + : TaskWarriorColors.kLightDialogBackGroundColor, + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.kdialogBackGroundColor + : TaskWarriorColors.kLightDialogBackGroundColor, + title: Center( + child: Text( + title, + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + ), + content: Form( + key: formKey, + child: SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 8), + buildName(), + const SizedBox(height: 8), + buildProject(), + const SizedBox(height: 12), + buildDueDate(context), + const SizedBox(height: 8), + buildPriority(), + ], + ), + ), + ), + actions: [ + buildCancelButton(context), + buildAddButton(context), + ], + ), + ), + ), + ); + } + + Widget buildName() => TextFormField( + autofocus: true, + controller: namecontroller, + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + decoration: InputDecoration( + hintText: 'Enter Task', + hintStyle: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + validator: (name) => name != null && name.isEmpty + ? 'You cannot leave this field empty!' + : null, + ); + + Widget buildProject() => TextFormField( + autofocus: true, + controller: projectController, + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + decoration: InputDecoration( + hintText: 'Enter Project', + hintStyle: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + ); + + Widget buildDueDate(BuildContext context) => Row( + children: [ + Text( + "Due : ", + style: GoogleFonts.poppins( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + fontWeight: TaskWarriorFonts.bold, + height: 3.3, + ), + ), + Expanded( + child: GestureDetector( + child: TextFormField( + style: inThePast + ? TextStyle(color: TaskWarriorColors.red) + : TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + readOnly: true, + controller: TextEditingController( + text: (due != null) ? dueString : null, + ), + decoration: InputDecoration( + hintText: 'Select due date', + hintStyle: inThePast + ? TextStyle(color: TaskWarriorColors.red) + : TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + onTap: () async { + var date = await showDatePicker( + builder: (BuildContext context, Widget? child) { + return Theme( + data: Theme.of(context).copyWith( + colorScheme: AppSettings.isDarkMode + ? ColorScheme( + brightness: Brightness.dark, + primary: TaskWarriorColors.white, + onPrimary: TaskWarriorColors.black, + secondary: TaskWarriorColors.black, + onSecondary: TaskWarriorColors.white, + error: TaskWarriorColors.red, + onError: TaskWarriorColors.black, + surface: TaskWarriorColors.black, + onSurface: TaskWarriorColors.white, + ) + : ColorScheme( + brightness: Brightness.light, + primary: TaskWarriorColors.black, + onPrimary: TaskWarriorColors.white, + secondary: TaskWarriorColors.white, + onSecondary: TaskWarriorColors.black, + error: TaskWarriorColors.red, + onError: TaskWarriorColors.white, + surface: TaskWarriorColors.white, + onSurface: TaskWarriorColors.black, + ), + ), + child: child!, + ); + }, + fieldHintText: "Month/Date/Year", + context: context, + initialDate: due ?? DateTime.now(), + firstDate: DateTime.now(), + lastDate: DateTime(2037, 12, 31), + ); + if (date != null) { + var time = await showTimePicker( + builder: (BuildContext context, Widget? child) { + return Theme( + data: Theme.of(context).copyWith( + textTheme: const TextTheme(), + colorScheme: AppSettings.isDarkMode + ? ColorScheme( + brightness: Brightness.dark, + primary: TaskWarriorColors.white, + onPrimary: TaskWarriorColors.black, + secondary: TaskWarriorColors.black, + onSecondary: TaskWarriorColors.white, + error: TaskWarriorColors.red, + onError: TaskWarriorColors.black, + surface: TaskWarriorColors.black, + onSurface: TaskWarriorColors.white, + ) + : ColorScheme( + brightness: Brightness.light, + primary: TaskWarriorColors.black, + onPrimary: TaskWarriorColors.white, + secondary: TaskWarriorColors.white, + onSecondary: TaskWarriorColors.black, + error: TaskWarriorColors.red, + onError: TaskWarriorColors.white, + surface: TaskWarriorColors.white, + onSurface: TaskWarriorColors.black, + ), + ), + child: MediaQuery( + data: MediaQuery.of(context).copyWith( + alwaysUse24HourFormat: change24hr, + ), + child: child!), + ); + }, + context: context, + initialTime: + TimeOfDay.fromDateTime(due ?? DateTime.now()), + ); + if (time != null) { + var dateTime = date.add( + Duration( + hours: time.hour, + minutes: time.minute, + ), + ); + due = dateTime.toUtc(); + dueString = DateFormat("yyyy-MM-dd").format(dateTime); + if (dateTime.isBefore(DateTime.now())) { + setState(() { + inThePast = true; + }); + + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + "The selected time is in the past.", + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor, + ), + ), + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.ksecondaryBackgroundColor + : TaskWarriorColors + .kLightSecondaryBackgroundColor, + duration: const Duration(seconds: 2))); + } else { + setState(() { + inThePast = false; + }); + } + } + } + }, + ), + ), + ), + ], + ); + + Widget buildPriority() => Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + 'Priority : ', + style: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + textAlign: TextAlign.left, + ), + DropdownButton( + dropdownColor: AppSettings.isDarkMode + ? TaskWarriorColors.kdialogBackGroundColor + : TaskWarriorColors.kLightDialogBackGroundColor, + value: priority, + elevation: 16, + style: GoogleFonts.poppins( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + underline: Container( + height: 1.5, + color: AppSettings.isDarkMode + ? TaskWarriorColors.kdialogBackGroundColor + : TaskWarriorColors.kLightDialogBackGroundColor, + ), + onChanged: (String? newValue) { + setState(() { + priority = newValue!; + }); + }, + items: ['H', 'M', 'L', 'None'] + .map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(' $value'), + ); + }).toList(), + ) + ], + ), + ], + ); + + Widget buildCancelButton(BuildContext context) => TextButton( + child: Text( + 'Cancel', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + onPressed: () => Navigator.of(context).pop("cancel"), + ); + + Widget buildAddButton(BuildContext context) { + return TextButton( + child: Text( + "Add", + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + onPressed: () async { + if (formKey.currentState!.validate()) { + var task = Tasks( + description: namecontroller.text, + status: 'pending', + priority: priority, + entry: DateTime.now().toIso8601String(), + id: 0, + project: projectController.text, + uuid: '', + urgency: 0, + due: dueString, + // dueString.toIso8601String(), + end: '', + modified: 'r'); + await taskdb.insertTask(task); + namecontroller.text = ''; + due = null; + priority = 'M'; + project = ''; + setState(() {}); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + 'Task Added Successfully!', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor, + ), + ), + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.ksecondaryBackgroundColor + : TaskWarriorColors.kLightSecondaryBackgroundColor, + duration: const Duration(seconds: 2))); + Navigator.of(context).pop(); + } + }, + ); + } +} diff --git a/lib/app/modules/home/views/home_page_floating_action_button.dart b/lib/app/modules/home/views/home_page_floating_action_button.dart index 2ddf18c7..961b13b7 100644 --- a/lib/app/modules/home/views/home_page_floating_action_button.dart +++ b/lib/app/modules/home/views/home_page_floating_action_button.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:taskwarrior/app/modules/home/views/add_task_bottom_sheet.dart'; +import 'package:taskwarrior/app/modules/home/views/add_task_to_taskc_bottom_sheet.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; @@ -9,7 +10,7 @@ import '../controllers/home_controller.dart'; class HomePageFloatingActionButton extends StatelessWidget { final HomeController controller; - const HomePageFloatingActionButton({required this.controller,super.key}); + const HomePageFloatingActionButton({required this.controller, super.key}); @override Widget build(BuildContext context) { @@ -28,16 +29,25 @@ class HomePageFloatingActionButton extends StatelessWidget { : TaskWarriorColors.white, ), ), - onPressed: () => showDialog( - context: context, - builder: (context) => AddTaskBottomSheet( - homeController: controller, - ), - ).then((value) { - if (controller.isSyncNeeded.value && value != "cancel") { - controller.isNeededtoSyncOnStart(context); - } - }) + onPressed: () => (controller.taskchampion.value) + ? (showDialog( + context: context, + builder: (context) => const AddTaskToTaskcBottomSheet(), + ).then((value) { + if (controller.isSyncNeeded.value && value != "cancel") { + controller.isNeededtoSyncOnStart(context); + } + })) + : (showDialog( + context: context, + builder: (context) => AddTaskBottomSheet( + homeController: controller, + ), + ).then((value) { + if (controller.isSyncNeeded.value && value != "cancel") { + controller.isNeededtoSyncOnStart(context); + } + })) // .then((value) { // // print(value); diff --git a/lib/app/modules/home/views/home_view.dart b/lib/app/modules/home/views/home_view.dart index 744a13c5..81dcc95a 100644 --- a/lib/app/modules/home/views/home_view.dart +++ b/lib/app/modules/home/views/home_view.dart @@ -50,7 +50,9 @@ class HomeView extends GetView { ? TaskWarriorColors.kprimaryBackgroundColor : TaskWarriorColors.kLightPrimaryBackgroundColor, drawer: NavDrawer(homeController: controller), - body: HomePageBody(controller: controller), + body: HomePageBody( + controller: controller, + ), endDrawer: Obx( () => FilterDrawer( filters: controller.getFilters(), From 1fd1c7a3628ce1b5a8bc32395b96502588e946d8 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 08:42:58 +0530 Subject: [PATCH 05/47] feat: add reports and fix the broken reports tour --- lib/app/modules/home/views/nav_drawer.dart | 45 ++-- .../controllers/reports_tour_controller.dart | 20 ++ .../reports/views/burn_down_daily_taskc.dart | 177 +++++++++++++++ .../views/burn_down_monthly_taskc.dart | 184 +++++++++++++++ .../reports/views/burn_down_weekly_taskc.dart | 195 ++++++++++++++++ .../modules/reports/views/reports_tour.dart | 112 ++++++++++ .../reports/views/reports_view_taskc.dart | 209 ++++++++++++++++++ .../settings/views/settings_page_body.dart | 1 + 8 files changed, 922 insertions(+), 21 deletions(-) create mode 100644 lib/app/modules/reports/controllers/reports_tour_controller.dart create mode 100644 lib/app/modules/reports/views/burn_down_daily_taskc.dart create mode 100644 lib/app/modules/reports/views/burn_down_monthly_taskc.dart create mode 100644 lib/app/modules/reports/views/burn_down_weekly_taskc.dart create mode 100644 lib/app/modules/reports/views/reports_tour.dart create mode 100644 lib/app/modules/reports/views/reports_view_taskc.dart diff --git a/lib/app/modules/home/views/nav_drawer.dart b/lib/app/modules/home/views/nav_drawer.dart index 35191bf5..fca2f22b 100644 --- a/lib/app/modules/home/views/nav_drawer.dart +++ b/lib/app/modules/home/views/nav_drawer.dart @@ -85,17 +85,36 @@ class NavDrawer extends StatelessWidget { : TaskWarriorColors.kLightPrimaryBackgroundColor, height: Get.height * 0.03, ), - Obx( - () => NavDrawerMenuItem( - icon: Icons.person_rounded, + Visibility( + visible: homeController.taskchampion.value, + child: NavDrawerMenuItem( + icon: Icons.task_alt, text: SentenceManager( currentLanguage: homeController.selectedLanguage.value, - ).sentences.navDrawerProfile, + ).sentences.ccsyncCredentials, onTap: () { - Get.toNamed(Routes.PROFILE); + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const ManageTaskChampionCreds(), + ), + ); }, ), ), + Visibility( + visible: !homeController.taskchampion.value, + child: Obx( + () => NavDrawerMenuItem( + icon: Icons.person_rounded, + text: SentenceManager( + currentLanguage: homeController.selectedLanguage.value, + ).sentences.navDrawerProfile, + onTap: () { + Get.toNamed(Routes.PROFILE); + }, + ), + ), + ), Obx( () => NavDrawerMenuItem( icon: Icons.summarize, @@ -118,22 +137,6 @@ class NavDrawer extends StatelessWidget { }, ), ), - Visibility( - visible: homeController.taskchampion.value, - child: NavDrawerMenuItem( - icon: Icons.task_alt, - text: SentenceManager( - currentLanguage: homeController.selectedLanguage.value, - ).sentences.ccsyncCredentials, - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const ManageTaskChampionCreds(), - ), - ); - }, - ), - ), Obx( () => NavDrawerMenuItem( icon: Icons.settings, diff --git a/lib/app/modules/reports/controllers/reports_tour_controller.dart b/lib/app/modules/reports/controllers/reports_tour_controller.dart new file mode 100644 index 00000000..35e3162b --- /dev/null +++ b/lib/app/modules/reports/controllers/reports_tour_controller.dart @@ -0,0 +1,20 @@ +import 'package:shared_preferences/shared_preferences.dart'; + +class SaveReportsTour { + Future data = SharedPreferences.getInstance(); + + void saveReportsTourStatus() async { + final value = await data; + value.setBool('reports_tour', true); + } + + Future getReportsTourStatus() async { + final value = await data; + if (value.containsKey('reports_tour')) { + bool? getData = value.getBool('reports_tour'); + return getData!; + } else { + return false; + } + } +} diff --git a/lib/app/modules/reports/views/burn_down_daily_taskc.dart b/lib/app/modules/reports/views/burn_down_daily_taskc.dart new file mode 100644 index 00000000..59a7aa45 --- /dev/null +++ b/lib/app/modules/reports/views/burn_down_daily_taskc.dart @@ -0,0 +1,177 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; +import 'package:taskwarrior/api_service.dart'; +import 'package:taskwarrior/app/models/chart.dart'; +import 'package:taskwarrior/app/modules/reports/views/common_chart_indicator.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/constants/utilites.dart'; +import 'package:taskwarrior/app/utils/theme/app_settings.dart'; + +class BurnDownDailyTaskc extends StatefulWidget { + const BurnDownDailyTaskc({super.key}); + + @override + State createState() => _BurnDownDailyTaskcState(); +} + +class _BurnDownDailyTaskcState extends State + with TickerProviderStateMixin { + late TaskDatabase taskDatabase; + late TooltipBehavior _dailyBurndownTooltipBehaviour; + Map> dailyInfo = {}; + + @override + void initState() { + super.initState(); + + // Initialize the tooltip behavior for the chart + _dailyBurndownTooltipBehaviour = TooltipBehavior( + enable: true, + builder: (dynamic data, dynamic point, dynamic series, int pointIndex, + int seriesIndex) { + final String date = data.x; + final int pendingCount = data.y1; + final int completedCount = data.y2; + + return Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Date: $date', + style: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + ), + ), + Text( + 'Pending: $pendingCount', + ), + Text( + 'Completed: $completedCount', + ), + ], + ), + ); + }, + ); + + // Initialize the database and fetch data + taskDatabase = TaskDatabase(); + taskDatabase.open().then((_) { + taskDatabase.fetchTasksFromDatabase().then((tasks) { + setState(() { + // Process the data and update the chart + _processData(tasks); + }); + }); + }); + } + + void _processData(List tasks) { + dailyInfo = {}; + + // Sort tasks by entry date in ascending order + tasks.sort((a, b) => a.entry.compareTo(b.entry)); + + for (var task in tasks) { + final String date = Utils.formatDate(DateTime.parse(task.entry), 'MM-dd'); + + if (dailyInfo.containsKey(date)) { + if (task.status == 'pending') { + dailyInfo[date]!['pending'] = (dailyInfo[date]!['pending'] ?? 0) + 1; + } else if (task.status == 'completed') { + dailyInfo[date]!['completed'] = + (dailyInfo[date]!['completed'] ?? 0) + 1; + } + } else { + dailyInfo[date] = { + 'pending': task.status == 'pending' ? 1 : 0, + 'completed': task.status == 'completed' ? 1 : 0, + }; + } + } + } + + @override + Widget build(BuildContext context) { + double height = MediaQuery.of(context).size.height; // Screen height + + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: SizedBox( + height: height * 0.6, + child: SfCartesianChart( + primaryXAxis: CategoryAxis( + title: AxisTitle( + text: 'Day - Month', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + color: AppSettings.isDarkMode ? Colors.white : Colors.black, + fontSize: TaskWarriorFonts.fontSizeSmall, + ), + ), + ), + primaryYAxis: NumericAxis( + title: AxisTitle( + text: 'Tasks', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode ? Colors.white : Colors.black, + ), + ), + ), + tooltipBehavior: _dailyBurndownTooltipBehaviour, + series: [ + StackedColumnSeries( + groupName: 'Group A', + enableTooltip: true, + color: TaskWarriorColors.green, + dataSource: dailyInfo.entries + .map((entry) => ChartData( + entry.key, + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y2, + name: 'Completed', + ), + StackedColumnSeries( + groupName: 'Group A', + color: TaskWarriorColors.yellow, + enableTooltip: true, + dataSource: dailyInfo.entries + .map((entry) => ChartData( + entry.key, + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y1, + name: 'Pending', + ), + ], + ), + ), + ), + const CommonChartIndicator( + title: 'Daily Burndown Chart', + ), + ], + ); + } +} diff --git a/lib/app/modules/reports/views/burn_down_monthly_taskc.dart b/lib/app/modules/reports/views/burn_down_monthly_taskc.dart new file mode 100644 index 00000000..3e75115b --- /dev/null +++ b/lib/app/modules/reports/views/burn_down_monthly_taskc.dart @@ -0,0 +1,184 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; +import 'package:taskwarrior/api_service.dart'; +import 'package:taskwarrior/app/models/chart.dart'; +import 'package:taskwarrior/app/modules/reports/views/common_chart_indicator.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/constants/utilites.dart'; +import 'package:taskwarrior/app/utils/theme/app_settings.dart'; + +class BurnDownMonthlyTaskc extends StatefulWidget { + const BurnDownMonthlyTaskc({super.key}); + + @override + State createState() => _BurnDownMonthlyTaskcState(); +} + +class _BurnDownMonthlyTaskcState extends State + with TickerProviderStateMixin { + late TaskDatabase taskDatabase; + Map> monthlyInfo = {}; + + late TooltipBehavior _weeklyBurndownTooltipBehaviour; + + @override + void initState() { + super.initState(); + + _weeklyBurndownTooltipBehaviour = TooltipBehavior( + enable: true, + builder: (dynamic data, dynamic point, dynamic series, int pointIndex, + int seriesIndex) { + final String monthYear = data.x; + final int pendingCount = data.y1; + final int completedCount = data.y2; + + return Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Month-Year: $monthYear', + style: const TextStyle( + fontWeight: TaskWarriorFonts.bold, + ), + ), + Text( + 'Pending: $pendingCount', + ), + Text( + 'Completed: $completedCount', + ), + ], + ), + ); + }, + ); + + taskDatabase = TaskDatabase(); + + ///fetch all data from the database + fetchAllData(); + } + + void fetchAllData() async { + List allData = await taskDatabase.fetchTasksFromDatabase(); + if (allData.isNotEmpty) { + sortBurnDownMonthly(allData); + } + } + + void sortBurnDownMonthly(List allData) { + monthlyInfo = {}; + + allData.sort((a, b) => a.entry.compareTo(b.entry)); + + for (int i = 0; i < allData.length; i++) { + final DateTime entryDate = DateTime.parse(allData[i].entry); + final String monthYear = + '${Utils.getMonthName(entryDate.month)} ${entryDate.year}'; + + if (monthlyInfo.containsKey(monthYear)) { + if (allData[i].status == 'pending') { + monthlyInfo[monthYear]!['pending'] = + (monthlyInfo[monthYear]!['pending'] ?? 0) + 1; + } else if (allData[i].status == 'completed') { + monthlyInfo[monthYear]!['completed'] = + (monthlyInfo[monthYear]!['completed'] ?? 0) + 1; + } + } else { + monthlyInfo[monthYear] = { + 'pending': allData[i].status == 'pending' ? 1 : 0, + 'completed': allData[i].status == 'completed' ? 1 : 0, + }; + } + } + + debugPrint("monthlyInfo: $monthlyInfo"); + + // Update the state to refresh the chart + setState(() {}); + } + + @override + Widget build(BuildContext context) { + final double height = MediaQuery.of(context).size.height; + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: SizedBox( + height: height * 0.6, + child: SfCartesianChart( + primaryXAxis: CategoryAxis( + title: AxisTitle( + text: 'Month - Year', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode ? Colors.white : Colors.black, + ), + ), + ), + primaryYAxis: NumericAxis( + title: AxisTitle( + text: 'Tasks', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode ? Colors.white : Colors.black, + ), + ), + ), + tooltipBehavior: _weeklyBurndownTooltipBehaviour, + series: [ + StackedColumnSeries( + groupName: 'Group A', + enableTooltip: true, + color: TaskWarriorColors.green, + dataSource: monthlyInfo.entries + .map((entry) => ChartData( + entry.key, + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y2, + name: 'Completed', + ), + StackedColumnSeries( + groupName: 'Group A', + color: TaskWarriorColors.yellow, + enableTooltip: true, + dataSource: monthlyInfo.entries + .map((entry) => ChartData( + entry.key, + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y1, + name: 'Pending', + ), + ], + ), + ), + ), + const CommonChartIndicator( + title: 'Monthly Burndown Chart', + ) + ], + ); + } +} diff --git a/lib/app/modules/reports/views/burn_down_weekly_taskc.dart b/lib/app/modules/reports/views/burn_down_weekly_taskc.dart new file mode 100644 index 00000000..193600a2 --- /dev/null +++ b/lib/app/modules/reports/views/burn_down_weekly_taskc.dart @@ -0,0 +1,195 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; +import 'package:taskwarrior/api_service.dart'; +import 'package:taskwarrior/app/models/chart.dart'; +import 'package:taskwarrior/app/modules/reports/views/common_chart_indicator.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/constants/utilites.dart'; +import 'package:taskwarrior/app/utils/theme/app_settings.dart'; + +class BurnDownWeeklyTask extends StatefulWidget { + const BurnDownWeeklyTask({super.key}); + + @override + State createState() => _BurnDownWeeklyTaskState(); +} + +class _BurnDownWeeklyTaskState extends State + with TickerProviderStateMixin { + late TaskDatabase taskDatabase; + late TooltipBehavior _weeklyBurndownTooltipBehaviour; + Map> weeklyInfo = {}; + + @override + void initState() { + super.initState(); + + ///initialize the _weeklyBurndownTooltipBehaviour tooltip behavior + _weeklyBurndownTooltipBehaviour = TooltipBehavior( + enable: true, + builder: (dynamic data, dynamic point, dynamic series, int pointIndex, + int seriesIndex) { + final String weekNumber = data.x; + final int pendingCount = data.y1; + final int completedCount = data.y2; + + return Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + weekNumber, + style: const TextStyle( + fontWeight: TaskWarriorFonts.bold, + ), + ), + Text( + 'Pending: $pendingCount', + ), + Text( + 'Completed: $completedCount', + ), + ], + ), + ); + }, + ); + + taskDatabase = TaskDatabase(); + + ///fetch all data from the database + fetchAllData(); + } + + void fetchAllData() async { + List allData = await taskDatabase.fetchTasksFromDatabase(); + if (allData.isNotEmpty) { + sortBurnDownWeekly(allData); + } + } + + void sortBurnDownWeekly(List allData) { + // Initialize weeklyInfo map + weeklyInfo = {}; + + // Sort allData by entry date in ascending order + allData.sort((a, b) => a.entry.compareTo(b.entry)); + + ///loop through allData and get the week number + for (int i = 0; i < allData.length; i++) { + final int weekNumber = + Utils.getWeekNumbertoInt(DateTime.parse(allData[i].entry)); + + ///check if weeklyInfo contains the week number + if (weeklyInfo.containsKey(weekNumber)) { + ///check if the status is pending or completed + if (allData[i].status == 'pending') { + ///if the status is pending then add 1 to the pending count + weeklyInfo[weekNumber]!['pending'] = + (weeklyInfo[weekNumber]!['pending'] ?? 0) + 1; + } else if (allData[i].status == 'completed') { + ///if the status is completed then add 1 to the completed count + weeklyInfo[weekNumber]!['completed'] = + (weeklyInfo[weekNumber]!['completed'] ?? 0) + 1; + } + } else { + ///if weeklyInfo does not contain the week number + weeklyInfo[weekNumber] = { + 'pending': allData[i].status == 'pending' ? 1 : 0, + 'completed': allData[i].status == 'completed' ? 1 : 0, + }; + } + } + + debugPrint("weeklyInfo $weeklyInfo"); + + // Update the state to refresh the chart + setState(() {}); + } + + @override + Widget build(BuildContext context) { + double height = MediaQuery.of(context).size.height; // Screen height + + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: SizedBox( + height: height * 0.6, + child: SfCartesianChart( + primaryXAxis: CategoryAxis( + title: AxisTitle( + text: 'Weeks - Year', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode ? Colors.white : Colors.black, + ), + ), + ), + primaryYAxis: NumericAxis( + title: AxisTitle( + text: 'Tasks', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + color: AppSettings.isDarkMode ? Colors.white : Colors.black, + fontSize: TaskWarriorFonts.fontSizeSmall, + ), + ), + ), + tooltipBehavior: _weeklyBurndownTooltipBehaviour, + series: [ + ///this is the completed tasks + StackedColumnSeries( + groupName: 'Group A', + enableTooltip: true, + color: TaskWarriorColors.green, + dataSource: weeklyInfo.entries + .map((entry) => ChartData( + 'Week ${entry.key}', + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y2, + name: 'Completed', + ), + + ///this is the pending tasks + StackedColumnSeries( + groupName: 'Group A', + color: TaskWarriorColors.yellow, + enableTooltip: true, + dataSource: weeklyInfo.entries + .map((entry) => ChartData( + 'Week ${entry.key}', + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y1, + name: 'Pending', + ), + ], + ), + ), + ), + const CommonChartIndicator( + title: 'Weekly Burndown Chart', + ), + ], + ); + } +} diff --git a/lib/app/modules/reports/views/reports_tour.dart b/lib/app/modules/reports/views/reports_tour.dart new file mode 100644 index 00000000..51f17360 --- /dev/null +++ b/lib/app/modules/reports/views/reports_tour.dart @@ -0,0 +1,112 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; + +List reportsDrawer({ + required GlobalKey daily, + required GlobalKey weekly, + required GlobalKey monthly, +}) { + List targets = []; + + // daily + targets.add( + TargetFocus( + keyTarget: daily, + alignSkip: Alignment.topRight, + radius: 10, + shape: ShapeLightFocus.RRect, + contents: [ + TargetContent( + align: ContentAlign.bottom, + builder: (context, controller) { + return Container( + alignment: Alignment.center, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Access your daily task report here", + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + color: Colors.white, + ), + ), + ], + ), + ); + }, + ), + ], + ), + ); + + // weekly + targets.add( + TargetFocus( + keyTarget: weekly, + alignSkip: Alignment.topRight, + radius: 10, + shape: ShapeLightFocus.RRect, + contents: [ + TargetContent( + align: ContentAlign.bottom, + builder: (context, controller) { + return Container( + alignment: Alignment.center, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Access your weekly task reports here", + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + color: Colors.white, + ), + ), + ], + ), + ); + }, + ), + ], + ), + ); + + // monthly + targets.add( + TargetFocus( + keyTarget: monthly, + alignSkip: Alignment.bottomCenter, + radius: 10, + shape: ShapeLightFocus.RRect, + contents: [ + TargetContent( + align: ContentAlign.bottom, + builder: (context, controller) { + return Container( + alignment: Alignment.center, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Access your monthly task reports here", + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + color: Colors.white, + ), + ), + ], + ), + ); + }, + ), + ], + ), + ); + + return targets; +} diff --git a/lib/app/modules/reports/views/reports_view_taskc.dart b/lib/app/modules/reports/views/reports_view_taskc.dart new file mode 100644 index 00000000..277a7c03 --- /dev/null +++ b/lib/app/modules/reports/views/reports_view_taskc.dart @@ -0,0 +1,209 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:taskwarrior/api_service.dart'; +import 'package:taskwarrior/app/modules/reports/controllers/reports_tour_controller.dart'; +import 'package:taskwarrior/app/modules/reports/views/burn_down_daily_taskc.dart'; +import 'package:taskwarrior/app/modules/reports/views/burn_down_monthly_taskc.dart'; +import 'package:taskwarrior/app/modules/reports/views/burn_down_weekly_taskc.dart'; +import 'package:taskwarrior/app/tour/reports_page_tour.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/theme/app_settings.dart'; +import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; + +class ReportsHomeTaskc extends StatefulWidget { + const ReportsHomeTaskc({ + super.key, + }); + + @override + State createState() => _ReportsHomeTaskcState(); +} + +class _ReportsHomeTaskcState extends State + with TickerProviderStateMixin { + late TabController _tabController; + final GlobalKey daily = GlobalKey(); + final GlobalKey weekly = GlobalKey(); + final GlobalKey monthly = GlobalKey(); + + bool isSaved = false; + late TutorialCoachMark tutorialCoachMark; + + int _selectedIndex = 0; + late TaskDatabase taskDatabase; + List allTasks = []; + + void _initReportsTour() { + tutorialCoachMark = TutorialCoachMark( + targets: reportsDrawer( + daily: daily, + weekly: weekly, + monthly: monthly, + ), + colorShadow: TaskWarriorColors.black, + paddingFocus: 10, + opacityShadow: 0.8, + hideSkip: true, + onFinish: () { + SaveReportsTour().saveReportsTourStatus(); + }, + ); + } + + void _showReportsTour() { + Future.delayed( + const Duration(seconds: 2), + () { + SaveReportsTour().getReportsTourStatus().then((value) => { + if (value == false) + { + tutorialCoachMark.show(context: context), + } + else + { + // ignore: avoid_print + print('User has seen this page'), + } + }); + }, + ); + } + + @override + void initState() { + super.initState(); + _initReportsTour(); + _showReportsTour(); + + _tabController = TabController(length: 3, vsync: this); + + // Initialize the database and fetch data + taskDatabase = TaskDatabase(); + taskDatabase.open().then((_) { + taskDatabase.fetchTasksFromDatabase().then((tasks) { + setState(() { + allTasks = tasks; + }); + }); + }); + } + + @override + Widget build(BuildContext context) { + double height = MediaQuery.of(context).size.height; // Screen height + + return Scaffold( + appBar: AppBar( + backgroundColor: TaskWarriorColors.kprimaryBackgroundColor, + title: Text( + 'Reports', + style: GoogleFonts.poppins(color: TaskWarriorColors.white), + ), + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon( + Icons.chevron_left, + color: TaskWarriorColors.white, + ), + ), + bottom: PreferredSize( + preferredSize: Size.fromHeight( + height * 0.1), // Adjust the preferred height as needed + child: TabBar( + controller: _tabController, + labelColor: TaskWarriorColors.white, + labelStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.medium, + fontSize: TaskWarriorFonts.fontSizeSmall, + ), + unselectedLabelStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.light, + ), + onTap: (value) { + setState(() { + _selectedIndex = value; + }); + }, + tabs: [ + Tab( + key: daily, + icon: const Icon(Icons.schedule), + text: 'Daily', + iconMargin: const EdgeInsets.only(bottom: 0.0), + ), + Tab( + key: weekly, + icon: const Icon(Icons.today), + text: 'Weekly', + iconMargin: const EdgeInsets.only(bottom: 0.0), + ), + Tab( + key: monthly, + icon: const Icon(Icons.date_range), + text: 'Monthly', + iconMargin: const EdgeInsets.only(bottom: 0.0), + ), + ], + ), + ), + ), + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryBackgroundColor + : TaskWarriorColors.white, + body: allTasks.isEmpty + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + Icons.heart_broken, + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'No Task found', + style: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.medium, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Add a task to see reports', + style: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.light, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + ], + ), + ], + ) + : IndexedStack( + index: _selectedIndex, + children: const [ + BurnDownDailyTaskc(), + BurnDownWeeklyTask(), + BurnDownMonthlyTaskc(), + ], + ), + ); + } +} diff --git a/lib/app/modules/settings/views/settings_page_body.dart b/lib/app/modules/settings/views/settings_page_body.dart index 207c1e64..4e1a2043 100644 --- a/lib/app/modules/settings/views/settings_page_body.dart +++ b/lib/app/modules/settings/views/settings_page_body.dart @@ -116,6 +116,7 @@ class SettingsPageBody extends StatelessWidget { controller: controller, ), ), + const Divider(), SettingsPageListTile( title: SentenceManager( currentLanguage: controller.selectedLanguage.value) From 303ca109658bdc73bdb622c74a3d2769a8ed2d49 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 08:44:08 +0530 Subject: [PATCH 06/47] fix: move reports_tour --- lib/app/modules/reports/{views => controllers}/reports_tour.dart | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/app/modules/reports/{views => controllers}/reports_tour.dart (100%) diff --git a/lib/app/modules/reports/views/reports_tour.dart b/lib/app/modules/reports/controllers/reports_tour.dart similarity index 100% rename from lib/app/modules/reports/views/reports_tour.dart rename to lib/app/modules/reports/controllers/reports_tour.dart From 373c8d8588a3841f490ab577917480819ceba045 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 11:25:57 +0530 Subject: [PATCH 07/47] feat: add project filter for taskc --- lib/api_service.dart | 12 ++ .../home/controllers/home_controller.dart | 11 ++ .../home/views/filter_drawer_home_page.dart | 169 +++++++++++------- .../modules/home/views/home_page_body.dart | 1 + .../home/views/project_column_home_page.dart | 27 --- .../home/views/project_column_taskc.dart | 131 ++++++++++++++ lib/app/modules/home/views/show_details.dart | 149 ++++++++++----- lib/app/modules/home/views/show_tasks.dart | 26 ++- lib/app/tour/filter_drawer_tour.dart | 34 ++++ 9 files changed, 408 insertions(+), 152 deletions(-) create mode 100644 lib/app/modules/home/views/project_column_taskc.dart diff --git a/lib/api_service.dart b/lib/api_service.dart index a6b9f668..f6188851 100644 --- a/lib/api_service.dart +++ b/lib/api_service.dart @@ -473,6 +473,18 @@ class TaskDatabase { }); } + Future> fetchUniqueProjects() async { + var taskDatabase = TaskDatabase(); + await taskDatabase.open(); + await taskDatabase.ensureDatabaseIsOpen(); + + final List> result = await taskDatabase._database! + .rawQuery( + 'SELECT DISTINCT project FROM Tasks WHERE project IS NOT NULL'); + + return result.map((row) => row['project'] as String).toList(); + } + Future> searchTasks(String query) async { final List> maps = await _database!.query( 'tasks', diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 248abe68..167f47e9 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -9,6 +9,7 @@ import 'package:get/get.dart'; import 'package:home_widget/home_widget.dart'; import 'package:loggy/loggy.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:taskwarrior/api_service.dart'; import 'package:taskwarrior/app/models/filters.dart'; import 'package:taskwarrior/app/models/json/task.dart'; @@ -66,9 +67,17 @@ class HomeController extends GetxController { if (Platform.isAndroid) { handleHomeWidgetClicked(); } + getUniqueProjects(); _loadTaskChampion(); } + Future> getUniqueProjects() async { + var taskDatabase = TaskDatabase(); + List uniqueProjects = await taskDatabase.fetchUniqueProjects(); + debugPrint('Unique projects: $uniqueProjects'); + return uniqueProjects; + } + Future _loadTaskChampion() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); taskchampion.value = prefs.getBool('taskchampion') ?? false; @@ -563,6 +572,7 @@ class HomeController extends GetxController { final GlobalKey statusKey = GlobalKey(); final GlobalKey projectsKey = GlobalKey(); + final GlobalKey projectsKeyTaskc = GlobalKey(); final GlobalKey filterTagKey = GlobalKey(); final GlobalKey sortByKey = GlobalKey(); @@ -571,6 +581,7 @@ class HomeController extends GetxController { targets: filterDrawer( statusKey: statusKey, projectsKey: projectsKey, + projectsKeyTaskc: projectsKeyTaskc, filterTagKey: filterTagKey, sortByKey: sortByKey, ), diff --git a/lib/app/modules/home/views/filter_drawer_home_page.dart b/lib/app/modules/home/views/filter_drawer_home_page.dart index 37dd569e..8a447ea6 100644 --- a/lib/app/modules/home/views/filter_drawer_home_page.dart +++ b/lib/app/modules/home/views/filter_drawer_home_page.dart @@ -3,6 +3,7 @@ import 'package:get/get_state_manager/get_state_manager.dart'; import 'package:taskwarrior/app/models/filters.dart'; import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart'; import 'package:taskwarrior/app/modules/home/views/project_column_home_page.dart'; +import 'package:taskwarrior/app/modules/home/views/project_column_taskc.dart'; import 'package:taskwarrior/app/services/tag_filter.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; @@ -13,7 +14,6 @@ import 'package:taskwarrior/app/utils/theme/app_settings.dart'; class FilterDrawer extends StatelessWidget { final Filters filters; final HomeController homeController; - const FilterDrawer( {required this.filters, required this.homeController, super.key}); @@ -165,81 +165,120 @@ class FilterDrawer extends StatelessWidget { const Divider( color: Color.fromARGB(0, 48, 46, 46), ), - Container( - key: homeController.projectsKey, - width: MediaQuery.of(context).size.width * 1, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: tileColor, - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: TaskWarriorColors.borderColor, + Visibility( + visible: !homeController.taskchampion.value, + child: Container( + key: homeController.projectsKey, + width: MediaQuery.of(context).size.width * 1, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: tileColor, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: TaskWarriorColors.borderColor, + ), + ), + child: ProjectsColumn( + projects: filters.projects, + projectFilter: filters.projectFilter, + callback: filters.toggleProjectFilter, ), ), - child: ProjectsColumn( - projects: filters.projects, - projectFilter: filters.projectFilter, - callback: filters.toggleProjectFilter, + ), + Visibility( + visible: homeController.taskchampion.value, + child: FutureBuilder>( + future: homeController.getUniqueProjects(), + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + return Container( + key: homeController.projectsKeyTaskc, + width: MediaQuery.of(context).size.width * 1, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: tileColor, + borderRadius: BorderRadius.circular(8), + border: + Border.all(color: TaskWarriorColors.borderColor), + ), + child: ProjectColumnTaskc( + callback: filters.toggleProjectFilter, + projects: snapshot.data!, + projectFilter: filters.projectFilter, + ), + ); + } else { + return const Center( + child: Text('No projects available.')); + } + }, ), ), const Divider( color: Color.fromARGB(0, 48, 46, 46), ), - Container( - key: homeController.filterTagKey, - width: MediaQuery.of(context).size.width * 1, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: tileColor, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: TaskWarriorColors.borderColor), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Divider( - color: Color.fromARGB(0, 48, 46, 46), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 0.0), - child: Text( - SentenceManager( - currentLanguage: - homeController.selectedLanguage.value) - .sentences - .filterDrawerFilterTagBy, - // style: GoogleFonts.poppins( - // color: (AppSettings.isDarkMode - // ? TaskWarriorColors.kprimaryTextColor - // : TaskWarriorColors.kLightSecondaryTextColor), - // // - // fontSize: TaskWarriorFonts.fontSizeLarge), - //textAlign: TextAlign.right, - style: TextStyle( - fontFamily: FontFamily.poppins, - fontSize: TaskWarriorFonts.fontSizeMedium, - color: AppSettings.isDarkMode - ? TaskWarriorColors.kprimaryTextColor - : TaskWarriorColors.kLightSecondaryTextColor, + Visibility( + visible: !homeController.taskchampion.value, + child: Container( + key: homeController.filterTagKey, + width: MediaQuery.of(context).size.width * 1, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: tileColor, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: TaskWarriorColors.borderColor), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Divider( + color: Color.fromARGB(0, 48, 46, 46), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 0.0), + child: Text( + SentenceManager( + currentLanguage: + homeController.selectedLanguage.value) + .sentences + .filterDrawerFilterTagBy, + // style: GoogleFonts.poppins( + // color: (AppSettings.isDarkMode + // ? TaskWarriorColors.kprimaryTextColor + // : TaskWarriorColors.kLightSecondaryTextColor), + // // + // fontSize: TaskWarriorFonts.fontSizeLarge), + //textAlign: TextAlign.right, + style: TextStyle( + fontFamily: FontFamily.poppins, + fontSize: TaskWarriorFonts.fontSizeMedium, + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightSecondaryTextColor, + ), ), ), - ), - const Divider( - color: Color.fromARGB(0, 48, 46, 46), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: TagFiltersWrap(filters.tagFilters), - ), - const Divider( - color: Color.fromARGB(0, 48, 46, 46), - ), - ], + const Divider( + color: Color.fromARGB(0, 48, 46, 46), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: TagFiltersWrap(filters.tagFilters), + ), + const Divider( + color: Color.fromARGB(0, 48, 46, 46), + ), + ], + ), ), ), - const Divider( - color: Color.fromARGB(0, 48, 46, 46), + Visibility( + visible: !homeController.taskchampion.value, + child: const Divider( + color: Color.fromARGB(0, 48, 46, 46), + ), ), Container( key: homeController.sortByKey, diff --git a/lib/app/modules/home/views/home_page_body.dart b/lib/app/modules/home/views/home_page_body.dart index 7341270c..e08bcc97 100644 --- a/lib/app/modules/home/views/home_page_body.dart +++ b/lib/app/modules/home/views/home_page_body.dart @@ -116,6 +116,7 @@ class HomePageBody extends StatelessWidget { child: TaskViewBuilder( pendingFilter: controller.pendingFilter.value, selectedSort: controller.selectedSort.value, + project: controller.projectFilter.value, ), ))) ], diff --git a/lib/app/modules/home/views/project_column_home_page.dart b/lib/app/modules/home/views/project_column_home_page.dart index 57cd68d6..a01b2e93 100644 --- a/lib/app/modules/home/views/project_column_home_page.dart +++ b/lib/app/modules/home/views/project_column_home_page.dart @@ -32,13 +32,6 @@ class ProjectsColumn extends StatelessWidget { children: [ Text( "Project : ", - // style: GoogleFonts.poppins( - // fontWeight: TaskWarriorFonts.bold, - // fontSize: TaskWarriorFonts.fontSizeMedium, - // color: AppSettings.isDarkMode - // ? TaskWarriorColors.white - // : TaskWarriorColors.black, - // ), style: TextStyle( fontFamily: FontFamily.poppins, fontWeight: TaskWarriorFonts.bold, @@ -57,12 +50,6 @@ class ProjectsColumn extends StatelessWidget { children: [ Text( projectFilter == "" ? "Not selected" : projectFilter, - // style: GoogleFonts.poppins( - // fontSize: TaskWarriorFonts.fontSizeSmall, - // color: AppSettings.isDarkMode - // ? TaskWarriorColors.white - // : TaskWarriorColors.black, - // ), style: TextStyle( fontFamily: FontFamily.poppins, fontSize: TaskWarriorFonts.fontSizeSmall, @@ -84,13 +71,6 @@ class ProjectsColumn extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, children: [ Text("All Projects", - // style: GoogleFonts.poppins( - // fontWeight: TaskWarriorFonts.semiBold, - // fontSize: TaskWarriorFonts.fontSizeSmall, - // color: AppSettings.isDarkMode - // ? TaskWarriorColors.white - // : TaskWarriorColors.black, - // ), style: TextStyle( fontFamily: FontFamily.poppins, fontSize: TaskWarriorFonts.fontSizeSmall, @@ -115,13 +95,6 @@ class ProjectsColumn extends StatelessWidget { children: [ Text( "No Projects Found", - // style: GoogleFonts.poppins( - // color: AppSettings.isDarkMode - // ? TaskWarriorColors.white - // : TaskWarriorColors.black, - // fontSize: TaskWarriorFonts.fontSizeSmall, - // ), - style: TextStyle( fontFamily: FontFamily.poppins, fontSize: TaskWarriorFonts.fontSizeSmall, diff --git a/lib/app/modules/home/views/project_column_taskc.dart b/lib/app/modules/home/views/project_column_taskc.dart new file mode 100644 index 00000000..134a260e --- /dev/null +++ b/lib/app/modules/home/views/project_column_taskc.dart @@ -0,0 +1,131 @@ +import 'package:flutter/material.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/gen/fonts.gen.dart'; +import 'package:taskwarrior/app/utils/theme/app_settings.dart'; // Import your necessary dependencies + +class ProjectColumnTaskc extends StatelessWidget { + const ProjectColumnTaskc({ + super.key, + required this.projects, + required this.projectFilter, + required this.callback, + }); + + final List projects; + final String projectFilter; + final void Function(String) callback; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + "Project : ", + style: TextStyle( + fontFamily: FontFamily.poppins, + fontWeight: TaskWarriorFonts.bold, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + const SizedBox( + width: 10, + ), + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Text( + projectFilter.isEmpty ? "Not selected" : projectFilter, + style: TextStyle( + fontFamily: FontFamily.poppins, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + ), + ), + ], + ), + ), + ProjectTileTaskc( + project: 'All Projects', + projectFilter: projectFilter, + callback: callback), + if (projects.isNotEmpty) + ...projects.map((entry) => ProjectTileTaskc( + project: entry, + projectFilter: projectFilter, + callback: callback, + )) + else + Column( + children: [ + Text( + "No Projects Found", + style: TextStyle( + fontFamily: FontFamily.poppins, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + const SizedBox( + height: 10, + ), + ], + ), + ], + ); + } +} + +class ProjectTileTaskc extends StatelessWidget { + const ProjectTileTaskc({ + super.key, + required this.project, + required this.projectFilter, + required this.callback, + }); + + final String project; + final String projectFilter; + final void Function(String) callback; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () => callback(project), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Radio( + value: project, + groupValue: projectFilter, + onChanged: (_) => callback(project), + ), + Text( + project, + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + const Spacer(), + ], + ), + ); + } +} diff --git a/lib/app/modules/home/views/show_details.dart b/lib/app/modules/home/views/show_details.dart index 55688375..7f6dd4c9 100644 --- a/lib/app/modules/home/views/show_details.dart +++ b/lib/app/modules/home/views/show_details.dart @@ -1,3 +1,5 @@ +// ignore_for_file: use_build_context_synchronously + import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; @@ -6,20 +8,48 @@ import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/utilites.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; -class TaskDetails extends StatelessWidget { +class TaskDetails extends StatefulWidget { final Tasks task; const TaskDetails({super.key, required this.task}); @override - Widget build(BuildContext context) { - String description = task.description; - String project = task.project ?? ''; - String status = task.status; - String priority = task.priority ?? ''; - String due = task.due ?? '-'; + State createState() => _TaskDetailsState(); +} + +class _TaskDetailsState extends State { + late String description; + late String project; + late String status; + late String priority; + late String due; + late TaskDatabase taskDatabase; + + bool hasChanges = false; + + @override + void initState() { + super.initState(); + description = widget.task.description; + project = widget.task.project!; + status = widget.task.status; + priority = widget.task.priority!; + due = widget.task.due ?? '-'; due = _buildDate(due); - bool hasChanges = false; + setState(() { + taskDatabase = TaskDatabase(); + taskDatabase.open(); + }); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + taskDatabase = TaskDatabase(); + taskDatabase.open(); + } + @override + Widget build(BuildContext context) { return Scaffold( backgroundColor: AppSettings.isDarkMode ? TaskWarriorColors.kprimaryBackgroundColor @@ -28,7 +58,7 @@ class TaskDetails extends StatelessWidget { foregroundColor: TaskWarriorColors.lightGrey, backgroundColor: TaskWarriorColors.kprimaryBackgroundColor, title: Text( - 'Task: ${task.description}', + 'Task: ${widget.task.description}', style: GoogleFonts.poppins(color: TaskWarriorColors.white), ), ), @@ -36,46 +66,63 @@ class TaskDetails extends StatelessWidget { padding: const EdgeInsets.all(16.0), child: ListView( children: [ - _buildEditableDetail(context, 'Description:', description, (value) { - description = value; - hasChanges = true; + _buildEditableDetail('Description:', description, (value) { + setState(() { + description = value; + hasChanges = true; + }); }), - _buildEditableDetail(context, 'Project:', project, (value) { - project = value; - hasChanges = true; + _buildEditableDetail('Project:', project, (value) { + setState(() { + project = value; + hasChanges = true; + }); }), - _buildSelectableDetail( - context, 'Status:', status, ['pending', 'completed'], (value) { - status = value; - hasChanges = true; + _buildSelectableDetail('Status:', status, ['pending', 'completed'], + (value) { + setState(() { + status = value; + hasChanges = true; + }); }), - _buildSelectableDetail( - context, 'Priority:', priority, ['H', 'M', 'L'], (value) { - priority = value; - hasChanges = true; + _buildSelectableDetail('Priority:', priority, ['H', 'M', 'L'], + (value) { + setState(() { + priority = value; + hasChanges = true; + }); }), - _buildDatePickerDetail(context, 'Due:', due, (value) { - due = value; - hasChanges = true; + _buildDatePickerDetail('Due:', due, (value) { + setState(() { + due = value; + hasChanges = true; + }); }), - _buildDetail('UUID:', task.uuid!), - _buildDetail('Urgency:', task.urgency.toString()), - _buildDetail('End:', _buildDate(task.end)), - _buildDetail('Entry:', _buildDate(task.entry)), - _buildDetail('Modified:', _buildDate(task.modified)), + _buildDetail('UUID:', widget.task.uuid!), + _buildDetail('Urgency:', widget.task.urgency.toString()), + _buildDetail('End:', _buildDate(widget.task.end)), + _buildDetail('Entry:', _buildDate(widget.task.entry)), + _buildDetail('Modified:', _buildDate(widget.task.modified)), ], ), ), floatingActionButton: hasChanges ? FloatingActionButton( onPressed: () async { - TaskDatabase taskDatabase = TaskDatabase(); - await taskDatabase.open(); - await taskDatabase.saveEditedTaskInDB( - task.uuid!, description, project, status, priority, due); - hasChanges = false; + await taskDatabase.saveEditedTaskInDB(widget.task.uuid!, + description, project, status, priority, due); + setState(() { + hasChanges = false; + }); modifyTaskOnTaskwarrior( - description, project, due, priority, status, task.uuid!); + description, + project, + due, + priority, + status, + widget.task.uuid!, + ); + // used this for testing }, child: const Icon(Icons.save), ) @@ -83,8 +130,8 @@ class TaskDetails extends StatelessWidget { ); } - Widget _buildEditableDetail(BuildContext context, String label, String value, - Function(String) onChanged) { + Widget _buildEditableDetail( + String label, String value, Function(String) onChanged) { return InkWell( onTap: () async { final result = await _showEditDialog(context, label, value); @@ -96,8 +143,8 @@ class TaskDetails extends StatelessWidget { ); } - Widget _buildSelectableDetail(BuildContext context, String label, - String value, List options, Function(String) onChanged) { + Widget _buildSelectableDetail(String label, String value, + List options, Function(String) onChanged) { return InkWell( onTap: () async { final result = await _showSelectDialog(context, label, value, options); @@ -109,8 +156,8 @@ class TaskDetails extends StatelessWidget { ); } - Widget _buildDatePickerDetail(BuildContext context, String label, - String value, Function(String) onChanged) { + Widget _buildDatePickerDetail( + String label, String value, Function(String) onChanged) { return InkWell( onTap: () async { final DateTime? pickedDate = await showDatePicker( @@ -122,14 +169,26 @@ class TaskDetails extends StatelessWidget { return Theme( data: Theme.of(context).copyWith( colorScheme: AppSettings.isDarkMode - ? ColorScheme.dark( + ? ColorScheme( + brightness: Brightness.dark, primary: TaskWarriorColors.white, onPrimary: TaskWarriorColors.black, + secondary: TaskWarriorColors.black, + onSecondary: TaskWarriorColors.white, + error: TaskWarriorColors.red, + onError: TaskWarriorColors.black, + surface: TaskWarriorColors.black, onSurface: TaskWarriorColors.white, ) - : ColorScheme.light( + : ColorScheme( + brightness: Brightness.light, primary: TaskWarriorColors.black, onPrimary: TaskWarriorColors.white, + secondary: TaskWarriorColors.white, + onSecondary: TaskWarriorColors.black, + error: TaskWarriorColors.red, + onError: TaskWarriorColors.white, + surface: TaskWarriorColors.white, onSurface: TaskWarriorColors.black, ), ), diff --git a/lib/app/modules/home/views/show_tasks.dart b/lib/app/modules/home/views/show_tasks.dart index 2cbd4448..bde8de80 100644 --- a/lib/app/modules/home/views/show_tasks.dart +++ b/lib/app/modules/home/views/show_tasks.dart @@ -41,7 +41,7 @@ class TaskViewBuilder extends StatelessWidget { } else if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } else { - return FutureBuilder( + return FutureBuilder>( future: _fetchTasks(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { @@ -51,12 +51,17 @@ class TaskViewBuilder extends StatelessWidget { } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Center(child: Text('No tasks available')); } else { - // Sorting tasks by ID in ascending order + // Filter tasks based on the selected project List tasks = List.from(snapshot.data!); - tasks.sort((a, b) => b.id.compareTo(a.id)); + if (project != 'All Projects') { + tasks = + tasks.where((task) => task.project == project).toList(); + } else { + tasks = List.from(snapshot.data!); + } - _updateTasksInDatabase(tasks); - _findTasksWithoutUUIDs(); + // Apply other filters and sorting + tasks.sort((a, b) => b.id.compareTo(a.id)); tasks = tasks.where((task) { if (pendingFilter) { @@ -98,15 +103,6 @@ class TaskViewBuilder extends StatelessWidget { } }); - // Filter tasks based on the pendingFilter - tasks = tasks.where((task) { - if (pendingFilter) { - return task.status == 'pending'; - } else { - return task.status == 'completed'; - } - }).toList(); - return Scaffold( backgroundColor: AppSettings.isDarkMode ? TaskWarriorColors.kprimaryBackgroundColor @@ -274,7 +270,7 @@ class TaskViewBuilder extends StatelessWidget { ); } - Future _fetchTasks() async { + Future> _fetchTasks() async { TaskDatabase taskDatabase = TaskDatabase(); await taskDatabase.open(); return await taskDatabase.fetchTasksFromDatabase(); diff --git a/lib/app/tour/filter_drawer_tour.dart b/lib/app/tour/filter_drawer_tour.dart index 67eb4655..4ddcfaaf 100644 --- a/lib/app/tour/filter_drawer_tour.dart +++ b/lib/app/tour/filter_drawer_tour.dart @@ -6,6 +6,7 @@ import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; List filterDrawer({ required GlobalKey statusKey, required GlobalKey projectsKey, + required GlobalKey projectsKeyTaskc, required GlobalKey filterTagKey, required GlobalKey sortByKey, }) { @@ -77,6 +78,39 @@ List filterDrawer({ ), ); + // projectsKeyTaskc + targets.add( + TargetFocus( + keyTarget: projectsKeyTaskc, + alignSkip: Alignment.topRight, + radius: 10, + shape: ShapeLightFocus.RRect, + contents: [ + TargetContent( + align: ContentAlign.top, + builder: (context, controller) { + return Container( + alignment: Alignment.center, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Filter tasks based on the projects", + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + color: TaskWarriorColors.white, + ), + ), + ], + ), + ); + }, + ), + ], + ), + ); + // filterTagByKey targets.add( TargetFocus( From 6e9f77877a590be844922b6c01e5cb0488951dcd Mon Sep 17 00:00:00 2001 From: Chinmay Date: Fri, 5 Jul 2024 13:40:56 +0530 Subject: [PATCH 08/47] Fixed double tap to exit app bug by removing onboarding screen and splash screen from navigation stack using Get.off --- lib/app/modules/home/views/home_page_body.dart | 1 - lib/app/modules/home/views/home_view.dart | 6 ------ .../onboarding/views/onboarding_page_start_button.dart | 6 +----- lib/app/modules/splash/bindings/splash_binding.dart | 1 + lib/app/modules/splash/controllers/splash_controller.dart | 4 ++-- 5 files changed, 4 insertions(+), 14 deletions(-) diff --git a/lib/app/modules/home/views/home_page_body.dart b/lib/app/modules/home/views/home_page_body.dart index 404cf341..91c6fb9a 100644 --- a/lib/app/modules/home/views/home_page_body.dart +++ b/lib/app/modules/home/views/home_page_body.dart @@ -20,7 +20,6 @@ class HomePageBody extends StatelessWidget { controller.showInAppTour(context); return DoubleBackToCloseApp( snackBar: const SnackBar(content: Text('Tap back again to exit')), - // ignore: avoid_unnecessary_containers child: Container( color: AppSettings.isDarkMode ? Palette.kToDark.shade200 diff --git a/lib/app/modules/home/views/home_view.dart b/lib/app/modules/home/views/home_view.dart index 744a13c5..6df21a5a 100644 --- a/lib/app/modules/home/views/home_view.dart +++ b/lib/app/modules/home/views/home_view.dart @@ -33,12 +33,6 @@ class HomeView extends GetView { controller.checkForSync(context); - // var taskData = controller.searchedTasks; - - // var pendingFilter = controller.pendingFilter; - // var waitingFilter = controller.waitingFilter; - // var pendingTags = controller.pendingTags; - return Obx( () => Scaffold( appBar: HomePageAppBar( diff --git a/lib/app/modules/onboarding/views/onboarding_page_start_button.dart b/lib/app/modules/onboarding/views/onboarding_page_start_button.dart index 972a1314..b7b2cbdc 100644 --- a/lib/app/modules/onboarding/views/onboarding_page_start_button.dart +++ b/lib/app/modules/onboarding/views/onboarding_page_start_button.dart @@ -16,11 +16,7 @@ class OnboardingPageStartButton extends StatelessWidget { child: ElevatedButton( onPressed: () { controller.markOnboardingAsCompleted(); - // Navigator.of(context).pushAndRemoveUntil( - // MaterialPageRoute(builder: (context) => const HomeView()), - // (Route route) => false, - // ); - Get.toNamed(Routes.HOME); + Get.offNamed(Routes.HOME); }, style: ElevatedButton.styleFrom( backgroundColor: TaskWarriorColors.black, diff --git a/lib/app/modules/splash/bindings/splash_binding.dart b/lib/app/modules/splash/bindings/splash_binding.dart index fcb9b7ca..7252c547 100644 --- a/lib/app/modules/splash/bindings/splash_binding.dart +++ b/lib/app/modules/splash/bindings/splash_binding.dart @@ -7,6 +7,7 @@ class SplashBinding extends Bindings { void dependencies() { Get.put( SplashController(), + permanent: true, ); } } diff --git a/lib/app/modules/splash/controllers/splash_controller.dart b/lib/app/modules/splash/controllers/splash_controller.dart index 05d7d5a0..7076084d 100644 --- a/lib/app/modules/splash/controllers/splash_controller.dart +++ b/lib/app/modules/splash/controllers/splash_controller.dart @@ -95,9 +95,9 @@ class SplashController extends GetxController { void sendToNextPage() async { await checkOnboardingStatus(); if (hasCompletedOnboarding.value) { - Get.toNamed(Routes.HOME); + Get.offNamed(Routes.HOME); } else { - Get.toNamed(Routes.ONBOARDING); + Get.offNamed(Routes.ONBOARDING); } } } From 07d9982291b9f3a9d11adbff36ceecf744366230 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 14:28:02 +0530 Subject: [PATCH 09/47] feat: add refresh tasks to the refresh button --- .../modules/home/views/home_page_app_bar.dart | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/app/modules/home/views/home_page_app_bar.dart b/lib/app/modules/home/views/home_page_app_bar.dart index 460087e7..763dfa4f 100644 --- a/lib/app/modules/home/views/home_page_app_bar.dart +++ b/lib/app/modules/home/views/home_page_app_bar.dart @@ -64,18 +64,22 @@ class HomePageAppBar extends StatelessWidget implements PreferredSizeWidget { var e = await CredentialsStorage.getEncryptionSecret(); if (c != null && e != null) { try { - List tasks = await fetchTasks(c, e); - print(tasks.toList()); - await updateTasksInDatabase(tasks); - print('Tasks updated successfully'); - Navigator.pushReplacement( - context, - PageRouteBuilder( - pageBuilder: (context, animation1, animation2) => - const HomeView(), - transitionDuration: Duration.zero, - reverseTransitionDuration: Duration.zero, - )); + // List tasks = await fetchTasks(c, e); + // print( + // '///////////////////////////////////////////////////////////'); + // print(tasks.toList()); + // await updateTasksInDatabase(tasks); + // print('Tasks updated successfully'); + // controller.fetchTasksFromDB(); + controller.refreshTasks(c, e); + // Navigator.pushReplacement( + // context, + // PageRouteBuilder( + // pageBuilder: (context, animation1, animation2) => + // const HomeView(), + // transitionDuration: Duration.zero, + // reverseTransitionDuration: Duration.zero, + // )); } catch (e) { print('Failed to update tasks: $e'); ScaffoldMessenger.of(context).showSnackBar( From 0942a26fd88ad547610fd4084dd89bd2de3896e7 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 14:34:12 +0530 Subject: [PATCH 10/47] fix: api service --- lib/api_service.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/api_service.dart b/lib/api_service.dart index f6188851..fbd699f3 100644 --- a/lib/api_service.dart +++ b/lib/api_service.dart @@ -67,12 +67,12 @@ class Tasks { } } -String baseUrl = 'YOUR_IP'; -String origin = 'CONTAINER_ORIGIN'; +String baseUrl = 'http://YOUR_IP:8000'; +String origin = 'http://localhost:8080'; Future> fetchTasks(String uuid, String encryptionSecret) async { String url = - '$baseUrl/tasks?email=$origin&origin=$origin&UUID=$uuid&encryptionSecret=$encryptionSecret'; + '$baseUrl/tasks?email=email&origin=$origin&UUID=$uuid&encryptionSecret=$encryptionSecret'; var response = await http.get(Uri.parse(url), headers: { "Content-Type": "application/json", From 5193d4476458897e8c1ee4e0492952f33ed5a536 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 14:34:38 +0530 Subject: [PATCH 11/47] feat: load tasks from Db anad sync tasks on init if enabled --- .../home/controllers/home_controller.dart | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 167f47e9..8532008a 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -23,6 +23,7 @@ import 'package:taskwarrior/app/tour/filter_drawer_tour.dart'; import 'package:taskwarrior/app/tour/home_page_tour.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/language/supported_language.dart'; +import 'package:taskwarrior/app/utils/taskchampion/taskchampion.dart'; import 'package:taskwarrior/app/utils/taskfunctions/comparator.dart'; import 'package:taskwarrior/app/utils/taskfunctions/projects.dart'; import 'package:taskwarrior/app/utils/taskfunctions/query.dart'; @@ -50,6 +51,7 @@ class HomeController extends GetxController { final Rx selectedLanguage = SupportedLanguage.english.obs; final ScrollController scrollController = ScrollController(); final RxBool showbtn = false.obs; + var tasks = [].obs; @override void onInit() { @@ -69,6 +71,7 @@ class HomeController extends GetxController { } getUniqueProjects(); _loadTaskChampion(); + fetchTasksFromDB(); } Future> getUniqueProjects() async { @@ -78,6 +81,28 @@ class HomeController extends GetxController { return uniqueProjects; } + Future deleteAllTasksInDB() async { + var taskDatabase = TaskDatabase(); + await taskDatabase.deleteAllTasksInDB(); + debugPrint('Deleted all tasks from db'); + } + + Future refreshTasks(String clientId, String encryptionSecret) async { + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + List tasksFromServer = await fetchTasks(clientId, encryptionSecret); + await updateTasksInDatabase(tasksFromServer); + List fetchedTasks = await taskDatabase.fetchTasksFromDatabase(); + tasks.value = fetchedTasks; + } + + Future fetchTasksFromDB() async { + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + List fetchedTasks = await taskDatabase.fetchTasksFromDatabase(); + tasks.value = fetchedTasks; + } + Future _loadTaskChampion() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); taskchampion.value = prefs.getBool('taskchampion') ?? false; @@ -440,9 +465,12 @@ class HomeController extends GetxController { final SharedPreferences prefs = await SharedPreferences.getInstance(); bool? value; value = prefs.getBool('sync-onStart') ?? false; - + String? clientId, encryptionSecret; + clientId = await CredentialsStorage.getClientId(); + encryptionSecret = await CredentialsStorage.getEncryptionSecret(); if (value) { synchronize(context, false); + refreshTasks(clientId!, encryptionSecret!); } else {} } From d6a0a26579a76700692f2c47cb159da5bc0c92ff Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 14:35:09 +0530 Subject: [PATCH 12/47] fix: update tasks without reload --- lib/app/modules/home/views/show_tasks.dart | 430 ++++++++++----------- 1 file changed, 196 insertions(+), 234 deletions(-) diff --git a/lib/app/modules/home/views/show_tasks.dart b/lib/app/modules/home/views/show_tasks.dart index bde8de80..a2067f7b 100644 --- a/lib/app/modules/home/views/show_tasks.dart +++ b/lib/app/modules/home/views/show_tasks.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:taskwarrior/api_service.dart'; +import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart'; import 'package:taskwarrior/app/modules/home/views/show_details.dart'; import 'package:taskwarrior/app/utils/constants/palette.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; @@ -29,245 +31,217 @@ class TaskViewBuilder extends StatelessWidget { TaskDatabase taskDatabase = TaskDatabase(); await taskDatabase.open(); callback(taskDatabase, uuid, encryptionSecret); + // taskDatabase.printDatabaseContents(); } @override Widget build(BuildContext context) { - return FutureBuilder( - future: _loadCredentials((taskDatabase, uuid, encryptionSecret) {}), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } else if (snapshot.hasError) { - return Center(child: Text('Error: ${snapshot.error}')); - } else { - return FutureBuilder>( - future: _fetchTasks(), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } else if (snapshot.hasError) { - return Center(child: Text('Error: ${snapshot.error}')); - } else if (!snapshot.hasData || snapshot.data!.isEmpty) { - return const Center(child: Text('No tasks available')); - } else { - // Filter tasks based on the selected project - List tasks = List.from(snapshot.data!); - if (project != 'All Projects') { - tasks = - tasks.where((task) => task.project == project).toList(); - } else { - tasks = List.from(snapshot.data!); - } + final HomeController taskController = Get.find(); + + return Obx(() { + List tasks = List.from(taskController.tasks); - // Apply other filters and sorting - tasks.sort((a, b) => b.id.compareTo(a.id)); + // Filter tasks based on the selected project + if (project != 'All Projects') { + tasks = tasks.where((task) => task.project == project).toList(); + } else { + tasks = List.from(tasks); + } - tasks = tasks.where((task) { - if (pendingFilter) { - return task.status == 'pending'; - } else { - return task.status == 'completed'; - } - }).toList(); + // Apply other filters and sorting + tasks.sort((a, b) => b.id.compareTo(a.id)); - // Apply sorting based on selectedSort - tasks.sort((a, b) { - switch (selectedSort) { - case 'Created+': - return a.entry.compareTo(b.entry); - case 'Created-': - return b.entry.compareTo(a.entry); - case 'Modified+': - return a.modified!.compareTo(b.modified!); - case 'Modified-': - return b.modified!.compareTo(a.modified!); - case 'Due till+': - return a.due!.compareTo(b.due!); - case 'Due till-': - return b.due!.compareTo(a.due!); - case 'Priority-': - return b.priority!.compareTo(a.priority!); - case 'Priority+': - return a.priority!.compareTo(b.priority!); - case 'Project+': - return a.project!.compareTo(b.project!); - case 'Project-': - return b.project!.compareTo(a.project!); - case 'Urgency-': - return b.urgency!.compareTo(a.urgency!); - case 'Urgency+': - return a.urgency!.compareTo(b.urgency!); - default: - return 0; - } - }); + tasks = tasks.where((task) { + if (pendingFilter) { + return task.status == 'pending'; + } else { + return task.status == 'completed'; + } + }).toList(); + // Apply sorting based on selectedSort + tasks.sort((a, b) { + switch (selectedSort) { + case 'Created+': + return a.entry.compareTo(b.entry); + case 'Created-': + return b.entry.compareTo(a.entry); + case 'Modified+': + return a.modified!.compareTo(b.modified!); + case 'Modified-': + return b.modified!.compareTo(a.modified!); + case 'Due till+': + return a.due!.compareTo(b.due!); + case 'Due till-': + return b.due!.compareTo(a.due!); + case 'Priority-': + return b.priority!.compareTo(a.priority!); + case 'Priority+': + return a.priority!.compareTo(b.priority!); + case 'Project+': + return a.project!.compareTo(b.project!); + case 'Project-': + return b.project!.compareTo(a.project!); + case 'Urgency-': + return b.urgency!.compareTo(a.urgency!); + case 'Urgency+': + return a.urgency!.compareTo(b.urgency!); + default: + return 0; + } + }); - return Scaffold( - backgroundColor: AppSettings.isDarkMode - ? TaskWarriorColors.kprimaryBackgroundColor - : TaskWarriorColors.kLightPrimaryBackgroundColor, - body: tasks.isEmpty - ? Padding( - padding: const EdgeInsets.all(16.0), - child: Center( - child: Text( - 'Click on the bottom right button to start adding tasks', - textAlign: TextAlign.center, + return Scaffold( + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryBackgroundColor + : TaskWarriorColors.kLightPrimaryBackgroundColor, + body: tasks.isEmpty + ? Padding( + padding: const EdgeInsets.all(16.0), + child: Center( + child: Text( + 'Click on the bottom right button to start adding tasks', + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + fontSize: TaskWarriorFonts.fontSizeLarge, + color: AppSettings.isDarkMode + ? TaskWarriorColors.kLightPrimaryBackgroundColor + : TaskWarriorColors.kprimaryBackgroundColor, + ), + ), + ), + ) + : ListView.builder( + shrinkWrap: true, + padding: EdgeInsets.only( + top: 4, + left: 2, + right: 2, + bottom: MediaQuery.of(context).size.height * 0.1, + ), + itemCount: tasks.length, + itemBuilder: (context, index) { + Tasks task = tasks[index]; + return Slidable( + startActionPane: ActionPane( + motion: const BehindMotion(), + children: [ + SlidableAction( + onPressed: (context) { + _markTaskAsCompleted(task.uuid!); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Task Marked As Completed. Refresh to view changes!', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors + .kLightPrimaryTextColor, + ), + ), + ), + ); + }, + icon: Icons.done, + label: "COMPLETE", + backgroundColor: TaskWarriorColors.green, + ), + ], + ), + endActionPane: ActionPane( + motion: const DrawerMotion(), + children: [ + SlidableAction( + onPressed: (context) { + _markTaskAsDeleted(task.uuid!); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Task Marked As Deleted. Refresh to view changes!', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors + .kLightPrimaryTextColor, + ), + ), + ), + ); + }, + icon: Icons.delete, + label: "DELETE", + backgroundColor: TaskWarriorColors.red, + ), + ], + ), + child: Card( + color: AppSettings.isDarkMode + ? Palette.kToDark + : TaskWarriorColors.white, + child: InkWell( + splashColor: AppSettings.isDarkMode + ? TaskWarriorColors.black + : TaskWarriorColors.borderColor, + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => TaskDetails(task: task), + ), + ), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: AppSettings.isDarkMode + ? TaskWarriorColors.borderColor + : TaskWarriorColors.black, + ), + color: AppSettings.isDarkMode + ? Palette.kToDark + : TaskWarriorColors.white, + borderRadius: BorderRadius.circular(8.0), + boxShadow: const [ + BoxShadow( + color: Colors.black12, + blurRadius: 4.0, + offset: Offset(0, 2), + ), + ], + ), + child: ListTile( + leading: CircleAvatar( + backgroundColor: + _getPriorityColor(task.priority!), + radius: 8, + ), + title: Text( + task.description, + maxLines: 1, + overflow: TextOverflow.ellipsis, style: GoogleFonts.poppins( - fontSize: TaskWarriorFonts.fontSizeLarge, color: AppSettings.isDarkMode ? TaskWarriorColors - .kLightPrimaryBackgroundColor + .kLightDialogBackGroundColor : TaskWarriorColors.kprimaryBackgroundColor, ), ), - ), - ) - : ListView.builder( - shrinkWrap: true, - padding: EdgeInsets.only( - top: 4, - left: 2, - right: 2, - bottom: MediaQuery.of(context).size.height * 0.1, - ), - itemCount: tasks.length, - itemBuilder: (context, index) { - Tasks task = tasks[index]; - return Slidable( - startActionPane: ActionPane( - motion: const BehindMotion(), - children: [ - SlidableAction( - onPressed: (context) { - _markTaskAsCompleted(task.uuid!); - ScaffoldMessenger.of(context) - .showSnackBar( - SnackBar( - content: Text( - 'Task Marked As Completed. Refresh to view changes!', - style: TextStyle( - color: AppSettings.isDarkMode - ? TaskWarriorColors - .kprimaryTextColor - : TaskWarriorColors - .kLightPrimaryTextColor, - ), - ), - ), - ); - }, - icon: Icons.done, - label: "COMPLETE", - backgroundColor: TaskWarriorColors.green, - ), - ], - ), - endActionPane: ActionPane( - motion: const DrawerMotion(), - children: [ - SlidableAction( - onPressed: (context) { - _markTaskAsDeleted(task.uuid!); - ScaffoldMessenger.of(context) - .showSnackBar( - SnackBar( - content: Text( - 'Task Marked As Deleted. Refresh to view changes!', - style: TextStyle( - color: AppSettings.isDarkMode - ? TaskWarriorColors - .kprimaryTextColor - : TaskWarriorColors - .kLightPrimaryTextColor, - ), - ), - ), - ); - }, - icon: Icons.delete, - label: "DELETE", - backgroundColor: TaskWarriorColors.red, - ), - ], - ), - child: Card( + subtitle: Text( + 'Urgency: ${task.urgency!.floorToDouble()} | Status: ${task.status}', + style: GoogleFonts.poppins( color: AppSettings.isDarkMode - ? Palette.kToDark - : TaskWarriorColors.white, - child: InkWell( - splashColor: AppSettings.isDarkMode - ? TaskWarriorColors.black - : TaskWarriorColors.borderColor, - onTap: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - TaskDetails(task: task), - ), - ), - child: Container( - decoration: BoxDecoration( - border: Border.all( - color: AppSettings.isDarkMode - ? TaskWarriorColors.borderColor - : TaskWarriorColors.black, - ), - color: AppSettings.isDarkMode - ? Palette.kToDark - : TaskWarriorColors.white, - borderRadius: BorderRadius.circular(8.0), - boxShadow: const [ - BoxShadow( - color: Colors.black12, - blurRadius: 4.0, - offset: Offset(0, 2), - ), - ], - ), - child: ListTile( - leading: CircleAvatar( - backgroundColor: - _getPriorityColor(task.priority!), - radius: 8, - ), - title: Text( - task.description, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: GoogleFonts.poppins( - color: AppSettings.isDarkMode - ? TaskWarriorColors - .kLightDialogBackGroundColor - : TaskWarriorColors - .kprimaryBackgroundColor, - ), - ), - subtitle: Text( - 'Urgency: ${task.urgency!.floorToDouble()} | Status: ${task.status}', - style: GoogleFonts.poppins( - color: AppSettings.isDarkMode - ? TaskWarriorColors - .ksecondaryTextColor - : TaskWarriorColors - .kLightSecondaryTextColor, - ), - ), - ), - ), - ), + ? TaskWarriorColors.ksecondaryTextColor + : TaskWarriorColors + .kLightSecondaryTextColor, ), - ); - }, + ), + ), ), - ); - } - }, - ); - } - }, - ); + ), + ), + ); + }, + ), + ); + }); } Future> _fetchTasks() async { @@ -276,18 +250,6 @@ class TaskViewBuilder extends StatelessWidget { return await taskDatabase.fetchTasksFromDatabase(); } - void _updateTasksInDatabase(List tasks) async { - TaskDatabase taskDatabase = TaskDatabase(); - await taskDatabase.open(); - // Perform update logic - } - - void _findTasksWithoutUUIDs() async { - TaskDatabase taskDatabase = TaskDatabase(); - await taskDatabase.open(); - // Perform find logic - } - void _markTaskAsCompleted(String uuid) async { String clientId = (await CredentialsStorage.getClientId()) ?? ''; String encryptionSecret = From 06a71e77a915b593b42766696cd467f522af8b59 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 14:35:30 +0530 Subject: [PATCH 13/47] feat: delete all tasks from DB --- lib/app/modules/home/views/nav_drawer.dart | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/lib/app/modules/home/views/nav_drawer.dart b/lib/app/modules/home/views/nav_drawer.dart index fca2f22b..56096812 100644 --- a/lib/app/modules/home/views/nav_drawer.dart +++ b/lib/app/modules/home/views/nav_drawer.dart @@ -101,6 +101,66 @@ class NavDrawer extends StatelessWidget { }, ), ), + Visibility( + visible: homeController.taskchampion.value, + child: NavDrawerMenuItem( + icon: Icons.delete, + text: 'Delete tasks', + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return Utils.showAlertDialog( + title: Text( + 'Delete All Tasks?', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + content: Text( + 'The action is irreversible and will delete all the tasks that are stored locally.', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + actions: [ + TextButton( + child: Text( + 'Cancel', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + onPressed: () { + Navigator.of(context).pop(); // Close the dialog + }, + ), + TextButton( + child: Text( + 'Confirm', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + onPressed: () { + homeController.deleteAllTasksInDB(); + Navigator.of(context).pop(); // Close the dialog + }, + ), + ], + ); + }, + ); + }), + ), Visibility( visible: !homeController.taskchampion.value, child: Obx( From 92469373d4354df7346aebe1c26885556f52cf37 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 14:56:33 +0530 Subject: [PATCH 14/47] fix: reports tour --- .../reports/controllers/reports_tour.dart | 112 ------------------ .../reports/views/reports_view_taskc.dart | 8 +- 2 files changed, 6 insertions(+), 114 deletions(-) delete mode 100644 lib/app/modules/reports/controllers/reports_tour.dart diff --git a/lib/app/modules/reports/controllers/reports_tour.dart b/lib/app/modules/reports/controllers/reports_tour.dart deleted file mode 100644 index 51f17360..00000000 --- a/lib/app/modules/reports/controllers/reports_tour.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; - -List reportsDrawer({ - required GlobalKey daily, - required GlobalKey weekly, - required GlobalKey monthly, -}) { - List targets = []; - - // daily - targets.add( - TargetFocus( - keyTarget: daily, - alignSkip: Alignment.topRight, - radius: 10, - shape: ShapeLightFocus.RRect, - contents: [ - TargetContent( - align: ContentAlign.bottom, - builder: (context, controller) { - return Container( - alignment: Alignment.center, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Access your daily task report here", - textAlign: TextAlign.center, - style: GoogleFonts.poppins( - color: Colors.white, - ), - ), - ], - ), - ); - }, - ), - ], - ), - ); - - // weekly - targets.add( - TargetFocus( - keyTarget: weekly, - alignSkip: Alignment.topRight, - radius: 10, - shape: ShapeLightFocus.RRect, - contents: [ - TargetContent( - align: ContentAlign.bottom, - builder: (context, controller) { - return Container( - alignment: Alignment.center, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Access your weekly task reports here", - textAlign: TextAlign.center, - style: GoogleFonts.poppins( - color: Colors.white, - ), - ), - ], - ), - ); - }, - ), - ], - ), - ); - - // monthly - targets.add( - TargetFocus( - keyTarget: monthly, - alignSkip: Alignment.bottomCenter, - radius: 10, - shape: ShapeLightFocus.RRect, - contents: [ - TargetContent( - align: ContentAlign.bottom, - builder: (context, controller) { - return Container( - alignment: Alignment.center, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Access your monthly task reports here", - textAlign: TextAlign.center, - style: GoogleFonts.poppins( - color: Colors.white, - ), - ), - ], - ), - ); - }, - ), - ], - ), - ); - - return targets; -} diff --git a/lib/app/modules/reports/views/reports_view_taskc.dart b/lib/app/modules/reports/views/reports_view_taskc.dart index 277a7c03..76f82fd4 100644 --- a/lib/app/modules/reports/views/reports_view_taskc.dart +++ b/lib/app/modules/reports/views/reports_view_taskc.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:taskwarrior/api_service.dart'; +import 'package:taskwarrior/app/modules/reports/controllers/reports_controller.dart'; import 'package:taskwarrior/app/modules/reports/controllers/reports_tour_controller.dart'; import 'package:taskwarrior/app/modules/reports/views/burn_down_daily_taskc.dart'; import 'package:taskwarrior/app/modules/reports/views/burn_down_monthly_taskc.dart'; @@ -29,7 +31,7 @@ class _ReportsHomeTaskcState extends State bool isSaved = false; late TutorialCoachMark tutorialCoachMark; - + late ReportsController reportsController; int _selectedIndex = 0; late TaskDatabase taskDatabase; List allTasks = []; @@ -75,7 +77,9 @@ class _ReportsHomeTaskcState extends State super.initState(); _initReportsTour(); _showReportsTour(); - + reportsController = Get.find(); + reportsController.initReportsTour(); + reportsController.showReportsTour(context); _tabController = TabController(length: 3, vsync: this); // Initialize the database and fetch data From 3e493df2347a39f4ab9cd2b752c45d78af15cde5 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 15:01:05 +0530 Subject: [PATCH 15/47] fix: fixed linting issues --- .../controllers/detail_route_controller.dart | 4 +++- .../detailRoute/views/detail_route_view.dart | 2 ++ .../home/controllers/home_controller.dart | 2 +- .../home/views/add_task_bottom_sheet.dart | 11 +++++------ .../home/views/filter_drawer_home_page.dart | 2 ++ .../modules/home/views/home_page_app_bar.dart | 6 ++---- lib/app/modules/home/views/show_tasks.dart | 17 ----------------- .../views/manage_task_server_page_app_bar.dart | 2 ++ .../reports/controllers/reports_controller.dart | 2 ++ .../controllers/settings_controller.dart | 3 ++- ...ettings_page_select_directory_list_tile.dart | 2 ++ .../splash/controllers/splash_controller.dart | 2 ++ lib/app/routes/app_pages.dart | 2 ++ lib/app/routes/app_routes.dart | 2 ++ 14 files changed, 29 insertions(+), 30 deletions(-) diff --git a/lib/app/modules/detailRoute/controllers/detail_route_controller.dart b/lib/app/modules/detailRoute/controllers/detail_route_controller.dart index eb26f4ca..2a536712 100644 --- a/lib/app/modules/detailRoute/controllers/detail_route_controller.dart +++ b/lib/app/modules/detailRoute/controllers/detail_route_controller.dart @@ -1,3 +1,5 @@ +// ignore_for_file: depend_on_referenced_packages + import 'package:built_collection/built_collection.dart'; import 'package:get/get.dart'; import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart'; @@ -46,7 +48,7 @@ class DetailRouteController extends GetxController { // 'status': controller.modify.draft.status, // 'entry': controller.modify.draft.entry, // 'modified': controller.modify.draft.modified, - // 'start': controller.modify.draft.start, + // 'start': controller.modify.draft.start, // 'end': controller.modify.draft.end, // 'due': controller.dueValue.value, // 'wait': controller.modify.draft.wait, diff --git a/lib/app/modules/detailRoute/views/detail_route_view.dart b/lib/app/modules/detailRoute/views/detail_route_view.dart index a947f48a..5568d7c6 100644 --- a/lib/app/modules/detailRoute/views/detail_route_view.dart +++ b/lib/app/modules/detailRoute/views/detail_route_view.dart @@ -1,3 +1,5 @@ +// ignore_for_file: depend_on_referenced_packages, deprecated_member_use + import 'package:built_collection/built_collection.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 8532008a..6a4488b8 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -548,7 +548,7 @@ class HomeController extends GetxController { void initLanguageAndDarkMode() { isDarkModeOn.value = AppSettings.isDarkMode; selectedLanguage.value = AppSettings.selectedLanguage; - print("called and value is${isDarkModeOn.value}"); + // print("called and value is${isDarkModeOn.value}"); } final addKey = GlobalKey(); diff --git a/lib/app/modules/home/views/add_task_bottom_sheet.dart b/lib/app/modules/home/views/add_task_bottom_sheet.dart index 6a8df7ce..13b598b1 100644 --- a/lib/app/modules/home/views/add_task_bottom_sheet.dart +++ b/lib/app/modules/home/views/add_task_bottom_sheet.dart @@ -269,7 +269,7 @@ class AddTaskBottomSheet extends StatelessWidget { initialTime: TimeOfDay.fromDateTime( homeController.due.value ?? DateTime.now()), ); - print("date$date Time : $time"); + // print("date$date Time : $time"); if (time != null) { var dateTime = date.add( Duration( @@ -277,13 +277,13 @@ class AddTaskBottomSheet extends StatelessWidget { minutes: time.minute, ), ); - print(dateTime); + // print(dateTime); homeController.due.value = dateTime.toUtc(); - print("due value ${homeController.due}"); + // print("due value ${homeController.due}"); homeController.dueString.value = DateFormat("dd-MM-yyyy HH:mm").format(dateTime); - print(homeController.dueString.value); + // print(homeController.dueString.value); if (dateTime.isBefore(DateTime.now())) { //Try changing the color. in the settings and Due display. @@ -391,7 +391,6 @@ class AddTaskBottomSheet extends StatelessWidget { ); Widget buildAddButton(BuildContext context) { - return TextButton( child: Text( "Add", @@ -402,7 +401,7 @@ class AddTaskBottomSheet extends StatelessWidget { ), ), onPressed: () async { - print(homeController.formKey.currentState); + // print(homeController.formKey.currentState); if (homeController.formKey.currentState!.validate()) { try { var task = taskParser(homeController.namecontroller.text) diff --git a/lib/app/modules/home/views/filter_drawer_home_page.dart b/lib/app/modules/home/views/filter_drawer_home_page.dart index 8a447ea6..548f8c9c 100644 --- a/lib/app/modules/home/views/filter_drawer_home_page.dart +++ b/lib/app/modules/home/views/filter_drawer_home_page.dart @@ -1,3 +1,5 @@ +// ignore_for_file: unrelated_type_equality_checks + import 'package:flutter/material.dart'; import 'package:get/get_state_manager/get_state_manager.dart'; import 'package:taskwarrior/app/models/filters.dart'; diff --git a/lib/app/modules/home/views/home_page_app_bar.dart b/lib/app/modules/home/views/home_page_app_bar.dart index 763dfa4f..645102d8 100644 --- a/lib/app/modules/home/views/home_page_app_bar.dart +++ b/lib/app/modules/home/views/home_page_app_bar.dart @@ -1,9 +1,8 @@ +// ignore_for_file: use_build_context_synchronously + import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:taskwarrior/api_service.dart'; -import 'package:taskwarrior/app/modules/home/views/home_view.dart'; - import 'package:taskwarrior/app/routes/app_pages.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/gen/fonts.gen.dart'; @@ -81,7 +80,6 @@ class HomePageAppBar extends StatelessWidget implements PreferredSizeWidget { // reverseTransitionDuration: Duration.zero, // )); } catch (e) { - print('Failed to update tasks: $e'); ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: AppSettings.isDarkMode diff --git a/lib/app/modules/home/views/show_tasks.dart b/lib/app/modules/home/views/show_tasks.dart index a2067f7b..822edcea 100644 --- a/lib/app/modules/home/views/show_tasks.dart +++ b/lib/app/modules/home/views/show_tasks.dart @@ -23,17 +23,6 @@ class TaskViewBuilder extends StatelessWidget { final bool pendingFilter; final String? project; - Future _loadCredentials( - Function(TaskDatabase, String, String) callback) async { - String uuid = (await CredentialsStorage.getClientId()) ?? ''; - String encryptionSecret = - (await CredentialsStorage.getEncryptionSecret()) ?? ''; - TaskDatabase taskDatabase = TaskDatabase(); - await taskDatabase.open(); - callback(taskDatabase, uuid, encryptionSecret); - // taskDatabase.printDatabaseContents(); - } - @override Widget build(BuildContext context) { final HomeController taskController = Get.find(); @@ -244,12 +233,6 @@ class TaskViewBuilder extends StatelessWidget { }); } - Future> _fetchTasks() async { - TaskDatabase taskDatabase = TaskDatabase(); - await taskDatabase.open(); - return await taskDatabase.fetchTasksFromDatabase(); - } - void _markTaskAsCompleted(String uuid) async { String clientId = (await CredentialsStorage.getClientId()) ?? ''; String encryptionSecret = diff --git a/lib/app/modules/manageTaskServer/views/manage_task_server_page_app_bar.dart b/lib/app/modules/manageTaskServer/views/manage_task_server_page_app_bar.dart index 0d05c240..ce35ad18 100644 --- a/lib/app/modules/manageTaskServer/views/manage_task_server_page_app_bar.dart +++ b/lib/app/modules/manageTaskServer/views/manage_task_server_page_app_bar.dart @@ -1,3 +1,5 @@ +// ignore_for_file: use_build_context_synchronously + import 'dart:math'; import 'package:flutter/foundation.dart'; diff --git a/lib/app/modules/reports/controllers/reports_controller.dart b/lib/app/modules/reports/controllers/reports_controller.dart index e5544f7c..abfe98fd 100644 --- a/lib/app/modules/reports/controllers/reports_controller.dart +++ b/lib/app/modules/reports/controllers/reports_controller.dart @@ -1,3 +1,5 @@ +// ignore_for_file: prefer_typing_uninitialized_variables + import 'dart:io'; import 'package:flutter/material.dart'; diff --git a/lib/app/modules/settings/controllers/settings_controller.dart b/lib/app/modules/settings/controllers/settings_controller.dart index c1f89163..049b37f2 100644 --- a/lib/app/modules/settings/controllers/settings_controller.dart +++ b/lib/app/modules/settings/controllers/settings_controller.dart @@ -1,10 +1,11 @@ +// ignore_for_file: depend_on_referenced_packages + import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:get/get_rx/get_rx.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:shared_preferences/shared_preferences.dart'; diff --git a/lib/app/modules/settings/views/settings_page_select_directory_list_tile.dart b/lib/app/modules/settings/views/settings_page_select_directory_list_tile.dart index d11712f5..70334a60 100644 --- a/lib/app/modules/settings/views/settings_page_select_directory_list_tile.dart +++ b/lib/app/modules/settings/views/settings_page_select_directory_list_tile.dart @@ -1,3 +1,5 @@ +// ignore_for_file: use_build_context_synchronously + import 'dart:io'; import 'package:flutter/material.dart'; diff --git a/lib/app/modules/splash/controllers/splash_controller.dart b/lib/app/modules/splash/controllers/splash_controller.dart index 05d7d5a0..c6427533 100644 --- a/lib/app/modules/splash/controllers/splash_controller.dart +++ b/lib/app/modules/splash/controllers/splash_controller.dart @@ -1,3 +1,5 @@ +// ignore_for_file: depend_on_referenced_packages + import 'dart:io'; import 'package:get/get.dart'; diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index ec084a3e..f6925604 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -1,3 +1,5 @@ +// ignore_for_file: constant_identifier_names + import 'package:get/get.dart'; import '../modules/about/bindings/about_binding.dart'; diff --git a/lib/app/routes/app_routes.dart b/lib/app/routes/app_routes.dart index 5a1af88c..5cf53cc3 100644 --- a/lib/app/routes/app_routes.dart +++ b/lib/app/routes/app_routes.dart @@ -1,3 +1,5 @@ +// ignore_for_file: constant_identifier_names + part of 'app_pages.dart'; // DO NOT EDIT. This is code generated via package:get_cli/get_cli.dart From e5c9cce20a800f3767dbb8ab53ea84a84ca1fb12 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 15:11:06 +0530 Subject: [PATCH 16/47] fix: add languages for delete tasks --- lib/app/modules/home/views/nav_drawer.dart | 14 +++++++++++--- lib/app/utils/language/english_sentences.dart | 10 ++++++++++ lib/app/utils/language/hindi_sentences.dart | 10 ++++++++++ lib/app/utils/language/marathi_sentences.dart | 10 ++++++++++ lib/app/utils/language/sentences.dart | 3 +++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/lib/app/modules/home/views/nav_drawer.dart b/lib/app/modules/home/views/nav_drawer.dart index 56096812..3822d8e9 100644 --- a/lib/app/modules/home/views/nav_drawer.dart +++ b/lib/app/modules/home/views/nav_drawer.dart @@ -105,14 +105,19 @@ class NavDrawer extends StatelessWidget { visible: homeController.taskchampion.value, child: NavDrawerMenuItem( icon: Icons.delete, - text: 'Delete tasks', + text: SentenceManager( + currentLanguage: homeController.selectedLanguage.value, + ).sentences.deleteTaskTitle, onTap: () { showDialog( context: context, builder: (BuildContext context) { return Utils.showAlertDialog( title: Text( - 'Delete All Tasks?', + SentenceManager( + currentLanguage: + homeController.selectedLanguage.value, + ).sentences.deleteTaskConfirmation, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -120,7 +125,10 @@ class NavDrawer extends StatelessWidget { ), ), content: Text( - 'The action is irreversible and will delete all the tasks that are stored locally.', + SentenceManager( + currentLanguage: + homeController.selectedLanguage.value, + ).sentences.deleteTaskWarning, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white diff --git a/lib/app/utils/language/english_sentences.dart b/lib/app/utils/language/english_sentences.dart index 866e7e4d..4a799845 100644 --- a/lib/app/utils/language/english_sentences.dart +++ b/lib/app/utils/language/english_sentences.dart @@ -196,4 +196,14 @@ class EnglishSentences extends Sentences { @override String get ccsyncCredentials => 'CCync credentials'; + + @override + String get deleteTaskConfirmation => 'Delete Tasks'; + + @override + String get deleteTaskTitle => 'Delete All Tasks?'; + + @override + String get deleteTaskWarning => + 'The action is irreversible and will delete all the tasks that are stored locally.'; } diff --git a/lib/app/utils/language/hindi_sentences.dart b/lib/app/utils/language/hindi_sentences.dart index 87ce9d39..99a5cadb 100644 --- a/lib/app/utils/language/hindi_sentences.dart +++ b/lib/app/utils/language/hindi_sentences.dart @@ -198,4 +198,14 @@ class HindiSentences extends Sentences { @override String get ccsyncCredentials => 'CCync क्रेडेन्शियल'; + + @override + String get deleteTaskConfirmation => 'कार्य हटाएं'; + + @override + String get deleteTaskTitle => 'सभी कार्य हटाएं?'; + + @override + String get deleteTaskWarning => + 'यह क्रिया अपरिवर्तनीय है और यह सभी स्थानीय रूप से संग्रहीत कार्यों को हटा देगी।'; } diff --git a/lib/app/utils/language/marathi_sentences.dart b/lib/app/utils/language/marathi_sentences.dart index 7111029e..27bbaa91 100644 --- a/lib/app/utils/language/marathi_sentences.dart +++ b/lib/app/utils/language/marathi_sentences.dart @@ -197,4 +197,14 @@ class MarathiSentences extends Sentences { @override String get ccsyncCredentials => 'CCync क्रेडेन्शियल'; + + @override + String get deleteTaskConfirmation => 'कार्य हटवा'; + + @override + String get deleteTaskTitle => 'सर्व कार्य हटवायचे का?'; + + @override + String get deleteTaskWarning => + 'ही क्रिया अपरिवर्तनीय आहे आणि हे सर्व स्थानिक पातळीवर संग्रहित केलेले कार्य हटवेल.'; } diff --git a/lib/app/utils/language/sentences.dart b/lib/app/utils/language/sentences.dart index 2ad3b3f0..4939cd3c 100644 --- a/lib/app/utils/language/sentences.dart +++ b/lib/app/utils/language/sentences.dart @@ -47,6 +47,9 @@ abstract class Sentences { String get navDrawerAbout; String get navDrawerSettings; String get ccsyncCredentials; + String get deleteTaskTitle; + String get deleteTaskConfirmation; + String get deleteTaskWarning; String get navDrawerExit; String get detailPageDescription; From bdfbdbf82fae3488ed9c9e9e76ed23d0b6460658 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Fri, 5 Jul 2024 19:38:30 +0530 Subject: [PATCH 17/47] fix: fix merge conflict --- lib/app/modules/home/views/tas_list_item.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/app/modules/home/views/tas_list_item.dart b/lib/app/modules/home/views/tas_list_item.dart index 95c4c369..5ad6e023 100644 --- a/lib/app/modules/home/views/tas_list_item.dart +++ b/lib/app/modules/home/views/tas_list_item.dart @@ -32,6 +32,7 @@ class TaskListItem extends StatelessWidget { @override Widget build(BuildContext context) { + // ignore: unused_element void saveChanges() async { var now = DateTime.now().toUtc(); modify.save( From 0e9c5b57e78ddedaa991f701628a2c43a60e1499 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 6 Jul 2024 13:17:06 +0530 Subject: [PATCH 18/47] fix: remove dependancy on redundant reports_tour_controller --- .../controllers/reports_tour_controller.dart | 20 ---------- .../reports/views/reports_view_taskc.dart | 40 ------------------- 2 files changed, 60 deletions(-) delete mode 100644 lib/app/modules/reports/controllers/reports_tour_controller.dart diff --git a/lib/app/modules/reports/controllers/reports_tour_controller.dart b/lib/app/modules/reports/controllers/reports_tour_controller.dart deleted file mode 100644 index 35e3162b..00000000 --- a/lib/app/modules/reports/controllers/reports_tour_controller.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:shared_preferences/shared_preferences.dart'; - -class SaveReportsTour { - Future data = SharedPreferences.getInstance(); - - void saveReportsTourStatus() async { - final value = await data; - value.setBool('reports_tour', true); - } - - Future getReportsTourStatus() async { - final value = await data; - if (value.containsKey('reports_tour')) { - bool? getData = value.getBool('reports_tour'); - return getData!; - } else { - return false; - } - } -} diff --git a/lib/app/modules/reports/views/reports_view_taskc.dart b/lib/app/modules/reports/views/reports_view_taskc.dart index 76f82fd4..5e7f7684 100644 --- a/lib/app/modules/reports/views/reports_view_taskc.dart +++ b/lib/app/modules/reports/views/reports_view_taskc.dart @@ -3,11 +3,9 @@ import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:taskwarrior/api_service.dart'; import 'package:taskwarrior/app/modules/reports/controllers/reports_controller.dart'; -import 'package:taskwarrior/app/modules/reports/controllers/reports_tour_controller.dart'; import 'package:taskwarrior/app/modules/reports/views/burn_down_daily_taskc.dart'; import 'package:taskwarrior/app/modules/reports/views/burn_down_monthly_taskc.dart'; import 'package:taskwarrior/app/modules/reports/views/burn_down_weekly_taskc.dart'; -import 'package:taskwarrior/app/tour/reports_page_tour.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; @@ -36,47 +34,9 @@ class _ReportsHomeTaskcState extends State late TaskDatabase taskDatabase; List allTasks = []; - void _initReportsTour() { - tutorialCoachMark = TutorialCoachMark( - targets: reportsDrawer( - daily: daily, - weekly: weekly, - monthly: monthly, - ), - colorShadow: TaskWarriorColors.black, - paddingFocus: 10, - opacityShadow: 0.8, - hideSkip: true, - onFinish: () { - SaveReportsTour().saveReportsTourStatus(); - }, - ); - } - - void _showReportsTour() { - Future.delayed( - const Duration(seconds: 2), - () { - SaveReportsTour().getReportsTourStatus().then((value) => { - if (value == false) - { - tutorialCoachMark.show(context: context), - } - else - { - // ignore: avoid_print - print('User has seen this page'), - } - }); - }, - ); - } - @override void initState() { super.initState(); - _initReportsTour(); - _showReportsTour(); reportsController = Get.find(); reportsController.initReportsTour(); reportsController.showReportsTour(context); From 7becfecf93295ec3adfae1677ad55518682fc95f Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 6 Jul 2024 13:32:00 +0530 Subject: [PATCH 19/47] fix: make reports tour stateless --- .../reports/views/reports_view_taskc.dart | 268 ++++++++---------- 1 file changed, 121 insertions(+), 147 deletions(-) diff --git a/lib/app/modules/reports/views/reports_view_taskc.dart b/lib/app/modules/reports/views/reports_view_taskc.dart index 5e7f7684..7b5cf61e 100644 --- a/lib/app/modules/reports/views/reports_view_taskc.dart +++ b/lib/app/modules/reports/views/reports_view_taskc.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:taskwarrior/api_service.dart'; import 'package:taskwarrior/app/modules/reports/controllers/reports_controller.dart'; @@ -9,165 +8,140 @@ import 'package:taskwarrior/app/modules/reports/views/burn_down_weekly_taskc.dar import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; -import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; -class ReportsHomeTaskc extends StatefulWidget { - const ReportsHomeTaskc({ - super.key, - }); +class ReportsHomeTaskc extends StatelessWidget { + final ReportsController reportsController = ReportsController(); + final TaskDatabase taskDatabase = TaskDatabase(); - @override - State createState() => _ReportsHomeTaskcState(); -} - -class _ReportsHomeTaskcState extends State - with TickerProviderStateMixin { - late TabController _tabController; - final GlobalKey daily = GlobalKey(); - final GlobalKey weekly = GlobalKey(); - final GlobalKey monthly = GlobalKey(); + ReportsHomeTaskc({super.key}); - bool isSaved = false; - late TutorialCoachMark tutorialCoachMark; - late ReportsController reportsController; - int _selectedIndex = 0; - late TaskDatabase taskDatabase; - List allTasks = []; - - @override - void initState() { - super.initState(); - reportsController = Get.find(); - reportsController.initReportsTour(); - reportsController.showReportsTour(context); - _tabController = TabController(length: 3, vsync: this); - - // Initialize the database and fetch data - taskDatabase = TaskDatabase(); - taskDatabase.open().then((_) { - taskDatabase.fetchTasksFromDatabase().then((tasks) { - setState(() { - allTasks = tasks; - }); - }); - }); + Future> fetchTasks() async { + await taskDatabase.open(); + return await taskDatabase.fetchTasksFromDatabase(); } @override Widget build(BuildContext context) { - double height = MediaQuery.of(context).size.height; // Screen height + double height = MediaQuery.of(context).size.height; + reportsController.initReportsTour(); + reportsController.showReportsTour(context); + return FutureBuilder>( + future: fetchTasks(), + builder: (context, snapshot) { + List allTasks = snapshot.data ?? []; - return Scaffold( - appBar: AppBar( - backgroundColor: TaskWarriorColors.kprimaryBackgroundColor, - title: Text( - 'Reports', - style: GoogleFonts.poppins(color: TaskWarriorColors.white), - ), - leading: GestureDetector( - onTap: () { - Navigator.pop(context); - }, - child: Icon( - Icons.chevron_left, - color: TaskWarriorColors.white, - ), - ), - bottom: PreferredSize( - preferredSize: Size.fromHeight( - height * 0.1), // Adjust the preferred height as needed - child: TabBar( - controller: _tabController, - labelColor: TaskWarriorColors.white, - labelStyle: GoogleFonts.poppins( - fontWeight: TaskWarriorFonts.medium, - fontSize: TaskWarriorFonts.fontSizeSmall, + return Scaffold( + appBar: AppBar( + backgroundColor: TaskWarriorColors.kprimaryBackgroundColor, + title: Text( + 'Reports', + style: GoogleFonts.poppins(color: TaskWarriorColors.white), ), - unselectedLabelStyle: GoogleFonts.poppins( - fontWeight: TaskWarriorFonts.light, - ), - onTap: (value) { - setState(() { - _selectedIndex = value; - }); - }, - tabs: [ - Tab( - key: daily, - icon: const Icon(Icons.schedule), - text: 'Daily', - iconMargin: const EdgeInsets.only(bottom: 0.0), - ), - Tab( - key: weekly, - icon: const Icon(Icons.today), - text: 'Weekly', - iconMargin: const EdgeInsets.only(bottom: 0.0), - ), - Tab( - key: monthly, - icon: const Icon(Icons.date_range), - text: 'Monthly', - iconMargin: const EdgeInsets.only(bottom: 0.0), + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon( + Icons.chevron_left, + color: TaskWarriorColors.white, ), - ], - ), - ), - ), - backgroundColor: AppSettings.isDarkMode - ? TaskWarriorColors.kprimaryBackgroundColor - : TaskWarriorColors.white, - body: allTasks.isEmpty - ? Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Icon( - Icons.heart_broken, - color: AppSettings.isDarkMode - ? TaskWarriorColors.white - : TaskWarriorColors.black, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'No Task found', - style: GoogleFonts.poppins( - fontWeight: TaskWarriorFonts.medium, - fontSize: TaskWarriorFonts.fontSizeSmall, - color: AppSettings.isDarkMode - ? TaskWarriorColors.white - : TaskWarriorColors.black, - ), - ), - ], + ), + bottom: PreferredSize( + preferredSize: Size.fromHeight(height * 0.1), + child: TabBar( + controller: reportsController.tabController, + labelColor: TaskWarriorColors.white, + labelStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.medium, + fontSize: TaskWarriorFonts.fontSizeSmall, ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Add a task to see reports', - style: GoogleFonts.poppins( - fontWeight: TaskWarriorFonts.light, - fontSize: TaskWarriorFonts.fontSizeSmall, - color: AppSettings.isDarkMode - ? TaskWarriorColors.white - : TaskWarriorColors.black, - ), - ), - ], + unselectedLabelStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.light, ), - ], - ) - : IndexedStack( - index: _selectedIndex, - children: const [ - BurnDownDailyTaskc(), - BurnDownWeeklyTask(), - BurnDownMonthlyTaskc(), - ], + onTap: (value) { + reportsController.selectedIndex.value = value; + }, + tabs: [ + Tab( + key: reportsController.daily, + icon: const Icon(Icons.schedule), + text: 'Daily', + iconMargin: const EdgeInsets.only(bottom: 0.0), + ), + Tab( + key: reportsController.weekly, + icon: const Icon(Icons.today), + text: 'Weekly', + iconMargin: const EdgeInsets.only(bottom: 0.0), + ), + Tab( + key: reportsController.monthly, + icon: const Icon(Icons.date_range), + text: 'Monthly', + iconMargin: const EdgeInsets.only(bottom: 0.0), + ), + ], + ), ), + ), + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryBackgroundColor + : TaskWarriorColors.white, + body: snapshot.connectionState == ConnectionState.waiting + ? const Center(child: CircularProgressIndicator()) + : allTasks.isEmpty + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + Icons.heart_broken, + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'No Task found', + style: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.medium, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Add a task to see reports', + style: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.light, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode + ? TaskWarriorColors.white + : TaskWarriorColors.black, + ), + ), + ], + ), + ], + ) + : IndexedStack( + index: reportsController.selectedIndex.value, + children: const [ + BurnDownDailyTaskc(), + BurnDownWeeklyTask(), + BurnDownMonthlyTaskc(), + ], + ), + ); + }, ); } } From 8aa5612ed0d80c88908a9b5c43bf9547b63e65f6 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 6 Jul 2024 15:17:24 +0530 Subject: [PATCH 20/47] fix: fixed reports for taskc --- lib/app/modules/home/views/nav_drawer.dart | 36 ++- .../controllers/reports_controller.dart | 8 +- .../reports/views/burn_down_daily_taskc.dart | 247 ++++++++-------- .../views/burn_down_monthly_taskc.dart | 260 ++++++++--------- .../reports/views/burn_down_weekly_taskc.dart | 273 +++++++++--------- .../reports/views/reports_view_taskc.dart | 21 +- 6 files changed, 430 insertions(+), 415 deletions(-) diff --git a/lib/app/modules/home/views/nav_drawer.dart b/lib/app/modules/home/views/nav_drawer.dart index 3822d8e9..2904963d 100644 --- a/lib/app/modules/home/views/nav_drawer.dart +++ b/lib/app/modules/home/views/nav_drawer.dart @@ -5,6 +5,7 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart'; import 'package:taskwarrior/app/modules/home/views/home_page_nav_drawer_menu_item.dart'; import 'package:taskwarrior/app/modules/home/views/theme_clipper.dart'; +import 'package:taskwarrior/app/modules/reports/views/reports_view_taskc.dart'; import 'package:taskwarrior/app/routes/app_pages.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; @@ -183,15 +184,32 @@ class NavDrawer extends StatelessWidget { ), ), ), - Obx( - () => NavDrawerMenuItem( - icon: Icons.summarize, - text: SentenceManager( - currentLanguage: homeController.selectedLanguage.value, - ).sentences.navDrawerReports, - onTap: () { - Get.toNamed(Routes.REPORTS); - }, + Visibility( + visible: !homeController.taskchampion.value, + child: Obx( + () => NavDrawerMenuItem( + icon: Icons.summarize, + text: SentenceManager( + currentLanguage: homeController.selectedLanguage.value, + ).sentences.navDrawerReports, + onTap: () { + Get.toNamed(Routes.REPORTS); + }, + ), + ), + ), + Visibility( + visible: homeController.taskchampion.value, + child: Obx( + () => NavDrawerMenuItem( + icon: Icons.summarize, + text: SentenceManager( + currentLanguage: homeController.selectedLanguage.value, + ).sentences.navDrawerReports, + onTap: () { + Get.to(() => ReportsHomeTaskc()); + }, + ), ), ), Obx( diff --git a/lib/app/modules/reports/controllers/reports_controller.dart b/lib/app/modules/reports/controllers/reports_controller.dart index abfe98fd..739f4b963 100644 --- a/lib/app/modules/reports/controllers/reports_controller.dart +++ b/lib/app/modules/reports/controllers/reports_controller.dart @@ -5,6 +5,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; +import 'package:taskwarrior/api_service.dart'; import 'package:taskwarrior/app/models/json/task.dart'; import 'package:taskwarrior/app/models/storage.dart'; import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart'; @@ -24,7 +25,7 @@ class ReportsController extends GetxController final GlobalKey daily = GlobalKey(); final GlobalKey weekly = GlobalKey(); final GlobalKey monthly = GlobalKey(); - + late TaskDatabase taskDatabase; var isSaved = false.obs; late TutorialCoachMark tutorialCoachMark; @@ -344,6 +345,11 @@ class ReportsController extends GetxController }); } + Future> fetchTasks() async { + await taskDatabase.open(); + return await taskDatabase.fetchTasksFromDatabase(); + } + // monthly report late TooltipBehavior monthlyBurndownTooltipBehaviour; RxMap> monthlyInfo = diff --git a/lib/app/modules/reports/views/burn_down_daily_taskc.dart b/lib/app/modules/reports/views/burn_down_daily_taskc.dart index 59a7aa45..ed9e946c 100644 --- a/lib/app/modules/reports/views/burn_down_daily_taskc.dart +++ b/lib/app/modules/reports/views/burn_down_daily_taskc.dart @@ -9,74 +9,50 @@ import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; import 'package:taskwarrior/app/utils/constants/utilites.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; -class BurnDownDailyTaskc extends StatefulWidget { - const BurnDownDailyTaskc({super.key}); +class BurnDownDailyTaskc extends StatelessWidget { + BurnDownDailyTaskc({super.key}); - @override - State createState() => _BurnDownDailyTaskcState(); -} - -class _BurnDownDailyTaskcState extends State - with TickerProviderStateMixin { - late TaskDatabase taskDatabase; - late TooltipBehavior _dailyBurndownTooltipBehaviour; - Map> dailyInfo = {}; - - @override - void initState() { - super.initState(); - - // Initialize the tooltip behavior for the chart - _dailyBurndownTooltipBehaviour = TooltipBehavior( - enable: true, - builder: (dynamic data, dynamic point, dynamic series, int pointIndex, - int seriesIndex) { - final String date = data.x; - final int pendingCount = data.y1; - final int completedCount = data.y2; + final TooltipBehavior _dailyBurndownTooltipBehaviour = TooltipBehavior( + enable: true, + builder: (dynamic data, dynamic point, dynamic series, int pointIndex, + int seriesIndex) { + final String date = data.x; + final int pendingCount = data.y1; + final int completedCount = data.y2; - return Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(5), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'Date: $date', - style: GoogleFonts.poppins( - fontWeight: TaskWarriorFonts.bold, - ), - ), - Text( - 'Pending: $pendingCount', - ), - Text( - 'Completed: $completedCount', + return Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Date: $date', + style: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, ), - ], - ), - ); - }, - ); + ), + Text('Pending: $pendingCount'), + Text('Completed: $completedCount'), + ], + ), + ); + }, + ); - // Initialize the database and fetch data - taskDatabase = TaskDatabase(); - taskDatabase.open().then((_) { - taskDatabase.fetchTasksFromDatabase().then((tasks) { - setState(() { - // Process the data and update the chart - _processData(tasks); - }); - }); - }); + Future>> fetchDailyInfo() async { + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + List tasks = await taskDatabase.fetchTasksFromDatabase(); + return _processData(tasks); } - void _processData(List tasks) { - dailyInfo = {}; + Map> _processData(List tasks) { + Map> dailyInfo = {}; // Sort tasks by entry date in ascending order tasks.sort((a, b) => a.entry.compareTo(b.entry)); @@ -98,80 +74,101 @@ class _BurnDownDailyTaskcState extends State }; } } + + return dailyInfo; } @override Widget build(BuildContext context) { double height = MediaQuery.of(context).size.height; // Screen height - return Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: SizedBox( - height: height * 0.6, - child: SfCartesianChart( - primaryXAxis: CategoryAxis( - title: AxisTitle( - text: 'Day - Month', - textStyle: GoogleFonts.poppins( - fontWeight: TaskWarriorFonts.bold, - color: AppSettings.isDarkMode ? Colors.white : Colors.black, - fontSize: TaskWarriorFonts.fontSizeSmall, + return FutureBuilder>>( + future: fetchDailyInfo(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } + + if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); + } + + Map> dailyInfo = snapshot.data ?? {}; + + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: SizedBox( + height: height * 0.6, + child: SfCartesianChart( + primaryXAxis: CategoryAxis( + title: AxisTitle( + text: 'Day - Month', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + color: AppSettings.isDarkMode + ? Colors.white + : Colors.black, + fontSize: TaskWarriorFonts.fontSizeSmall, + ), + ), ), - ), - ), - primaryYAxis: NumericAxis( - title: AxisTitle( - text: 'Tasks', - textStyle: GoogleFonts.poppins( - fontWeight: TaskWarriorFonts.bold, - fontSize: TaskWarriorFonts.fontSizeSmall, - color: AppSettings.isDarkMode ? Colors.white : Colors.black, + primaryYAxis: NumericAxis( + title: AxisTitle( + text: 'Tasks', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode + ? Colors.white + : Colors.black, + ), + ), ), + tooltipBehavior: _dailyBurndownTooltipBehaviour, + series: [ + StackedColumnSeries( + groupName: 'Group A', + enableTooltip: true, + color: TaskWarriorColors.green, + dataSource: dailyInfo.entries + .map((entry) => ChartData( + entry.key, + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y2, + name: 'Completed', + ), + StackedColumnSeries( + groupName: 'Group A', + color: TaskWarriorColors.yellow, + enableTooltip: true, + dataSource: dailyInfo.entries + .map((entry) => ChartData( + entry.key, + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y1, + name: 'Pending', + ), + ], ), ), - tooltipBehavior: _dailyBurndownTooltipBehaviour, - series: [ - StackedColumnSeries( - groupName: 'Group A', - enableTooltip: true, - color: TaskWarriorColors.green, - dataSource: dailyInfo.entries - .map((entry) => ChartData( - entry.key, - entry.value['pending'] ?? 0, - entry.value['completed'] ?? 0, - )) - .toList(), - xValueMapper: (ChartData data, _) => data.x, - yValueMapper: (ChartData data, _) => data.y2, - name: 'Completed', - ), - StackedColumnSeries( - groupName: 'Group A', - color: TaskWarriorColors.yellow, - enableTooltip: true, - dataSource: dailyInfo.entries - .map((entry) => ChartData( - entry.key, - entry.value['pending'] ?? 0, - entry.value['completed'] ?? 0, - )) - .toList(), - xValueMapper: (ChartData data, _) => data.x, - yValueMapper: (ChartData data, _) => data.y1, - name: 'Pending', - ), - ], ), - ), - ), - const CommonChartIndicator( - title: 'Daily Burndown Chart', - ), - ], + const CommonChartIndicator( + title: 'Daily Burndown Chart', + ), + ], + ); + }, ); } } diff --git a/lib/app/modules/reports/views/burn_down_monthly_taskc.dart b/lib/app/modules/reports/views/burn_down_monthly_taskc.dart index 3e75115b..2d1477f9 100644 --- a/lib/app/modules/reports/views/burn_down_monthly_taskc.dart +++ b/lib/app/modules/reports/views/burn_down_monthly_taskc.dart @@ -9,75 +9,54 @@ import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; import 'package:taskwarrior/app/utils/constants/utilites.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; -class BurnDownMonthlyTaskc extends StatefulWidget { - const BurnDownMonthlyTaskc({super.key}); - - @override - State createState() => _BurnDownMonthlyTaskcState(); -} - -class _BurnDownMonthlyTaskcState extends State - with TickerProviderStateMixin { - late TaskDatabase taskDatabase; - Map> monthlyInfo = {}; - - late TooltipBehavior _weeklyBurndownTooltipBehaviour; - - @override - void initState() { - super.initState(); - - _weeklyBurndownTooltipBehaviour = TooltipBehavior( - enable: true, - builder: (dynamic data, dynamic point, dynamic series, int pointIndex, - int seriesIndex) { - final String monthYear = data.x; - final int pendingCount = data.y1; - final int completedCount = data.y2; - - return Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(5), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - 'Month-Year: $monthYear', - style: const TextStyle( - fontWeight: TaskWarriorFonts.bold, - ), - ), - Text( - 'Pending: $pendingCount', - ), - Text( - 'Completed: $completedCount', +class BurnDownMonthlyTaskc extends StatelessWidget { + BurnDownMonthlyTaskc({super.key}); + + final _monthlyBurndownTooltipBehaviour = TooltipBehavior( + enable: true, + builder: (dynamic data, dynamic point, dynamic series, int pointIndex, + int seriesIndex) { + final String monthYear = data.x; + final int pendingCount = data.y1; + final int completedCount = data.y2; + + return Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Month-Year: $monthYear', + style: const TextStyle( + fontWeight: TaskWarriorFonts.bold, ), - ], - ), - ); - }, - ); - - taskDatabase = TaskDatabase(); - - ///fetch all data from the database - fetchAllData(); - } - - void fetchAllData() async { - List allData = await taskDatabase.fetchTasksFromDatabase(); - if (allData.isNotEmpty) { - sortBurnDownMonthly(allData); - } + ), + Text( + 'Pending: $pendingCount', + ), + Text( + 'Completed: $completedCount', + ), + ], + ), + ); + }, + ); + + Future>> fetchMonthlyInfo() async { + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + List tasks = await taskDatabase.fetchTasksFromDatabase(); + return sortBurnDownMonthly(tasks); } - void sortBurnDownMonthly(List allData) { - monthlyInfo = {}; + Map> sortBurnDownMonthly(List allData) { + Map> monthlyInfo = {}; allData.sort((a, b) => a.entry.compareTo(b.entry)); @@ -103,82 +82,99 @@ class _BurnDownMonthlyTaskcState extends State } debugPrint("monthlyInfo: $monthlyInfo"); - - // Update the state to refresh the chart - setState(() {}); + return monthlyInfo; } @override Widget build(BuildContext context) { final double height = MediaQuery.of(context).size.height; - return Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: SizedBox( - height: height * 0.6, - child: SfCartesianChart( - primaryXAxis: CategoryAxis( - title: AxisTitle( - text: 'Month - Year', - textStyle: GoogleFonts.poppins( - fontWeight: TaskWarriorFonts.bold, - fontSize: TaskWarriorFonts.fontSizeSmall, - color: AppSettings.isDarkMode ? Colors.white : Colors.black, + + return FutureBuilder>>( + future: fetchMonthlyInfo(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } + + if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); + } + + Map> monthlyInfo = snapshot.data ?? {}; + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: SizedBox( + height: height * 0.6, + child: SfCartesianChart( + primaryXAxis: CategoryAxis( + title: AxisTitle( + text: 'Month - Year', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode + ? Colors.white + : Colors.black, + ), + ), ), - ), - ), - primaryYAxis: NumericAxis( - title: AxisTitle( - text: 'Tasks', - textStyle: GoogleFonts.poppins( - fontWeight: TaskWarriorFonts.bold, - fontSize: TaskWarriorFonts.fontSizeSmall, - color: AppSettings.isDarkMode ? Colors.white : Colors.black, + primaryYAxis: NumericAxis( + title: AxisTitle( + text: 'Tasks', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode + ? Colors.white + : Colors.black, + ), + ), ), + tooltipBehavior: _monthlyBurndownTooltipBehaviour, + series: [ + StackedColumnSeries( + groupName: 'Group A', + enableTooltip: true, + color: TaskWarriorColors.green, + dataSource: monthlyInfo.entries + .map((entry) => ChartData( + entry.key, + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y2, + name: 'Completed', + ), + StackedColumnSeries( + groupName: 'Group A', + color: TaskWarriorColors.yellow, + enableTooltip: true, + dataSource: monthlyInfo.entries + .map((entry) => ChartData( + entry.key, + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y1, + name: 'Pending', + ), + ], ), ), - tooltipBehavior: _weeklyBurndownTooltipBehaviour, - series: [ - StackedColumnSeries( - groupName: 'Group A', - enableTooltip: true, - color: TaskWarriorColors.green, - dataSource: monthlyInfo.entries - .map((entry) => ChartData( - entry.key, - entry.value['pending'] ?? 0, - entry.value['completed'] ?? 0, - )) - .toList(), - xValueMapper: (ChartData data, _) => data.x, - yValueMapper: (ChartData data, _) => data.y2, - name: 'Completed', - ), - StackedColumnSeries( - groupName: 'Group A', - color: TaskWarriorColors.yellow, - enableTooltip: true, - dataSource: monthlyInfo.entries - .map((entry) => ChartData( - entry.key, - entry.value['pending'] ?? 0, - entry.value['completed'] ?? 0, - )) - .toList(), - xValueMapper: (ChartData data, _) => data.x, - yValueMapper: (ChartData data, _) => data.y1, - name: 'Pending', - ), - ], ), - ), - ), - const CommonChartIndicator( - title: 'Monthly Burndown Chart', - ) - ], + const CommonChartIndicator( + title: 'Monthly Burndown Chart', + ), + ], + ); + }, ); } } diff --git a/lib/app/modules/reports/views/burn_down_weekly_taskc.dart b/lib/app/modules/reports/views/burn_down_weekly_taskc.dart index 193600a2..6d2430db 100644 --- a/lib/app/modules/reports/views/burn_down_weekly_taskc.dart +++ b/lib/app/modules/reports/views/burn_down_weekly_taskc.dart @@ -9,76 +9,55 @@ import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; import 'package:taskwarrior/app/utils/constants/utilites.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; -class BurnDownWeeklyTask extends StatefulWidget { - const BurnDownWeeklyTask({super.key}); - - @override - State createState() => _BurnDownWeeklyTaskState(); -} - -class _BurnDownWeeklyTaskState extends State - with TickerProviderStateMixin { - late TaskDatabase taskDatabase; - late TooltipBehavior _weeklyBurndownTooltipBehaviour; - Map> weeklyInfo = {}; - - @override - void initState() { - super.initState(); - - ///initialize the _weeklyBurndownTooltipBehaviour tooltip behavior - _weeklyBurndownTooltipBehaviour = TooltipBehavior( - enable: true, - builder: (dynamic data, dynamic point, dynamic series, int pointIndex, - int seriesIndex) { - final String weekNumber = data.x; - final int pendingCount = data.y1; - final int completedCount = data.y2; - - return Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(5), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - weekNumber, - style: const TextStyle( - fontWeight: TaskWarriorFonts.bold, - ), - ), - Text( - 'Pending: $pendingCount', - ), - Text( - 'Completed: $completedCount', +class BurnDownWeeklyTask extends StatelessWidget { + BurnDownWeeklyTask({super.key}); + + final TooltipBehavior _weeklyBurndownTooltipBehaviour = TooltipBehavior( + enable: true, + builder: (dynamic data, dynamic point, dynamic series, int pointIndex, + int seriesIndex) { + final String weekNumber = data.x; + final int pendingCount = data.y1; + final int completedCount = data.y2; + + return Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + weekNumber, + style: const TextStyle( + fontWeight: TaskWarriorFonts.bold, ), - ], - ), - ); - }, - ); - - taskDatabase = TaskDatabase(); - - ///fetch all data from the database - fetchAllData(); - } - - void fetchAllData() async { - List allData = await taskDatabase.fetchTasksFromDatabase(); - if (allData.isNotEmpty) { - sortBurnDownWeekly(allData); - } + ), + Text( + 'Pending: $pendingCount', + ), + Text( + 'Completed: $completedCount', + ), + ], + ), + ); + }, + ); + + Future>> fetchWeeklyInfo() async { + TaskDatabase taskDatabase = TaskDatabase(); + await taskDatabase.open(); + List tasks = await taskDatabase.fetchTasksFromDatabase(); + return sortBurnDownWeekly(tasks); } - void sortBurnDownWeekly(List allData) { + Map> sortBurnDownWeekly(List allData) { // Initialize weeklyInfo map - weeklyInfo = {}; + Map> weeklyInfo = {}; // Sort allData by entry date in ascending order allData.sort((a, b) => a.entry.compareTo(b.entry)); @@ -102,7 +81,8 @@ class _BurnDownWeeklyTaskState extends State } } else { ///if weeklyInfo does not contain the week number - weeklyInfo[weekNumber] = { + // ignore: collection_methods_unrelated_type + weeklyInfo[weekNumber.toString()] = { 'pending': allData[i].status == 'pending' ? 1 : 0, 'completed': allData[i].status == 'completed' ? 1 : 0, }; @@ -110,86 +90,101 @@ class _BurnDownWeeklyTaskState extends State } debugPrint("weeklyInfo $weeklyInfo"); - - // Update the state to refresh the chart - setState(() {}); + return weeklyInfo; } @override Widget build(BuildContext context) { double height = MediaQuery.of(context).size.height; // Screen height - - return Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: SizedBox( - height: height * 0.6, - child: SfCartesianChart( - primaryXAxis: CategoryAxis( - title: AxisTitle( - text: 'Weeks - Year', - textStyle: GoogleFonts.poppins( - fontWeight: TaskWarriorFonts.bold, - fontSize: TaskWarriorFonts.fontSizeSmall, - color: AppSettings.isDarkMode ? Colors.white : Colors.black, + return FutureBuilder>>( + future: fetchWeeklyInfo(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } + + if (snapshot.hasError) { + return Center(child: Text('Error: ${snapshot.error}')); + } + + Map> weeklyInfo = snapshot.data ?? {}; + + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: SizedBox( + height: height * 0.6, + child: SfCartesianChart( + primaryXAxis: CategoryAxis( + title: AxisTitle( + text: 'Weeks - Year', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + fontSize: TaskWarriorFonts.fontSizeSmall, + color: AppSettings.isDarkMode + ? Colors.white + : Colors.black, + ), + ), + ), + primaryYAxis: NumericAxis( + title: AxisTitle( + text: 'Tasks', + textStyle: GoogleFonts.poppins( + fontWeight: TaskWarriorFonts.bold, + color: AppSettings.isDarkMode + ? Colors.white + : Colors.black, + fontSize: TaskWarriorFonts.fontSizeSmall, + ), + ), + ), + tooltipBehavior: _weeklyBurndownTooltipBehaviour, + series: [ + ///this is the completed tasks + StackedColumnSeries( + groupName: 'Group A', + enableTooltip: true, + color: TaskWarriorColors.green, + dataSource: weeklyInfo.entries + .map((entry) => ChartData( + 'Week ${entry.key}', + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y2, + name: 'Completed', + ), + + ///this is the pending tasks + StackedColumnSeries( + groupName: 'Group A', + color: TaskWarriorColors.yellow, + enableTooltip: true, + dataSource: weeklyInfo.entries + .map((entry) => ChartData( + 'Week ${entry.key}', + entry.value['pending'] ?? 0, + entry.value['completed'] ?? 0, + )) + .toList(), + xValueMapper: (ChartData data, _) => data.x, + yValueMapper: (ChartData data, _) => data.y1, + name: 'Pending', + ), + ], ), ), ), - primaryYAxis: NumericAxis( - title: AxisTitle( - text: 'Tasks', - textStyle: GoogleFonts.poppins( - fontWeight: TaskWarriorFonts.bold, - color: AppSettings.isDarkMode ? Colors.white : Colors.black, - fontSize: TaskWarriorFonts.fontSizeSmall, - ), - ), + const CommonChartIndicator( + title: 'Weekly Burndown Chart', ), - tooltipBehavior: _weeklyBurndownTooltipBehaviour, - series: [ - ///this is the completed tasks - StackedColumnSeries( - groupName: 'Group A', - enableTooltip: true, - color: TaskWarriorColors.green, - dataSource: weeklyInfo.entries - .map((entry) => ChartData( - 'Week ${entry.key}', - entry.value['pending'] ?? 0, - entry.value['completed'] ?? 0, - )) - .toList(), - xValueMapper: (ChartData data, _) => data.x, - yValueMapper: (ChartData data, _) => data.y2, - name: 'Completed', - ), - - ///this is the pending tasks - StackedColumnSeries( - groupName: 'Group A', - color: TaskWarriorColors.yellow, - enableTooltip: true, - dataSource: weeklyInfo.entries - .map((entry) => ChartData( - 'Week ${entry.key}', - entry.value['pending'] ?? 0, - entry.value['completed'] ?? 0, - )) - .toList(), - xValueMapper: (ChartData data, _) => data.x, - yValueMapper: (ChartData data, _) => data.y1, - name: 'Pending', - ), - ], - ), - ), - ), - const CommonChartIndicator( - title: 'Weekly Burndown Chart', - ), - ], - ); + ], + ); + }); } } diff --git a/lib/app/modules/reports/views/reports_view_taskc.dart b/lib/app/modules/reports/views/reports_view_taskc.dart index 7b5cf61e..202f9eb5 100644 --- a/lib/app/modules/reports/views/reports_view_taskc.dart +++ b/lib/app/modules/reports/views/reports_view_taskc.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:taskwarrior/api_service.dart'; +import 'package:get/get.dart'; import 'package:taskwarrior/app/modules/reports/controllers/reports_controller.dart'; import 'package:taskwarrior/app/modules/reports/views/burn_down_daily_taskc.dart'; import 'package:taskwarrior/app/modules/reports/views/burn_down_monthly_taskc.dart'; @@ -8,9 +8,10 @@ import 'package:taskwarrior/app/modules/reports/views/burn_down_weekly_taskc.dar import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; +import 'package:taskwarrior/api_service.dart'; class ReportsHomeTaskc extends StatelessWidget { - final ReportsController reportsController = ReportsController(); + final ReportsController reportsController = Get.put(ReportsController()); final TaskDatabase taskDatabase = TaskDatabase(); ReportsHomeTaskc({super.key}); @@ -132,13 +133,15 @@ class ReportsHomeTaskc extends StatelessWidget { ), ], ) - : IndexedStack( - index: reportsController.selectedIndex.value, - children: const [ - BurnDownDailyTaskc(), - BurnDownWeeklyTask(), - BurnDownMonthlyTaskc(), - ], + : Obx( + () => IndexedStack( + index: reportsController.selectedIndex.value, + children: [ + BurnDownDailyTaskc(), + BurnDownWeeklyTask(), + BurnDownMonthlyTaskc(), + ], + ), ), ); }, From 1d09d36c8f382f80a1d7ed0d556443b1672dac46 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 6 Jul 2024 15:23:06 +0530 Subject: [PATCH 21/47] fix: merge conflict --- .../modules/reports/views/burn_down_weekly_taskc.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/app/modules/reports/views/burn_down_weekly_taskc.dart b/lib/app/modules/reports/views/burn_down_weekly_taskc.dart index 6d2430db..6d9f5821 100644 --- a/lib/app/modules/reports/views/burn_down_weekly_taskc.dart +++ b/lib/app/modules/reports/views/burn_down_weekly_taskc.dart @@ -68,16 +68,16 @@ class BurnDownWeeklyTask extends StatelessWidget { Utils.getWeekNumbertoInt(DateTime.parse(allData[i].entry)); ///check if weeklyInfo contains the week number - if (weeklyInfo.containsKey(weekNumber)) { + if (weeklyInfo.containsKey(weekNumber.toString())) { ///check if the status is pending or completed if (allData[i].status == 'pending') { ///if the status is pending then add 1 to the pending count - weeklyInfo[weekNumber]!['pending'] = - (weeklyInfo[weekNumber]!['pending'] ?? 0) + 1; + weeklyInfo[weekNumber.toString()]!['pending'] = + (weeklyInfo[weekNumber.toString()]!['pending'] ?? 0) + 1; } else if (allData[i].status == 'completed') { ///if the status is completed then add 1 to the completed count - weeklyInfo[weekNumber]!['completed'] = - (weeklyInfo[weekNumber]!['completed'] ?? 0) + 1; + weeklyInfo[weekNumber.toString()]!['completed'] = + (weeklyInfo[weekNumber.toString()]!['completed'] ?? 0) + 1; } } else { ///if weeklyInfo does not contain the week number From 16722bf01d95c81f75690669d18331f0c577f105 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 6 Jul 2024 18:00:24 +0530 Subject: [PATCH 22/47] feat: make taskchampion view stateless --- .../modules/home/views/home_page_app_bar.dart | 5 +- lib/app/modules/home/views/nav_drawer.dart | 2 +- lib/app/utils/taskchampion/taskchampion.dart | 47 ++++--------------- 3 files changed, 13 insertions(+), 41 deletions(-) diff --git a/lib/app/modules/home/views/home_page_app_bar.dart b/lib/app/modules/home/views/home_page_app_bar.dart index 645102d8..5c7b2033 100644 --- a/lib/app/modules/home/views/home_page_app_bar.dart +++ b/lib/app/modules/home/views/home_page_app_bar.dart @@ -107,8 +107,7 @@ class HomePageAppBar extends StatelessWidget implements PreferredSizeWidget { Navigator.push( context, MaterialPageRoute( - builder: (_) => - const ManageTaskChampionCreds(), + builder: (_) => ManageTaskChampionCreds(), )).then((value) {}); }, textColor: TaskWarriorColors.purple, @@ -144,7 +143,7 @@ class HomePageAppBar extends StatelessWidget implements PreferredSizeWidget { Navigator.push( context, MaterialPageRoute( - builder: (_) => const ManageTaskChampionCreds(), + builder: (_) => ManageTaskChampionCreds(), )).then((value) {}); }, textColor: TaskWarriorColors.purple, diff --git a/lib/app/modules/home/views/nav_drawer.dart b/lib/app/modules/home/views/nav_drawer.dart index 2904963d..bed358f0 100644 --- a/lib/app/modules/home/views/nav_drawer.dart +++ b/lib/app/modules/home/views/nav_drawer.dart @@ -96,7 +96,7 @@ class NavDrawer extends StatelessWidget { onTap: () { Navigator.of(context).push( MaterialPageRoute( - builder: (context) => const ManageTaskChampionCreds(), + builder: (context) => ManageTaskChampionCreds(), ), ); }, diff --git a/lib/app/utils/taskchampion/taskchampion.dart b/lib/app/utils/taskchampion/taskchampion.dart index 2047aff9..566e3c90 100644 --- a/lib/app/utils/taskchampion/taskchampion.dart +++ b/lib/app/utils/taskchampion/taskchampion.dart @@ -6,49 +6,29 @@ import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; import 'package:url_launcher/url_launcher.dart'; -class ManageTaskChampionCreds extends StatefulWidget { - const ManageTaskChampionCreds({super.key}); - - @override - State createState() => - _ManageTaskChampionCredsState(); -} - -class _ManageTaskChampionCredsState extends State { - String encryptionSecret = ''; - String clientId = ''; - +class ManageTaskChampionCreds extends StatelessWidget { final TextEditingController _encryptionSecretController = TextEditingController(); final TextEditingController _clientIdController = TextEditingController(); - @override - void initState() { - super.initState(); + ManageTaskChampionCreds({super.key}) { _loadCredentials(); } Future _loadCredentials() async { SharedPreferences prefs = await SharedPreferences.getInstance(); - setState(() { - encryptionSecret = prefs.getString('encryptionSecret') ?? ''; - clientId = prefs.getString('clientId') ?? ''; - _encryptionSecretController.text = encryptionSecret; - _clientIdController.text = clientId; - }); + _encryptionSecretController.text = + prefs.getString('encryptionSecret') ?? ''; + _clientIdController.text = prefs.getString('clientId') ?? ''; } - Future _saveCredentials() async { + Future _saveCredentials(BuildContext context) async { SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setString('encryptionSecret', _encryptionSecretController.text); await prefs.setString('clientId', _clientIdController.text); - } - - @override - void dispose() { - _encryptionSecretController.dispose(); - _clientIdController.dispose(); - super.dispose(); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Credentials saved successfully')), + ); } @override @@ -136,14 +116,7 @@ class _ManageTaskChampionCredsState extends State { ), const SizedBox(height: 20), ElevatedButton( - onPressed: () async { - await _saveCredentials(); - // ignore: use_build_context_synchronously - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Credentials saved successfully')), - ); - }, + onPressed: () => _saveCredentials(context), child: const Text('Save Credentials'), ), const SizedBox(height: 10), From 1c2898f16b4bc8b9d662bc49fb78d6e2dfecc97c Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 6 Jul 2024 18:08:36 +0530 Subject: [PATCH 23/47] fix: minor bug fix --- lib/app/utils/taskchampion/taskchampion.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/app/utils/taskchampion/taskchampion.dart b/lib/app/utils/taskchampion/taskchampion.dart index 566e3c90..16b218e5 100644 --- a/lib/app/utils/taskchampion/taskchampion.dart +++ b/lib/app/utils/taskchampion/taskchampion.dart @@ -1,3 +1,5 @@ +// ignore_for_file: use_build_context_synchronously + import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:shared_preferences/shared_preferences.dart'; From 5a7d7afdfcc1557cf713b6681b973e458982cc71 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 6 Jul 2024 18:11:13 +0530 Subject: [PATCH 24/47] fix: move CredentialStorage --- lib/api_service.dart | 2 +- .../home/controllers/home_controller.dart | 2 +- .../modules/home/views/home_page_app_bar.dart | 1 + lib/app/modules/home/views/show_tasks.dart | 2 +- .../utils/taskchampion/credentials_storage.dart | 16 ++++++++++++++++ lib/app/utils/taskchampion/taskchampion.dart | 15 --------------- 6 files changed, 20 insertions(+), 18 deletions(-) create mode 100644 lib/app/utils/taskchampion/credentials_storage.dart diff --git a/lib/api_service.dart b/lib/api_service.dart index fbd699f3..5df62b72 100644 --- a/lib/api_service.dart +++ b/lib/api_service.dart @@ -5,7 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart'; -import 'package:taskwarrior/app/utils/taskchampion/taskchampion.dart'; +import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; class Tasks { final int id; diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 6a4488b8..3da42168 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -23,7 +23,7 @@ import 'package:taskwarrior/app/tour/filter_drawer_tour.dart'; import 'package:taskwarrior/app/tour/home_page_tour.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/language/supported_language.dart'; -import 'package:taskwarrior/app/utils/taskchampion/taskchampion.dart'; +import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; import 'package:taskwarrior/app/utils/taskfunctions/comparator.dart'; import 'package:taskwarrior/app/utils/taskfunctions/projects.dart'; import 'package:taskwarrior/app/utils/taskfunctions/query.dart'; diff --git a/lib/app/modules/home/views/home_page_app_bar.dart b/lib/app/modules/home/views/home_page_app_bar.dart index 5c7b2033..1b766270 100644 --- a/lib/app/modules/home/views/home_page_app_bar.dart +++ b/lib/app/modules/home/views/home_page_app_bar.dart @@ -7,6 +7,7 @@ import 'package:taskwarrior/app/routes/app_pages.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/gen/fonts.gen.dart'; import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; +import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; import 'package:taskwarrior/app/utils/taskchampion/taskchampion.dart'; import 'package:taskwarrior/app/utils/taskserver/taskserver.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; diff --git a/lib/app/modules/home/views/show_tasks.dart b/lib/app/modules/home/views/show_tasks.dart index 822edcea..26b987f4 100644 --- a/lib/app/modules/home/views/show_tasks.dart +++ b/lib/app/modules/home/views/show_tasks.dart @@ -8,7 +8,7 @@ import 'package:taskwarrior/app/modules/home/views/show_details.dart'; import 'package:taskwarrior/app/utils/constants/palette.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; -import 'package:taskwarrior/app/utils/taskchampion/taskchampion.dart'; +import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; class TaskViewBuilder extends StatelessWidget { diff --git a/lib/app/utils/taskchampion/credentials_storage.dart b/lib/app/utils/taskchampion/credentials_storage.dart new file mode 100644 index 00000000..3e449963 --- /dev/null +++ b/lib/app/utils/taskchampion/credentials_storage.dart @@ -0,0 +1,16 @@ +import 'package:shared_preferences/shared_preferences.dart'; + +class CredentialsStorage { + static const String _encryptionSecretKey = 'encryptionSecret'; + static const String _clientIdKey = 'clientId'; + + static Future getEncryptionSecret() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString(_encryptionSecretKey); + } + + static Future getClientId() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getString(_clientIdKey); + } +} diff --git a/lib/app/utils/taskchampion/taskchampion.dart b/lib/app/utils/taskchampion/taskchampion.dart index 16b218e5..79da30c3 100644 --- a/lib/app/utils/taskchampion/taskchampion.dart +++ b/lib/app/utils/taskchampion/taskchampion.dart @@ -140,18 +140,3 @@ class ManageTaskChampionCreds extends StatelessWidget { ); } } - -class CredentialsStorage { - static const String _encryptionSecretKey = 'encryptionSecret'; - static const String _clientIdKey = 'clientId'; - - static Future getEncryptionSecret() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - return prefs.getString(_encryptionSecretKey); - } - - static Future getClientId() async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - return prefs.getString(_clientIdKey); - } -} From 33a10cbb9b1799136a0f09f304758213d93aa5b2 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 6 Jul 2024 18:33:07 +0530 Subject: [PATCH 25/47] fix: make addtasktotaskc stateless --- .../home/controllers/home_controller.dart | 4 + .../views/add_task_to_taskc_bottom_sheet.dart | 109 ++++++------------ .../home_page_floating_action_button.dart | 4 +- 3 files changed, 41 insertions(+), 76 deletions(-) diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 3da42168..78502dd0 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -51,6 +51,7 @@ class HomeController extends GetxController { final Rx selectedLanguage = SupportedLanguage.english.obs; final ScrollController scrollController = ScrollController(); final RxBool showbtn = false.obs; + late TaskDatabase taskdb; var tasks = [].obs; @override @@ -69,6 +70,8 @@ class HomeController extends GetxController { if (Platform.isAndroid) { handleHomeWidgetClicked(); } + taskdb = TaskDatabase(); + taskdb.open(); getUniqueProjects(); _loadTaskChampion(); fetchTasksFromDB(); @@ -483,6 +486,7 @@ class HomeController extends GetxController { // dialogue box final formKey = GlobalKey(); final namecontroller = TextEditingController(); + final projectcontroller = TextEditingController(); var due = Rxn(); RxString dueString = ''.obs; RxString priority = 'M'.obs; diff --git a/lib/app/modules/home/views/add_task_to_taskc_bottom_sheet.dart b/lib/app/modules/home/views/add_task_to_taskc_bottom_sheet.dart index 30d6a9c8..00e6587a 100644 --- a/lib/app/modules/home/views/add_task_to_taskc_bottom_sheet.dart +++ b/lib/app/modules/home/views/add_task_to_taskc_bottom_sheet.dart @@ -2,53 +2,15 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:taskwarrior/api_service.dart'; +import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; -class AddTaskToTaskcBottomSheet extends StatefulWidget { - const AddTaskToTaskcBottomSheet({super.key}); - - @override - State createState() => - _AddTaskToTaskcBottomSheetState(); -} - -class _AddTaskToTaskcBottomSheetState extends State { - final formKey = GlobalKey(); - final namecontroller = TextEditingController(); - DateTime? due; - String dueString = ''; - String priority = 'M'; - final projectController = TextEditingController(); - String project = ''; - bool inThePast = false; - bool change24hr = false; - late TaskDatabase taskdb; - - Future checkto24hr() async { - final SharedPreferences prefs = await SharedPreferences.getInstance(); - setState(() { - change24hr = prefs.getBool('24hourformate') ?? false; - }); - } - - @override - void initState() { - super.initState(); - checkto24hr(); - taskdb = TaskDatabase(); - taskdb.open(); - } - - @override - void dispose() { - projectController.dispose(); - namecontroller.dispose(); - super.dispose(); - } +class AddTaskToTaskcBottomSheet extends StatelessWidget { + final HomeController homeController; + const AddTaskToTaskcBottomSheet({super.key, required this.homeController}); @override Widget build(BuildContext context) { @@ -78,7 +40,7 @@ class _AddTaskToTaskcBottomSheetState extends State { ), ), content: Form( - key: formKey, + key: homeController.formKey, child: SizedBox( width: MediaQuery.of(context).size.width * 0.8, child: Column( @@ -108,7 +70,7 @@ class _AddTaskToTaskcBottomSheetState extends State { Widget buildName() => TextFormField( autofocus: true, - controller: namecontroller, + controller: homeController.namecontroller, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -129,7 +91,7 @@ class _AddTaskToTaskcBottomSheetState extends State { Widget buildProject() => TextFormField( autofocus: true, - controller: projectController, + controller: homeController.projectcontroller, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -160,7 +122,7 @@ class _AddTaskToTaskcBottomSheetState extends State { Expanded( child: GestureDetector( child: TextFormField( - style: inThePast + style: homeController.inThePast.value ? TextStyle(color: TaskWarriorColors.red) : TextStyle( color: AppSettings.isDarkMode @@ -169,11 +131,13 @@ class _AddTaskToTaskcBottomSheetState extends State { ), readOnly: true, controller: TextEditingController( - text: (due != null) ? dueString : null, + text: (homeController.due.value != null) + ? homeController.dueString.value + : null, ), decoration: InputDecoration( hintText: 'Select due date', - hintStyle: inThePast + hintStyle: homeController.inThePast.value ? TextStyle(color: TaskWarriorColors.red) : TextStyle( color: AppSettings.isDarkMode @@ -215,7 +179,7 @@ class _AddTaskToTaskcBottomSheetState extends State { }, fieldHintText: "Month/Date/Year", context: context, - initialDate: due ?? DateTime.now(), + initialDate: homeController.due.value ?? DateTime.now(), firstDate: DateTime.now(), lastDate: DateTime(2037, 12, 31), ); @@ -251,14 +215,15 @@ class _AddTaskToTaskcBottomSheetState extends State { ), child: MediaQuery( data: MediaQuery.of(context).copyWith( - alwaysUse24HourFormat: change24hr, + alwaysUse24HourFormat: + homeController.change24hr.value, ), child: child!), ); }, context: context, - initialTime: - TimeOfDay.fromDateTime(due ?? DateTime.now()), + initialTime: TimeOfDay.fromDateTime( + homeController.due.value ?? DateTime.now()), ); if (time != null) { var dateTime = date.add( @@ -267,12 +232,11 @@ class _AddTaskToTaskcBottomSheetState extends State { minutes: time.minute, ), ); - due = dateTime.toUtc(); - dueString = DateFormat("yyyy-MM-dd").format(dateTime); + homeController.due.value = dateTime.toUtc(); + homeController.dueString.value = + DateFormat("yyyy-MM-dd").format(dateTime); if (dateTime.isBefore(DateTime.now())) { - setState(() { - inThePast = true; - }); + homeController.inThePast.value = true; ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( @@ -289,9 +253,7 @@ class _AddTaskToTaskcBottomSheetState extends State { .kLightSecondaryBackgroundColor, duration: const Duration(seconds: 2))); } else { - setState(() { - inThePast = false; - }); + homeController.inThePast.value = false; } } } @@ -322,7 +284,7 @@ class _AddTaskToTaskcBottomSheetState extends State { dropdownColor: AppSettings.isDarkMode ? TaskWarriorColors.kdialogBackGroundColor : TaskWarriorColors.kLightDialogBackGroundColor, - value: priority, + value: homeController.priority.value, elevation: 16, style: GoogleFonts.poppins( color: AppSettings.isDarkMode @@ -336,9 +298,7 @@ class _AddTaskToTaskcBottomSheetState extends State { : TaskWarriorColors.kLightDialogBackGroundColor, ), onChanged: (String? newValue) { - setState(() { - priority = newValue!; - }); + homeController.priority.value = newValue!; }, items: ['H', 'M', 'L', 'None'] .map>((String value) { @@ -376,26 +336,25 @@ class _AddTaskToTaskcBottomSheetState extends State { ), ), onPressed: () async { - if (formKey.currentState!.validate()) { + if (homeController.formKey.currentState!.validate()) { var task = Tasks( - description: namecontroller.text, + description: homeController.namecontroller.text, status: 'pending', - priority: priority, + priority: homeController.priority.value, entry: DateTime.now().toIso8601String(), id: 0, - project: projectController.text, + project: homeController.projectcontroller.text, uuid: '', urgency: 0, - due: dueString, + due: homeController.dueString.value, // dueString.toIso8601String(), end: '', modified: 'r'); - await taskdb.insertTask(task); - namecontroller.text = ''; - due = null; - priority = 'M'; - project = ''; - setState(() {}); + await homeController.taskdb.insertTask(task); + homeController.namecontroller.text = ''; + homeController.due.value = null; + homeController.priority.value = 'M'; + homeController.projectcontroller.text = ''; ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( 'Task Added Successfully!', diff --git a/lib/app/modules/home/views/home_page_floating_action_button.dart b/lib/app/modules/home/views/home_page_floating_action_button.dart index 961b13b7..9770b3f9 100644 --- a/lib/app/modules/home/views/home_page_floating_action_button.dart +++ b/lib/app/modules/home/views/home_page_floating_action_button.dart @@ -32,7 +32,9 @@ class HomePageFloatingActionButton extends StatelessWidget { onPressed: () => (controller.taskchampion.value) ? (showDialog( context: context, - builder: (context) => const AddTaskToTaskcBottomSheet(), + builder: (context) => AddTaskToTaskcBottomSheet( + homeController: controller, + ), ).then((value) { if (controller.isSyncNeeded.value && value != "cancel") { controller.isNeededtoSyncOnStart(context); From c190e1a444b272b480480b67075b8cb5dbb94963 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 6 Jul 2024 19:16:31 +0530 Subject: [PATCH 26/47] fix: complete and delete task logic --- lib/api_service.dart | 23 ++++++++++++++-------- lib/app/modules/home/views/show_tasks.dart | 11 ++--------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/api_service.dart b/lib/api_service.dart index 5df62b72..3cb5f2cd 100644 --- a/lib/api_service.dart +++ b/lib/api_service.dart @@ -141,18 +141,24 @@ Future updateTasksInDatabase(List tasks) async { localTask.status, localTask.uuid!, ); + if (localTask.status == 'completed') { + completeTask('email', localTask.uuid!); + } else if (localTask.status == 'deleted') { + deleteTask('email', localTask.uuid!); + } } } } } -Future deleteTask( - String email, String encryptionSecret, String uuid, String taskUuid) async { +Future deleteTask(String email, String taskUuid) async { + var c = await CredentialsStorage.getClientId(); + var e = await CredentialsStorage.getEncryptionSecret(); final url = Uri.parse('$baseUrl/delete-task'); final body = jsonEncode({ 'email': email, - 'encryptionSecret': encryptionSecret, - 'UUID': uuid, + 'encryptionSecret': e, + 'UUID': c, 'taskuuid': taskUuid, }); @@ -175,13 +181,14 @@ Future deleteTask( } } -Future completeTask( - String email, String encryptionSecret, String uuid, String taskUuid) async { +Future completeTask(String email, String taskUuid) async { + var c = await CredentialsStorage.getClientId(); + var e = await CredentialsStorage.getEncryptionSecret(); final url = Uri.parse('$baseUrl/complete-task'); final body = jsonEncode({ 'email': email, - 'encryptionSecret': encryptionSecret, - 'UUID': uuid, + 'encryptionSecret': e, + 'UUID': c, 'taskuuid': taskUuid, }); diff --git a/lib/app/modules/home/views/show_tasks.dart b/lib/app/modules/home/views/show_tasks.dart index 26b987f4..2b45bdc5 100644 --- a/lib/app/modules/home/views/show_tasks.dart +++ b/lib/app/modules/home/views/show_tasks.dart @@ -8,7 +8,6 @@ import 'package:taskwarrior/app/modules/home/views/show_details.dart'; import 'package:taskwarrior/app/utils/constants/palette.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; -import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; class TaskViewBuilder extends StatelessWidget { @@ -234,23 +233,17 @@ class TaskViewBuilder extends StatelessWidget { } void _markTaskAsCompleted(String uuid) async { - String clientId = (await CredentialsStorage.getClientId()) ?? ''; - String encryptionSecret = - (await CredentialsStorage.getEncryptionSecret()) ?? ''; TaskDatabase taskDatabase = TaskDatabase(); await taskDatabase.open(); taskDatabase.markTaskAsCompleted(uuid); - completeTask('email', encryptionSecret, clientId, uuid); + completeTask('email', uuid); } void _markTaskAsDeleted(String uuid) async { - String clientId = (await CredentialsStorage.getClientId()) ?? ''; - String encryptionSecret = - (await CredentialsStorage.getEncryptionSecret()) ?? ''; TaskDatabase taskDatabase = TaskDatabase(); await taskDatabase.open(); taskDatabase.markTaskAsDeleted(uuid); - deleteTask('email', encryptionSecret, clientId, uuid); + deleteTask('email', uuid); } Color _getPriorityColor(String priority) { From 2d730685c38539f34b8e4c979b7cc028d6d3cd48 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Sat, 6 Jul 2024 21:12:58 +0530 Subject: [PATCH 27/47] feat: add confirmation dialog for task details --- lib/app/modules/home/views/show_details.dart | 234 ++++++++++++------- 1 file changed, 147 insertions(+), 87 deletions(-) diff --git a/lib/app/modules/home/views/show_details.dart b/lib/app/modules/home/views/show_details.dart index 7f6dd4c9..038daab1 100644 --- a/lib/app/modules/home/views/show_details.dart +++ b/lib/app/modules/home/views/show_details.dart @@ -1,4 +1,4 @@ -// ignore_for_file: use_build_context_synchronously +// ignore_for_file: deprecated_member_use, use_build_context_synchronously import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -50,83 +50,83 @@ class _TaskDetailsState extends State { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppSettings.isDarkMode - ? TaskWarriorColors.kprimaryBackgroundColor - : TaskWarriorColors.kLightPrimaryBackgroundColor, - appBar: AppBar( - foregroundColor: TaskWarriorColors.lightGrey, - backgroundColor: TaskWarriorColors.kprimaryBackgroundColor, - title: Text( - 'Task: ${widget.task.description}', - style: GoogleFonts.poppins(color: TaskWarriorColors.white), - ), - ), - body: Padding( - padding: const EdgeInsets.all(16.0), - child: ListView( - children: [ - _buildEditableDetail('Description:', description, (value) { - setState(() { - description = value; - hasChanges = true; - }); - }), - _buildEditableDetail('Project:', project, (value) { - setState(() { - project = value; - hasChanges = true; - }); - }), - _buildSelectableDetail('Status:', status, ['pending', 'completed'], - (value) { - setState(() { - status = value; - hasChanges = true; - }); - }), - _buildSelectableDetail('Priority:', priority, ['H', 'M', 'L'], - (value) { - setState(() { - priority = value; - hasChanges = true; - }); - }), - _buildDatePickerDetail('Due:', due, (value) { - setState(() { - due = value; - hasChanges = true; - }); - }), - _buildDetail('UUID:', widget.task.uuid!), - _buildDetail('Urgency:', widget.task.urgency.toString()), - _buildDetail('End:', _buildDate(widget.task.end)), - _buildDetail('Entry:', _buildDate(widget.task.entry)), - _buildDetail('Modified:', _buildDate(widget.task.modified)), - ], + return WillPopScope( + onWillPop: () async { + if (hasChanges) { + final action = await _showUnsavedChangesDialog(context); + if (action == UnsavedChangesAction.cancel) { + return Future.value(false); + } else if (action == UnsavedChangesAction.save) { + await _saveTask(); + } + } + return Future.value(true); + }, + child: Scaffold( + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryBackgroundColor + : TaskWarriorColors.kLightPrimaryBackgroundColor, + appBar: AppBar( + foregroundColor: TaskWarriorColors.lightGrey, + backgroundColor: TaskWarriorColors.kprimaryBackgroundColor, + title: Text( + 'Task: ${widget.task.description}', + style: GoogleFonts.poppins(color: TaskWarriorColors.white), + ), ), - ), - floatingActionButton: hasChanges - ? FloatingActionButton( - onPressed: () async { - await taskDatabase.saveEditedTaskInDB(widget.task.uuid!, - description, project, status, priority, due); + body: Padding( + padding: const EdgeInsets.all(16.0), + child: ListView( + children: [ + _buildEditableDetail('Description:', description, (value) { setState(() { - hasChanges = false; + description = value; + hasChanges = true; }); - modifyTaskOnTaskwarrior( - description, - project, - due, - priority, - status, - widget.task.uuid!, - ); - // used this for testing - }, - child: const Icon(Icons.save), - ) - : null, + }), + _buildEditableDetail('Project:', project, (value) { + setState(() { + project = value; + hasChanges = true; + }); + }), + _buildSelectableDetail( + 'Status:', status, ['pending', 'completed'], (value) { + setState(() { + status = value; + hasChanges = true; + }); + }), + _buildSelectableDetail('Priority:', priority, ['H', 'M', 'L'], + (value) { + setState(() { + priority = value; + hasChanges = true; + }); + }), + _buildDatePickerDetail('Due:', due, (value) { + setState(() { + due = value; + hasChanges = true; + }); + }), + _buildDetail('UUID:', widget.task.uuid!), + _buildDetail('Urgency:', widget.task.urgency.toString()), + _buildDetail('End:', _buildDate(widget.task.end)), + _buildDetail('Entry:', _buildDate(widget.task.entry)), + _buildDetail('Modified:', _buildDate(widget.task.modified)), + ], + ), + ), + floatingActionButton: hasChanges + ? FloatingActionButton( + onPressed: () async { + await _saveTask(); + }, + child: const Icon(Icons.save), + ) + : null, + ), ); } @@ -169,25 +169,15 @@ class _TaskDetailsState extends State { return Theme( data: Theme.of(context).copyWith( colorScheme: AppSettings.isDarkMode - ? ColorScheme( - brightness: Brightness.dark, + ? ColorScheme.dark( primary: TaskWarriorColors.white, onPrimary: TaskWarriorColors.black, - secondary: TaskWarriorColors.black, - onSecondary: TaskWarriorColors.white, - error: TaskWarriorColors.red, - onError: TaskWarriorColors.black, surface: TaskWarriorColors.black, onSurface: TaskWarriorColors.white, ) - : ColorScheme( - brightness: Brightness.light, + : ColorScheme.light( primary: TaskWarriorColors.black, onPrimary: TaskWarriorColors.white, - secondary: TaskWarriorColors.white, - onSecondary: TaskWarriorColors.black, - error: TaskWarriorColors.red, - onError: TaskWarriorColors.white, surface: TaskWarriorColors.white, onSurface: TaskWarriorColors.black, ), @@ -376,4 +366,74 @@ class _TaskDetailsState extends State { return '-'; } } + + Future _showUnsavedChangesDialog( + BuildContext context) async { + return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return Utils.showAlertDialog( + title: Text( + 'Unsaved Changes', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor), + ), + content: Text( + 'You have unsaved changes. What would you like to do?', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(UnsavedChangesAction.cancel); + }, + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(UnsavedChangesAction.discard); + }, + child: const Text('Don\'t Save'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(UnsavedChangesAction.save); + }, + child: const Text('Save'), + ), + ], + ); + }, + ); + } + + Future _saveTask() async { + await taskDatabase.saveEditedTaskInDB( + widget.task.uuid!, + description, + project, + status, + priority, + due, + ); + setState(() { + hasChanges = false; + }); + modifyTaskOnTaskwarrior( + description, + project, + due, + priority, + status, + widget.task.uuid!, + ); + } } + +enum UnsavedChangesAction { save, discard, cancel } From ceeec9fffbde4b8d3e57241e6af2133f6c4cb101 Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 20 Jul 2024 10:29:19 +0530 Subject: [PATCH 28/47] Query file tests added --- pubspec.lock | 98 ++++++++++++++++++++++++++++- pubspec.yaml | 7 ++- test/taskfunctions/query_tests.dart | 72 +++++++++++++++++++++ 3 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 test/taskfunctions/query_tests.dart diff --git a/pubspec.lock b/pubspec.lock index 14d42c7e..27c534e7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -201,6 +201,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "3945034e86ea203af7a056d98e98e42a5518fff200d6e8e6647e1886b07e936e" + url: "https://pub.dev" + source: hosted + version: "1.8.0" cross_file: dependency: transitive description: @@ -503,7 +511,7 @@ packages: source: hosted version: "2.0.9" flutter_test: - dependency: "direct dev" + dependency: "direct main" description: flutter source: sdk version: "0.0.0" @@ -528,6 +536,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.6.6" + get_test: + dependency: "direct main" + description: + name: get_test + sha256: "558c39cb35fb37bd501f337dc143de60a4314d5ef3b75f4b0551d6741634995b" + url: "https://pub.dev" + source: hosted + version: "4.0.1" glob: dependency: transitive description: @@ -760,6 +776,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + mockito: + dependency: "direct main" + description: + name: mockito + sha256: "6841eed20a7befac0ce07df8116c8b8233ed1f4486a7647c7fc5a02ae6163917" + url: "https://pub.dev" + source: hosted + version: "5.4.4" nm: dependency: transitive description: @@ -768,6 +792,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" package_config: dependency: transitive description: @@ -1037,6 +1069,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" shelf_web_socket: dependency: transitive description: @@ -1058,6 +1106,30 @@ packages: description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" source_span: dependency: transitive description: @@ -1154,6 +1226,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" + test: + dependency: "direct main" + description: + name: test + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" + url: "https://pub.dev" + source: hosted + version: "1.25.2" test_api: dependency: transitive description: @@ -1162,6 +1242,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.0" + test_core: + dependency: transitive + description: + name: test_core + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" + url: "https://pub.dev" + source: hosted + version: "0.6.0" time: dependency: transitive description: @@ -1362,6 +1450,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 86c46f43..dafde94a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,7 +31,10 @@ dependencies: flutter_platform_widgets: ^6.0.2 flutter_slidable: ^3.0.1 flutter_svg: ^2.0.7 + flutter_test: + sdk: flutter get: ^4.6.5 + get_test: ^4.0.1 google_fonts: ^6.1.0 hive: ^2.2.1 hive_flutter: ^1.1.0 @@ -41,6 +44,7 @@ dependencies: in_app_update: ^4.2.3 intl: ^0.18.0 loggy: ^2.0.1+1 + mockito: ^5.4.4 package_info_plus: ^4.0.2 pem: ^2.0.1 permission_handler: @@ -53,6 +57,7 @@ dependencies: sizer: ^2.0.15 sqflite: ^2.3.3+1 syncfusion_flutter_charts: ^23.2.7 + test: ^1.25.2 timezone: ^0.9.2 tuple: ^2.0.0 tutorial_coach_mark: ^1.2.11 @@ -63,8 +68,6 @@ dev_dependencies: build_runner: null flutter_gen_runner: null flutter_lints: 4.0.0 - flutter_test: - sdk: flutter flutter_gen: output: lib/app/utils/gen/ diff --git a/test/taskfunctions/query_tests.dart b/test/taskfunctions/query_tests.dart new file mode 100644 index 00000000..93396ef0 --- /dev/null +++ b/test/taskfunctions/query_tests.dart @@ -0,0 +1,72 @@ +import 'dart:io'; +import 'package:taskwarrior/app/utils/taskfunctions/query.dart'; +import 'package:test/test.dart'; + +void main() { + late Directory tempDir; + late Query query; + + setUp(() { + tempDir = Directory.systemTemp.createTempSync('query_test'); + query = Query(tempDir); + }); + + tearDown(() { + tempDir.deleteSync(recursive: true); + }); + + test('setSelectedSort and getSelectedSort', () { + const selectedSort = 'priority-'; + query.setSelectedSort(selectedSort); + expect(query.getSelectedSort(), selectedSort); + }); + + test('togglePendingFilter and getPendingFilter', () { + expect(query.getPendingFilter(), true); + query.togglePendingFilter(); + expect(query.getPendingFilter(), false); + query.togglePendingFilter(); + expect(query.getPendingFilter(), true); + }); + + test('toggleWaitingFilter and getWaitingFilter', () { + expect(query.getWaitingFilter(), true); + query.toggleWaitingFilter(); + expect(query.getWaitingFilter(), false); + query.toggleWaitingFilter(); + expect(query.getWaitingFilter(), true); + }); + + test('toggleProjectFilter and projectFilter', () { + const project = 'Work'; + query.toggleProjectFilter(project); + expect(query.projectFilter(), project); + query.toggleProjectFilter(project); + expect(query.projectFilter(), ''); + }); + + test('toggleTagUnion and tagUnion', () { + expect(query.tagUnion(), false); + query.toggleTagUnion(); + expect(query.tagUnion(), true); + query.toggleTagUnion(); + expect(query.tagUnion(), false); + }); + + test('toggleTagFilter and getSelectedTags', () { + const tag1 = 'important'; + const tag2 = 'urgent'; + + query.toggleTagFilter(tag1); + var tags = query.getSelectedTags(); + expect(tags.contains('+$tag1'), true); + + query.toggleTagFilter(tag1); + tags = query.getSelectedTags(); + expect(tags.contains('+$tag1'), false); + + query.toggleTagFilter(tag2); + tags = query.getSelectedTags(); + expect(tags.contains('+$tag2'), true); + }); +} From 08ac7c14f8951de0770b4a7c7515a04870bbf88b Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 20 Jul 2024 11:00:06 +0530 Subject: [PATCH 29/47] Tests added for comparator and query --- test/taskfunctions/comparator_test.dart | 61 +++++++++++++++++++ .../{query_tests.dart => query_test.dart} | 0 2 files changed, 61 insertions(+) create mode 100644 test/taskfunctions/comparator_test.dart rename test/taskfunctions/{query_tests.dart => query_test.dart} (100%) diff --git a/test/taskfunctions/comparator_test.dart b/test/taskfunctions/comparator_test.dart new file mode 100644 index 00000000..7d5cc960 --- /dev/null +++ b/test/taskfunctions/comparator_test.dart @@ -0,0 +1,61 @@ +// ignore_for_file: depend_on_referenced_packages + +import 'package:test/test.dart'; +import 'package:taskwarrior/app/utils/taskfunctions/comparator.dart'; +import 'package:taskwarrior/app/models/json/task.dart'; +import 'package:built_collection/built_collection.dart'; + +void main() { + final task1 = Task((builder) => builder + ..entry = DateTime(2024, 7, 20) + ..modified = DateTime(2024, 7, 21) + ..start = DateTime(2024, 7, 22) + ..due = DateTime(2024, 7, 23) + ..priority = 'H' + ..project = 'Project A' + ..tags = ListBuilder(['tag1', 'tag2'])); + + final task2 = Task((builder) => builder + ..entry = DateTime(2024, 7, 19) + ..modified = DateTime(2024, 7, 18) + ..start = DateTime(2024, 7, 21) + ..due = DateTime(2024, 7, 22) + ..priority = 'L' + ..project = 'Project B' + ..tags = ListBuilder(['tag1'])); + + test('Test compareTasks for Created column', () { + final compare = compareTasks('Created'); + expect(compare(task1, task2), greaterThan(0)); + }); + + test('Test compareTasks for Modified column', () { + final compare = compareTasks('Modified'); + expect(compare(task1, task2), lessThan(0)); + }); + + test('Test compareTasks for Start Time column', () { + final compare = compareTasks('Start Time'); + expect(compare(task1, task2), greaterThan(0)); + }); + + test('Test compareTasks for Priority column', () { + final compare = compareTasks('Priority'); + expect(compare(task1, task2), lessThan(0)); + }); + + test('Test compareTasks for Project column', () { + final compare = compareTasks('Project'); + expect(compare(task1, task2), greaterThan(0)); + }); + + test('Test compareTasks for Tags column', () { + final compare = compareTasks('Tags'); + expect(compare(task1, task2), greaterThan(0)); + }); + + test('Test compareTasks for Urgency column', () { + final compare = compareTasks('Urgency'); + expect(compare(task1, task2), lessThan(0)); + }); +} diff --git a/test/taskfunctions/query_tests.dart b/test/taskfunctions/query_test.dart similarity index 100% rename from test/taskfunctions/query_tests.dart rename to test/taskfunctions/query_test.dart From edad6c4b3eb5326ba053f6e352eb90c5706ef344 Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 20 Jul 2024 11:10:51 +0530 Subject: [PATCH 30/47] Test fix for comparator --- test/taskfunctions/comparator_test.dart | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/test/taskfunctions/comparator_test.dart b/test/taskfunctions/comparator_test.dart index 7d5cc960..38e87122 100644 --- a/test/taskfunctions/comparator_test.dart +++ b/test/taskfunctions/comparator_test.dart @@ -1,9 +1,6 @@ -// ignore_for_file: depend_on_referenced_packages - import 'package:test/test.dart'; import 'package:taskwarrior/app/utils/taskfunctions/comparator.dart'; import 'package:taskwarrior/app/models/json/task.dart'; -import 'package:built_collection/built_collection.dart'; void main() { final task1 = Task((builder) => builder @@ -13,7 +10,11 @@ void main() { ..due = DateTime(2024, 7, 23) ..priority = 'H' ..project = 'Project A' - ..tags = ListBuilder(['tag1', 'tag2'])); + ..tags.replace(['tag1', 'tag2']) + ..status = 'pending' + ..uuid = 'uuid1' + ..description = 'Task 1 Description' + ); final task2 = Task((builder) => builder ..entry = DateTime(2024, 7, 19) @@ -22,7 +23,11 @@ void main() { ..due = DateTime(2024, 7, 22) ..priority = 'L' ..project = 'Project B' - ..tags = ListBuilder(['tag1'])); + ..tags.replace(['tag1']) + ..status = 'pending' + ..uuid = 'uuid2' + ..description = 'Task 2 Description' + ); test('Test compareTasks for Created column', () { final compare = compareTasks('Created'); @@ -31,7 +36,7 @@ void main() { test('Test compareTasks for Modified column', () { final compare = compareTasks('Modified'); - expect(compare(task1, task2), lessThan(0)); + expect(compare(task1, task2), greaterThan(0)); }); test('Test compareTasks for Start Time column', () { @@ -41,12 +46,12 @@ void main() { test('Test compareTasks for Priority column', () { final compare = compareTasks('Priority'); - expect(compare(task1, task2), lessThan(0)); + expect(compare(task1, task2), greaterThan(0)); }); test('Test compareTasks for Project column', () { final compare = compareTasks('Project'); - expect(compare(task1, task2), greaterThan(0)); + expect(compare(task1, task2), lessThan(0)); }); test('Test compareTasks for Tags column', () { From 9de2bd3ba798cb4ae617c1f8f96d6785888a8570 Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 20 Jul 2024 11:40:26 +0530 Subject: [PATCH 31/47] Datetime differences tests added --- .../datetime_differences_test.dart | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 test/taskfunctions/datetime_differences_test.dart diff --git a/test/taskfunctions/datetime_differences_test.dart b/test/taskfunctions/datetime_differences_test.dart new file mode 100644 index 00000000..434771e9 --- /dev/null +++ b/test/taskfunctions/datetime_differences_test.dart @@ -0,0 +1,96 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:taskwarrior/app/utils/taskfunctions/datetime_differences.dart'; + +void main() { + group('DateTime Functions Tests', () { + test('Test age function', () { + DateTime dt = DateTime.now().subtract(const Duration(days: 365)); + String result = age(dt); + expect(result, contains('12mo ')); + + dt = DateTime.now().subtract(const Duration(days: 60)); + result = age(dt); + expect(result, contains('2mo ')); + + dt = DateTime.now().subtract(const Duration(days: 21)); + result = age(dt); + expect(result, contains('3w ')); + + dt = DateTime.now().subtract(const Duration(days: 4)); + result = age(dt); + expect(result, contains('4d ')); + + dt = DateTime.now().subtract(const Duration(hours: 5)); + result = age(dt); + expect(result, contains('5h ')); + + dt = DateTime.now().subtract(const Duration(minutes: 10)); + result = age(dt); + expect(result, contains('10min ')); + + dt = DateTime.now().subtract(const Duration(seconds: 30)); + result = age(dt); + expect(result, contains('30s ')); + }); + + test('Test when function', () { + DateTime dt = DateTime.now().add(const Duration(days: 365)); + String result = when(dt); + expect(result, contains('12mo')); + + dt = DateTime.now().add(const Duration(days: 60)); + result = when(dt); + expect(result, contains('1mo')); + + dt = DateTime.now().add(const Duration(days: 21)); + result = when(dt); + expect(result, contains('2w')); + + dt = DateTime.now().add(const Duration(days: 4)); + result = when(dt); + expect(result, contains('3d')); + + dt = DateTime.now().add(const Duration(hours: 5)); + result = when(dt); + expect(result, contains('4h')); + + dt = DateTime.now().add(const Duration(minutes: 10)); + result = when(dt); + expect(result, contains('9min')); + + dt = DateTime.now().add(const Duration(seconds: 30)); + result = when(dt); + expect(result, contains('29s')); + }); + + test('Test difference function', () { + DateTime dt = DateTime.now().subtract(const Duration(days: 365)); + String result = difference(DateTime.now().difference(dt)); + expect(result, contains('12mo ')); + + dt = DateTime.now().subtract(const Duration(days: 60)); + result = difference(DateTime.now().difference(dt)); + expect(result, contains('2mo ')); + + dt = DateTime.now().subtract(const Duration(days: 21)); + result = difference(DateTime.now().difference(dt)); + expect(result, contains('3w ')); + + dt = DateTime.now().subtract(const Duration(days: 4)); + result = difference(DateTime.now().difference(dt)); + expect(result, contains('4d ')); + + dt = DateTime.now().subtract(const Duration(hours: 5)); + result = difference(DateTime.now().difference(dt)); + expect(result, contains('5h ')); + + dt = DateTime.now().subtract(const Duration(minutes: 10)); + result = difference(DateTime.now().difference(dt)); + expect(result, contains('10min ')); + + dt = DateTime.now().subtract(const Duration(seconds: 30)); + result = difference(DateTime.now().difference(dt)); + expect(result, contains('30s ')); + }); + }); +} From f453e8ffee999500c1f00461c58cb52a5d3fd1bb Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 20 Jul 2024 13:50:36 +0530 Subject: [PATCH 32/47] Draft test added --- test/taskfunctions/draft_test.dart | 92 ++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 test/taskfunctions/draft_test.dart diff --git a/test/taskfunctions/draft_test.dart b/test/taskfunctions/draft_test.dart new file mode 100644 index 00000000..debe15ab --- /dev/null +++ b/test/taskfunctions/draft_test.dart @@ -0,0 +1,92 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:taskwarrior/app/models/models.dart'; +import 'package:taskwarrior/app/utils/taskfunctions/draft.dart'; + +void main() { + group('Draft Tests', () { + test('Setting status to completed updates end date', () { + Task original = Task( + (b) => b + ..id = 1 + ..description = 'Task 1' + ..status = 'pending' + ..start = DateTime.utc(2023, 1, 1) + ..priority = 'H' + ..project = 'Project A' + ..tags.replace(['tag1', 'tag2']) + ..uuid = 'uuid1' + ..description = 'Task 1 Description' + ..entry = DateTime(2024, 7, 20) + ..modified = DateTime(2024, 7, 21) + ..start = DateTime(2024, 7, 22) + ..due = DateTime(2024, 7, 23), + ); + + Draft draft = Draft(original); + + draft.set('status', 'completed'); + + expect(draft.draft.status, 'completed'); + + expect(draft.draft.end, isNotNull); + }); + + test('Setting status to pending does not update end date', () { + Task original = Task( + (b) => b + ..id = 2 + ..description = 'Task 2' + ..status = 'completed' + ..start = DateTime.utc(2023, 1, 1) + ..priority = 'H' + ..project = 'Project A' + ..tags.replace(['tag1', 'tag2']) + ..uuid = 'uuid2' + ..description = 'Task 2 Description' + ..entry = DateTime(2024, 7, 20) + ..modified = DateTime(2024, 7, 21) + ..start = DateTime(2024, 7, 22) + ..due = DateTime(2024, 7, 23), + ); + + Draft draft = Draft(original); + + draft.set('status', 'pending'); + + expect(draft.draft.status, 'pending'); + + expect(draft.draft.end, isNull); + }); + + test('Setting other properties updates correctly', () { + Task original = Task( + (b) => b + ..id = 1 + ..description = 'Task 3' + ..status = 'pending' + ..start = DateTime.utc(2023, 1, 1) + ..priority = 'H' + ..project = 'Project A' + ..tags.replace(['tag1', 'tag2']) + ..uuid = 'uuid3' + ..description = 'Task 3 Description' + ..entry = DateTime(2024, 7, 20) + ..modified = DateTime(2024, 7, 21) + ..start = DateTime(2024, 7, 22) + ..due = DateTime(2024, 7, 23), + ); + + Draft draft = Draft(original); + + draft.set('priority', 'L'); + + expect(draft.draft.priority, 'L'); + + expect(draft.draft.id, original.id); + + expect(draft.draft.description, original.description); + + expect(draft.draft.status, original.status); + }); + }); +} From 1a781f7fb9a615582214edf0b387739192f912bc Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 20 Jul 2024 14:33:48 +0530 Subject: [PATCH 33/47] Patch testcases added --- test/taskfunctions/path_test.dart | 55 +++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 test/taskfunctions/path_test.dart diff --git a/test/taskfunctions/path_test.dart b/test/taskfunctions/path_test.dart new file mode 100644 index 00000000..f262265c --- /dev/null +++ b/test/taskfunctions/path_test.dart @@ -0,0 +1,55 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:taskwarrior/app/models/models.dart'; +import 'package:taskwarrior/app/utils/taskfunctions/patch.dart'; + +void main() { + group('patch function', () { + test('should patch description', () { + Task initialTask = Task( + (b) => b + ..id = 1 + ..description = 'Task 3' + ..status = 'pending' + ..start = DateTime.utc(2023, 1, 1) + ..priority = 'H' + ..project = 'Project A' + ..tags.replace(['tag1', 'tag2']) + ..uuid = 'uuid3' + ..description = 'Task 3 Description' + ..entry = DateTime(2024, 7, 20) + ..modified = DateTime(2024, 7, 21) + ..start = DateTime(2024, 7, 22) + ..due = DateTime(2024, 7, 23), + ); + Map updates = {'description': 'Updated description'}; + + Task patchedTask = patch(initialTask, updates); + + expect(patchedTask.description, 'Updated description'); + }); + + test('should handle unknown keys gracefully', () { + Task initialTask = Task( + (b) => b + ..id = 1 + ..description = 'Task 3' + ..status = 'pending' + ..start = DateTime.utc(2023, 1, 1) + ..priority = 'H' + ..project = 'Project A' + ..tags.replace(['tag1', 'tag2']) + ..uuid = 'uuid3' + ..description = 'Task 3 Description' + ..entry = DateTime(2024, 7, 20) + ..modified = DateTime(2024, 7, 21) + ..start = DateTime(2024, 7, 22) + ..due = DateTime(2024, 7, 23), + ); + Map updates = {'unknownField': 'some value'}; + + Task patchedTask = patch(initialTask, updates); + + expect(patchedTask, initialTask); + }); + }); +} From 9be3607e6ece41b3b4e27b3839b5d43cda8fd5bc Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 20 Jul 2024 14:40:23 +0530 Subject: [PATCH 34/47] Profiles class testcases added --- test/taskfunctions/profiles_test.dart | 67 +++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 test/taskfunctions/profiles_test.dart diff --git a/test/taskfunctions/profiles_test.dart b/test/taskfunctions/profiles_test.dart new file mode 100644 index 00000000..c8c34e1a --- /dev/null +++ b/test/taskfunctions/profiles_test.dart @@ -0,0 +1,67 @@ +import 'dart:io'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:taskwarrior/app/utils/taskfunctions/profiles.dart'; + +void main() { + late Directory testDirectory; + late Profiles profiles; + + setUp(() async { + testDirectory = await Directory.systemTemp.createTemp('test_directory'); + profiles = Profiles(testDirectory); + }); + + tearDown(() { + testDirectory.deleteSync(recursive: true); + }); + + test('Add and list profiles', () { + var profileId = profiles.addProfile(); + + expect(profiles.listProfiles(), contains(profileId)); + }); + + test('Set and get alias', () { + var profileId = profiles.addProfile(); + + profiles.setAlias(profile: profileId, alias: 'Test Alias'); + + var alias = profiles.getAlias(profileId); + expect(alias, 'Test Alias'); + }); + + test('Set and get current profile', () { + var profileId = profiles.addProfile(); + + profiles.setCurrentProfile(profileId); + + var currentProfile = profiles.getCurrentProfile(); + expect(currentProfile, profileId); + }); + + test('Delete profile', () { + var profileId = profiles.addProfile(); + + profiles.deleteProfile(profileId); + + expect(profiles.listProfiles(), isNot(contains(profileId))); + }); + + test('Copy configuration to new profile', () { + var profileId = profiles.addProfile(); + + profiles.copyConfigToNewProfile(profileId); + + expect(Directory('${testDirectory.path}/profiles').listSync(), + hasLength(greaterThan(1))); + }); + + test('Get current storage', () { + var profileId = profiles.addProfile(); + profiles.setCurrentProfile(profileId); + + var storage = profiles.getCurrentStorage(); + + expect(storage, isNotNull); + }); +} From 33c1633eda4a48190efb87c4e8f28bcd24099a21 Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 20 Jul 2024 14:47:49 +0530 Subject: [PATCH 35/47] Projects testcase added --- test/taskfunctions/projects_test.dart | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 test/taskfunctions/projects_test.dart diff --git a/test/taskfunctions/projects_test.dart b/test/taskfunctions/projects_test.dart new file mode 100644 index 00000000..b25288e2 --- /dev/null +++ b/test/taskfunctions/projects_test.dart @@ -0,0 +1,70 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:taskwarrior/app/utils/taskfunctions/projects.dart'; + +void main() { + test('sparseDecoratedProjectTree test', () { + var projects1 = { + 'projectA': 5, + 'projectA.subprojectB': 3, + 'projectA.subprojectC': 2, + 'projectA.subprojectC.subsubprojectD': 1, + }; + var result1 = sparseDecoratedProjectTree(projects1); + expect(result1.keys.toSet(), { + 'projectA', + 'projectA.subprojectB', + 'projectA.subprojectC', + 'projectA.subprojectC.subsubprojectD', + }); + expect(result1['projectA']!.children, { + 'projectA.subprojectB', + 'projectA.subprojectC', + }); + expect(result1['projectA.subprojectC']!.children, { + 'projectA.subprojectC.subsubprojectD', + }); + + var projects2 = { + 'projectX': 10, + 'projectX.subprojectY': 5, + 'projectX.subprojectZ': 3, + 'projectX.subprojectZ.subsubprojectA': 2, + 'projectX.subprojectZ.subsubprojectB': 1, + 'projectX.subprojectZ.subsubprojectC': 4, + }; + var result2 = sparseDecoratedProjectTree(projects2); + expect(result2.keys.toSet(), { + 'projectX', + 'projectX.subprojectY', + 'projectX.subprojectZ', + 'projectX.subprojectZ.subsubprojectA', + 'projectX.subprojectZ.subsubprojectB', + 'projectX.subprojectZ.subsubprojectC', + }); + expect(result2['projectX.subprojectZ.subsubprojectA']!.parent, 'projectX.subprojectZ'); + expect(result2['projectX.subprojectZ.subsubprojectC']!.parent, 'projectX.subprojectZ'); + + var projects3 = { + 'rootProject': 0, + }; + var result3 = sparseDecoratedProjectTree(projects3); + expect(result3.keys, ['rootProject']); + expect(result3['rootProject']!.children.isEmpty, true); + expect(result3['rootProject']!.parent, null); + + var projects4 = { + 'projectP': 2, + 'projectP.subprojectQ': 3, + 'projectP.subprojectQ.subsubprojectR': 1, + }; + var result4 = sparseDecoratedProjectTree(projects4); + expect(result4.keys.toSet(), { + 'projectP', + 'projectP.subprojectQ', + 'projectP.subprojectQ.subsubprojectR', + }); + expect(result4['projectP.subprojectQ.subsubprojectR']!.parent, 'projectP.subprojectQ'); + + + }); +} From 3c01816400a64888d8f0ca1fb49a96f9bfb9f202 Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 20 Jul 2024 14:50:47 +0530 Subject: [PATCH 36/47] Validate test added --- test/taskfunctions/validate_test.dart | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test/taskfunctions/validate_test.dart diff --git a/test/taskfunctions/validate_test.dart b/test/taskfunctions/validate_test.dart new file mode 100644 index 00000000..03c2c5aa --- /dev/null +++ b/test/taskfunctions/validate_test.dart @@ -0,0 +1,24 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:taskwarrior/app/utils/taskfunctions/validate.dart'; + +void main() { + test('validateTaskDescription', () { + expect(() => validateTaskDescription('Write test cases'), returnsNormally); + + expect(() => validateTaskDescription(''), throwsFormatException); + + expect(() => validateTaskDescription('Do something\\'), throwsFormatException); + }); + + test('validateTaskProject', () { + expect(() => validateTaskProject('Personal'), returnsNormally); + + expect(() => validateTaskProject('Work\\'), throwsFormatException); + }); + + test('validateTaskTags', () { + expect(() => validateTaskTags('important'), returnsNormally); + + expect(() => validateTaskTags('urgent tasks'), throwsFormatException); + }); +} From 0fe10ac4ca19e7cda65244c74882ed3fd67abd3b Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 27 Jul 2024 19:33:02 +0530 Subject: [PATCH 37/47] Task parser tests added --- test/taskfunctions/taskparser_test.dart | 64 +++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 test/taskfunctions/taskparser_test.dart diff --git a/test/taskfunctions/taskparser_test.dart b/test/taskfunctions/taskparser_test.dart new file mode 100644 index 00000000..4f1973b7 --- /dev/null +++ b/test/taskfunctions/taskparser_test.dart @@ -0,0 +1,64 @@ +import 'package:taskwarrior/app/utils/taskfunctions/taskparser.dart'; +import 'package:test/test.dart'; + +void main() { + group('taskParser', () { + test('parses a task with multiple attributes and tags', () { + const taskString = + '+tag1 status:completed project:work priority:high due:2024-12-31T23:59:59Z This is a complex task'; + final task = taskParser(taskString); + expect(task.description, 'This is a complex task'); + expect(task.status, 'completed'); + expect(task.project, 'work'); + expect(task.priority, 'high'); + expect(task.due, DateTime.parse('2024-12-31T23:59:59Z').toUtc()); + expect(task.wait, isNull); + expect(task.until, isNull); + expect(task.tags, ['tag1']); + }); + + test('parses a task with long description and tags', () { + const taskString = '+longtag1 +longtag2 ' + 'This is a very long description that goes on and on, potentially including special characters and a very long string to test how the parser handles such cases'; + final task = taskParser(taskString); + expect(task.description, + 'This is a very long description that goes on and on, potentially including special characters and a very long string to test how the parser handles such cases'); + expect(task.status, 'pending'); + expect(task.project, isNull); + expect(task.priority, isNull); + expect(task.due, isNull); + expect(task.wait, isNull); + expect(task.until, isNull); + expect(task.tags, ['longtag1', 'longtag2']); + }); + + test('parses a task with mixed attribute formats', () { + const taskString = + 'status:completed prio:high project:work +tag1 This is a task with mixed attribute formats'; + final task = taskParser(taskString); + expect(task.description, 'This is a task with mixed attribute formats'); + expect(task.status, 'completed'); + expect(task.project, 'work'); + expect(task.priority, 'high'); + expect(task.due, isNull); + expect(task.wait, isNull); + expect(task.until, isNull); + expect(task.tags, ['tag1']); + }); + + test('parses a task with overlapping attributes and tags', () { + const taskString = + '+tag1 status:completed project:work +tag2 This is a task with overlapping attributes and tags'; + final task = taskParser(taskString); + expect(task.description, + 'This is a task with overlapping attributes and tags'); + expect(task.status, 'completed'); + expect(task.project, 'work'); + expect(task.priority, isNull); + expect(task.due, isNull); + expect(task.wait, isNull); + expect(task.until, isNull); + expect(task.tags, ['tag1', 'tag2']); + }); + }); +} From 5eb6a6f2a75f59897094b2fbd90c7dadaf353ee5 Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 27 Jul 2024 19:49:52 +0530 Subject: [PATCH 38/47] Path renamed --- test/taskfunctions/{path_test.dart => patch_test.dart} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/taskfunctions/{path_test.dart => patch_test.dart} (100%) diff --git a/test/taskfunctions/path_test.dart b/test/taskfunctions/patch_test.dart similarity index 100% rename from test/taskfunctions/path_test.dart rename to test/taskfunctions/patch_test.dart From 817695b8b993008aa462810f6e7e59728ebaa778 Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 27 Jul 2024 19:58:51 +0530 Subject: [PATCH 39/47] tags testcases added --- test/taskfunctions/tags_test.dart | 318 ++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 test/taskfunctions/tags_test.dart diff --git a/test/taskfunctions/tags_test.dart b/test/taskfunctions/tags_test.dart new file mode 100644 index 00000000..c2067b21 --- /dev/null +++ b/test/taskfunctions/tags_test.dart @@ -0,0 +1,318 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:taskwarrior/app/models/models.dart'; +import 'package:taskwarrior/app/utils/taskfunctions/tags.dart'; + +void main() { + group('tagSet', () { + test('should return all unique tags from tasks', () { + final tasks = [ + Task((b) => b + ..id = 1 + ..description = 'Task 1' + ..status = 'pending' + ..tags.replace(['tag1', 'tag2']) + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project A' + ..uuid = 'uuid1'), + Task((b) => b + ..id = 2 + ..description = 'Task 2' + ..status = 'pending' + ..tags.replace(['tag2', 'tag3']) + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project B' + ..uuid = 'uuid2'), + ]; + + final result = tagSet(tasks); + expect(result, {'tag1', 'tag2', 'tag3'}); + }); + + test('should return an empty set if no tasks', () { + final tasks = []; + + final result = tagSet(tasks); + expect(result, {}); + }); + + test('should return an empty set if tasks have no tags', () { + final tasks = [ + Task((b) => b + ..id = 1 + ..description = 'Task 1' + ..status = 'pending' + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project A' + ..uuid = 'uuid1'), + Task((b) => b + ..id = 2 + ..description = 'Task 2' + ..status = 'pending' + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project B' + ..uuid = 'uuid2'), + ]; + + final result = tagSet(tasks); + expect(result, {}); + }); + }); + + group('tagFrequencies', () { + test('should count the frequency of each tag correctly', () { + final tasks = [ + Task((b) => b + ..id = 1 + ..description = 'Task 1' + ..status = 'pending' + ..tags.replace(['tag1', 'tag2']) + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project A' + ..uuid = 'uuid1'), + Task((b) => b + ..id = 2 + ..description = 'Task 2' + ..status = 'pending' + ..tags.replace(['tag2', 'tag3']) + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project B' + ..uuid = 'uuid2'), + Task((b) => b + ..id = 3 + ..description = 'Task 3' + ..status = 'pending' + ..tags.replace(['tag2']) + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project C' + ..uuid = 'uuid3'), + ]; + + final result = tagFrequencies(tasks); + expect(result, {'tag1': 1, 'tag2': 3, 'tag3': 1}); + }); + + test('should return an empty map if no tasks', () { + final tasks = []; + + final result = tagFrequencies(tasks); + expect(result, {}); + }); + + test('should return an empty map if tasks have no tags', () { + final tasks = [ + Task((b) => b + ..id = 1 + ..description = 'Task 1' + ..status = 'pending' + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project A' + ..uuid = 'uuid1'), + Task((b) => b + ..id = 2 + ..description = 'Task 2' + ..status = 'pending' + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project B' + ..uuid = 'uuid2'), + ]; + + final result = tagFrequencies(tasks); + expect(result, {}); + }); + + test('should count tags correctly with overlapping tasks', () { + final tasks = [ + Task((b) => b + ..id = 1 + ..description = 'Task 1' + ..status = 'pending' + ..tags.replace(['tag1', 'tag2']) + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project A' + ..uuid = 'uuid1'), + Task((b) => b + ..id = 2 + ..description = 'Task 2' + ..status = 'pending' + ..tags.replace(['tag1', 'tag2', 'tag3']) + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project B' + ..uuid = 'uuid2'), + Task((b) => b + ..id = 3 + ..description = 'Task 3' + ..status = 'pending' + ..tags.replace(['tag2', 'tag3']) + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project C' + ..uuid = 'uuid3'), + ]; + + final result = tagFrequencies(tasks); + expect(result, {'tag1': 2, 'tag2': 3, 'tag3': 2}); + }); + }); + + group('tagsLastModified', () { + test('should return the latest modification date for each tag', () { + final tasks = [ + Task((b) => b + ..id = 1 + ..description = 'Task 1' + ..status = 'pending' + ..tags.replace(['tag1']) + ..modified = DateTime.utc(2024, 1, 1) + ..start = DateTime.now() + ..entry = DateTime.now() + ..due = DateTime.now() + ..project = 'Project A' + ..uuid = 'uuid1'), + Task((b) => b + ..id = 2 + ..description = 'Task 2' + ..status = 'pending' + ..tags.replace(['tag2']) + ..modified = DateTime.utc(2024, 2, 1) + ..start = DateTime.now() + ..entry = DateTime.now() + ..due = DateTime.now() + ..project = 'Project B' + ..uuid = 'uuid2'), + Task((b) => b + ..id = 3 + ..description = 'Task 3' + ..status = 'pending' + ..tags.replace(['tag1', 'tag3']) + ..modified = DateTime.utc(2024, 3, 1) + ..start = DateTime.now() + ..entry = DateTime.now() + ..due = DateTime.now() + ..project = 'Project C' + ..uuid = 'uuid3'), + ]; + + final result = tagsLastModified(tasks); + expect(result, { + 'tag1': DateTime.utc(2024, 3, 1), + 'tag2': DateTime.utc(2024, 2, 1), + 'tag3': DateTime.utc(2024, 3, 1), + }); + }); + + test('should return an empty map if no tasks', () { + final tasks = []; + + final result = tagsLastModified(tasks); + expect(result, {}); + }); + + test('should return an empty map if tasks have no tags', () { + final tasks = [ + Task((b) => b + ..id = 1 + ..description = 'Task 1' + ..status = 'pending' + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project A' + ..uuid = 'uuid1'), + Task((b) => b + ..id = 2 + ..description = 'Task 2' + ..status = 'pending' + ..start = DateTime.now() + ..entry = DateTime.now() + ..modified = DateTime.now() + ..due = DateTime.now() + ..project = 'Project B' + ..uuid = 'uuid2'), + ]; + + final result = tagsLastModified(tasks); + expect(result, {}); + }); + + test('should return correct modification dates with overlapping tags', () { + final tasks = [ + Task((b) => b + ..id = 1 + ..description = 'Task 1' + ..status = 'pending' + ..tags.replace(['tag1', 'tag2']) + ..modified = DateTime.utc(2024, 1, 1) + ..start = DateTime.now() + ..entry = DateTime.now() + ..due = DateTime.now() + ..project = 'Project A' + ..uuid = 'uuid1'), + Task((b) => b + ..id = 2 + ..description = 'Task 2' + ..status = 'pending' + ..tags.replace(['tag2', 'tag3']) + ..modified = DateTime.utc(2024, 2, 1) + ..start = DateTime.now() + ..entry = DateTime.now() + ..due = DateTime.now() + ..project = 'Project B' + ..uuid = 'uuid2'), + Task((b) => b + ..id = 3 + ..description = 'Task 3' + ..status = 'pending' + ..tags.replace(['tag3']) + ..modified = DateTime.utc(2024, 3, 1) + ..start = DateTime.now() + ..entry = DateTime.now() + ..due = DateTime.now() + ..project = 'Project C' + ..uuid = 'uuid3'), + ]; + + final result = tagsLastModified(tasks); + expect(result, { + 'tag1': DateTime.utc(2024, 1, 1), + 'tag2': DateTime.utc(2024, 2, 1), + 'tag3': DateTime.utc(2024, 3, 1), + }); + }); + }); +} From bcce8213b99d39b1e41979bfa14a09358df733a6 Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 27 Jul 2024 21:16:04 +0530 Subject: [PATCH 40/47] Added run: flutter test in github workflow --- .github/workflows/flutterci.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/flutterci.yml b/.github/workflows/flutterci.yml index d23daeb1..22d22120 100644 --- a/.github/workflows/flutterci.yml +++ b/.github/workflows/flutterci.yml @@ -34,12 +34,11 @@ jobs: # Step 5: Analyze the code using flutter analyze - run: flutter analyze - # Step 6: Format the code using flutter format - # - run: flutter format -n --set-exit-if-changed . + # Step 6: Format the code using flutter format (uncomment if needed) + # - run: flutter format -n --set-exit-if-changed . # Step 7: Run tests using flutter test - # - run: flutter test - + - run: flutter test # Step 8: Build APK using flutter build apk - run: flutter build apk From 0c2dd10cf745271535202eec9f9b94f50ffc6b15 Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 27 Jul 2024 21:48:43 +0530 Subject: [PATCH 41/47] Added translations for profile page --- lib/app/utils/language/english_sentences.dart | 31 +++++++++++++++++++ lib/app/utils/language/sentences.dart | 16 ++++++++++ 2 files changed, 47 insertions(+) diff --git a/lib/app/utils/language/english_sentences.dart b/lib/app/utils/language/english_sentences.dart index 4a799845..0635c59b 100644 --- a/lib/app/utils/language/english_sentences.dart +++ b/lib/app/utils/language/english_sentences.dart @@ -206,4 +206,35 @@ class EnglishSentences extends Sentences { @override String get deleteTaskWarning => 'The action is irreversible and will delete all the tasks that are stored locally.'; + + @override + String get profilePageProfile => 'Profile'; + @override + String get profilePageProfiles => 'Profiles'; + @override + String get profilePageCurrentProfile => 'Current Profile'; + @override + String get profilePageManageSelectedProfile => 'Manage Selected Profile'; + @override + String get profilePageRenameAlias => 'Rename Alias'; + + @override + String get profilePageConfigureTaskserver => 'Configure Taskserver'; + @override + String get profilePageExportTasks => 'Export Tasks'; + @override + String get profilePageCopyConfigToNewProfile => 'Copy Config To New Profile'; + @override + String get profilePageDeleteProfile => 'Delete Profile'; + @override + String get profilePageAddNewProfile => 'Add New Profile'; + + @override + String get profilePageRenameAliasDialogueBoxTitle => 'Rename Alias'; + @override + String get profilePageRenameAliasDialogueBoxNewAlias => 'New Alias'; + @override + String get profilePageRenameAliasDialogueBoxCancel => 'Cancel'; + @override + String get profilePageRenameAliasDialogueBoxSubmit => 'Submit'; } diff --git a/lib/app/utils/language/sentences.dart b/lib/app/utils/language/sentences.dart index 4939cd3c..8d3af13d 100644 --- a/lib/app/utils/language/sentences.dart +++ b/lib/app/utils/language/sentences.dart @@ -106,4 +106,20 @@ abstract class Sentences { String get reportsPageNoTasksFound; String get reportsPageAddTasksToSeeReports; + + String get profilePageProfile; + String get profilePageProfiles; + String get profilePageCurrentProfile; + String get profilePageManageSelectedProfile; + String get profilePageRenameAlias; + String get profilePageConfigureTaskserver; + String get profilePageExportTasks; + String get profilePageCopyConfigToNewProfile; + String get profilePageDeleteProfile; + String get profilePageAddNewProfile; + + String get profilePageRenameAliasDialogueBoxTitle; + String get profilePageRenameAliasDialogueBoxNewAlias; + String get profilePageRenameAliasDialogueBoxCancel; + String get profilePageRenameAliasDialogueBoxSubmit; } From fa27b8c032f897cf624a555a0b03210879bacd1f Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 27 Jul 2024 21:59:41 +0530 Subject: [PATCH 42/47] Added manage task server translations --- lib/app/utils/language/english_sentences.dart | 20 +++++++++++++++++++ lib/app/utils/language/sentences.dart | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/lib/app/utils/language/english_sentences.dart b/lib/app/utils/language/english_sentences.dart index 0635c59b..b356bd2e 100644 --- a/lib/app/utils/language/english_sentences.dart +++ b/lib/app/utils/language/english_sentences.dart @@ -237,4 +237,24 @@ class EnglishSentences extends Sentences { String get profilePageRenameAliasDialogueBoxCancel => 'Cancel'; @override String get profilePageRenameAliasDialogueBoxSubmit => 'Submit'; + + @override + String get manageTaskServerPageConfigureTaskserver => 'Configure Task Server'; + @override + String get manageTaskServerPageConfigureTASKRC => 'Configure TASKRC'; + @override + String get manageTaskServerPageSetTaskRC => 'Set TaskRC'; + @override + String get manageTaskServerPageConfigureYourCertificate => + 'Configure Your Certificate'; + @override + String get manageTaskServerPageSelectCertificate => 'Select Certificate'; + @override + String get manageTaskServerPageConfigureTaskserverKey => + 'Configure Task Server Key'; + @override + String get manageTaskServerPageSelectKey => 'Select Key'; + @override + String get manageTaskServerPageConfigureServerCertificate => + 'Configure Server Certificate'; } diff --git a/lib/app/utils/language/sentences.dart b/lib/app/utils/language/sentences.dart index 8d3af13d..ba4f49b5 100644 --- a/lib/app/utils/language/sentences.dart +++ b/lib/app/utils/language/sentences.dart @@ -122,4 +122,13 @@ abstract class Sentences { String get profilePageRenameAliasDialogueBoxNewAlias; String get profilePageRenameAliasDialogueBoxCancel; String get profilePageRenameAliasDialogueBoxSubmit; + + String get manageTaskServerPageConfigureTaskserver; + String get manageTaskServerPageConfigureTASKRC; + String get manageTaskServerPageSetTaskRC; + String get manageTaskServerPageConfigureYourCertificate; + String get manageTaskServerPageSelectCertificate; + String get manageTaskServerPageConfigureTaskserverKey; + String get manageTaskServerPageSelectKey; + String get manageTaskServerPageConfigureServerCertificate; } From 1c1fa2238b09e778873fff00af4af852042504b9 Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 27 Jul 2024 22:07:36 +0530 Subject: [PATCH 43/47] Add marathi and hindi translations --- lib/app/utils/language/english_sentences.dart | 11 +++ lib/app/utils/language/hindi_sentences.dart | 61 ++++++++++++++++ lib/app/utils/language/marathi_sentences.dart | 69 +++++++++++++++++++ lib/app/utils/language/sentences.dart | 6 ++ 4 files changed, 147 insertions(+) diff --git a/lib/app/utils/language/english_sentences.dart b/lib/app/utils/language/english_sentences.dart index b356bd2e..88d46d8b 100644 --- a/lib/app/utils/language/english_sentences.dart +++ b/lib/app/utils/language/english_sentences.dart @@ -257,4 +257,15 @@ class EnglishSentences extends Sentences { @override String get manageTaskServerPageConfigureServerCertificate => 'Configure Server Certificate'; + + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxTitle => 'Configure TaskRC'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxSubtitle => 'Paste the TaskRC content or select taskrc file'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxInputFieldText => 'Paste your TaskRC content here'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxOr => 'Or'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC => 'Select TaskRC file'; } diff --git a/lib/app/utils/language/hindi_sentences.dart b/lib/app/utils/language/hindi_sentences.dart index 99a5cadb..801aa115 100644 --- a/lib/app/utils/language/hindi_sentences.dart +++ b/lib/app/utils/language/hindi_sentences.dart @@ -208,4 +208,65 @@ class HindiSentences extends Sentences { @override String get deleteTaskWarning => 'यह क्रिया अपरिवर्तनीय है और यह सभी स्थानीय रूप से संग्रहीत कार्यों को हटा देगी।'; + + + @override + String get profilePageProfile => 'प्रोफ़ाइल'; + @override + String get profilePageProfiles => 'प्रोफ़ाइल्स'; + @override + String get profilePageCurrentProfile => 'वर्तमान प्रोफ़ाइल'; + @override + String get profilePageManageSelectedProfile => 'चुनी हुई प्रोफ़ाइल प्रबंधित करें'; + @override + String get profilePageRenameAlias => 'उपनाम बदलें'; + + @override + String get profilePageConfigureTaskserver => 'टास्क सर्वर कॉन्फ़िगर करें'; + @override + String get profilePageExportTasks => 'कार्य निर्यात करें'; + @override + String get profilePageCopyConfigToNewProfile => 'नई प्रोफ़ाइल पर कॉन्फ़िगरेशन कॉपी करें'; + @override + String get profilePageDeleteProfile => 'प्रोफ़ाइल हटाएँ'; + @override + String get profilePageAddNewProfile => 'नई प्रोफ़ाइल जोड़ें'; + + @override + String get profilePageRenameAliasDialogueBoxTitle => 'उपनाम बदलें'; + @override + String get profilePageRenameAliasDialogueBoxNewAlias => 'नया उपनाम'; + @override + String get profilePageRenameAliasDialogueBoxCancel => 'रद्द करें'; + @override + String get profilePageRenameAliasDialogueBoxSubmit => 'प्रस्तुत करें'; + + @override + String get manageTaskServerPageConfigureTaskserver => 'टास्क सर्वर कॉन्फ़िगर करें'; + @override + String get manageTaskServerPageConfigureTASKRC => 'TASKRC कॉन्फ़िगर करें'; + @override + String get manageTaskServerPageSetTaskRC => 'TaskRC सेट करें'; + @override + String get manageTaskServerPageConfigureYourCertificate => 'अपने सर्टिफिकेट को कॉन्फ़िगर करें'; + @override + String get manageTaskServerPageSelectCertificate => 'सर्टिफिकेट चुनें'; + @override + String get manageTaskServerPageConfigureTaskserverKey => 'टास्क सर्वर की कॉन्फ़िगर करें'; + @override + String get manageTaskServerPageSelectKey => 'कुंजी चुनें'; + @override + String get manageTaskServerPageConfigureServerCertificate => 'सर्वर सर्टिफिकेट कॉन्फ़िगर करें'; + + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxTitle => 'TaskRC कॉन्फ़िगर करें'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxSubtitle => 'TaskRC सामग्री पेस्ट करें या taskrc फ़ाइल चुनें'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxInputFieldText => 'यहाँ अपनी TaskRC सामग्री पेस्ट करें'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxOr => 'या'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC => 'TaskRC फ़ाइल चुनें'; + } diff --git a/lib/app/utils/language/marathi_sentences.dart b/lib/app/utils/language/marathi_sentences.dart index 27bbaa91..24963d7c 100644 --- a/lib/app/utils/language/marathi_sentences.dart +++ b/lib/app/utils/language/marathi_sentences.dart @@ -207,4 +207,73 @@ class MarathiSentences extends Sentences { @override String get deleteTaskWarning => 'ही क्रिया अपरिवर्तनीय आहे आणि हे सर्व स्थानिक पातळीवर संग्रहित केलेले कार्य हटवेल.'; + + @override + String get profilePageProfile => 'प्रोफाइल'; + @override + String get profilePageProfiles => 'प्रोफाइल्स'; + @override + String get profilePageCurrentProfile => 'सद्याचा प्रोफाइल'; + @override + String get profilePageManageSelectedProfile => + 'चयनित प्रोफाइल व्यवस्थापित करा'; + @override + String get profilePageRenameAlias => 'उपनाम पुनर्नामित करा'; + + @override + String get profilePageConfigureTaskserver => 'टास्क सर्व्हर कॉन्फिगर करा'; + @override + String get profilePageExportTasks => 'टास्क निर्यात करा'; + @override + String get profilePageCopyConfigToNewProfile => + 'नवीन प्रोफाइलवर कॉन्फिगरेशन कॉपी करा'; + @override + String get profilePageDeleteProfile => 'प्रोफाइल हटवा'; + @override + String get profilePageAddNewProfile => 'नवीन प्रोफाइल जोडा'; + + @override + String get profilePageRenameAliasDialogueBoxTitle => 'उपनाम पुनर्नामित करा'; + @override + String get profilePageRenameAliasDialogueBoxNewAlias => 'नवा उपनाम'; + @override + String get profilePageRenameAliasDialogueBoxCancel => 'रद्द करा'; + @override + String get profilePageRenameAliasDialogueBoxSubmit => 'सादर करा'; + + @override + String get manageTaskServerPageConfigureTaskserver => + 'टास्क सर्व्हर कॉन्फिगर करा'; + @override + String get manageTaskServerPageConfigureTASKRC => 'TASKRC कॉन्फिगर करा'; + @override + String get manageTaskServerPageSetTaskRC => 'TaskRC सेट करा'; + @override + String get manageTaskServerPageConfigureYourCertificate => + 'आपला सर्टिफिकेट कॉन्फिगर करा'; + @override + String get manageTaskServerPageSelectCertificate => 'सर्टिफिकेट निवडा'; + @override + String get manageTaskServerPageConfigureTaskserverKey => + 'टास्क सर्व्हर की कॉन्फिगर करा'; + @override + String get manageTaskServerPageSelectKey => 'की निवडा'; + @override + String get manageTaskServerPageConfigureServerCertificate => + 'सर्व्हर सर्टिफिकेट कॉन्फिगर करा'; + + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxTitle => + 'TaskRC कॉन्फिगर करा'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxSubtitle => + 'TaskRC सामग्री पेस्ट करा किंवा taskrc फाइल निवडा'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxInputFieldText => + 'येथे आपली TaskRC सामग्री पेस्ट करा'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxOr => 'किंवा'; + @override + String get manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC => + 'TaskRC फाइल निवडा'; } diff --git a/lib/app/utils/language/sentences.dart b/lib/app/utils/language/sentences.dart index ba4f49b5..823262ae 100644 --- a/lib/app/utils/language/sentences.dart +++ b/lib/app/utils/language/sentences.dart @@ -131,4 +131,10 @@ abstract class Sentences { String get manageTaskServerPageConfigureTaskserverKey; String get manageTaskServerPageSelectKey; String get manageTaskServerPageConfigureServerCertificate; + + String get manageTaskServerPageConfigureTaskRCDialogueBoxTitle; + String get manageTaskServerPageConfigureTaskRCDialogueBoxSubtitle; + String get manageTaskServerPageConfigureTaskRCDialogueBoxInputFieldText; + String get manageTaskServerPageConfigureTaskRCDialogueBoxOr; + String get manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC; } From e3a97b0199337423ab7c151c3f06f2c2a126e75f Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 27 Jul 2024 22:30:45 +0530 Subject: [PATCH 44/47] Added translations for profile page --- .../profile/views/deleteprofiledialog.dart | 6 ++- .../modules/profile/views/manageprofile.dart | 45 ++++++++++++++++--- .../modules/profile/views/profile_view.dart | 20 +++++++-- .../profile/views/renameprofiledialog.dart | 14 ++++-- .../modules/profile/views/selectprofile.dart | 6 ++- 5 files changed, 77 insertions(+), 14 deletions(-) diff --git a/lib/app/modules/profile/views/deleteprofiledialog.dart b/lib/app/modules/profile/views/deleteprofiledialog.dart index eb80a298..2f98ad78 100644 --- a/lib/app/modules/profile/views/deleteprofiledialog.dart +++ b/lib/app/modules/profile/views/deleteprofiledialog.dart @@ -3,6 +3,7 @@ import 'package:get/get.dart'; import 'package:taskwarrior/app/modules/splash/controllers/splash_controller.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/utilites.dart'; +import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; class DeleteProfileDialog extends StatelessWidget { @@ -23,7 +24,10 @@ class DeleteProfileDialog extends StatelessWidget { child: Utils.showAlertDialog( scrollable: true, title: Text( - 'Delete Profile?', + SentenceManager( + currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageDeleteProfile, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white diff --git a/lib/app/modules/profile/views/manageprofile.dart b/lib/app/modules/profile/views/manageprofile.dart index 5d1f437f..d49c9f98 100644 --- a/lib/app/modules/profile/views/manageprofile.dart +++ b/lib/app/modules/profile/views/manageprofile.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; import 'package:tuple/tuple.dart'; @@ -25,11 +26,41 @@ class ManageProfile extends StatelessWidget { @override Widget build(BuildContext context) { var triples = [ - Tuple3(Icons.edit, 'Rename Alias', rename), - Tuple3(Icons.link, 'Configure Taskserver', configure), - Tuple3(Icons.upload, 'Export tasks', export), - Tuple3(Icons.copy, 'Copy config to new profile', copy), - Tuple3(Icons.delete, 'Delete profile', delete), + Tuple3( + Icons.edit, + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageRenameAlias, + rename, + ), + Tuple3( + Icons.link, + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageConfigureTaskserver, + configure, + ), + Tuple3( + Icons.upload, + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageExportTasks, + export, + ), + Tuple3( + Icons.copy, + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageCopyConfigToNewProfile, + copy, + ), + Tuple3( + Icons.delete, + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageDeleteProfile, + delete, + ), ]; return ExpansionTile( @@ -49,7 +80,9 @@ class ManageProfile extends StatelessWidget { ? TaskWarriorColors.white : TaskWarriorColors.black, title: Text( - 'Manage selected profile', + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageManageSelectedProfile, style: GoogleFonts.poppins( fontWeight: TaskWarriorFonts.bold, fontSize: TaskWarriorFonts.fontSizeMedium, diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart index ef1931bb..c2670863 100644 --- a/lib/app/modules/profile/views/profile_view.dart +++ b/lib/app/modules/profile/views/profile_view.dart @@ -11,6 +11,7 @@ import 'package:taskwarrior/app/routes/app_pages.dart'; import 'package:taskwarrior/app/utils/constants/palette.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/utilites.dart'; +import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; import '../controllers/profile_controller.dart'; @@ -25,8 +26,18 @@ class ProfileView extends GetView { appBar: AppBar( backgroundColor: Palette.kToDark.shade200, title: Obx(() => Text( - controller.profilesMap.length == 1 ? 'Profile' : 'Profiles', - style: GoogleFonts.poppins(color: TaskWarriorColors.white), + controller.profilesMap.length == 1 + ? SentenceManager( + currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageProfile + : SentenceManager( + currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageProfiles, + style: GoogleFonts.poppins( + color: TaskWarriorColors.white, + ), )), leading: IconButton( onPressed: () { @@ -302,7 +313,10 @@ class ProfilesColumn extends StatelessWidget { ? TaskWarriorColors.deepPurpleAccent : TaskWarriorColors.deepPurple), label: Text( - 'Add new Profile', + SentenceManager( + currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageAddNewProfile, key: addNewProfileKey, style: TextStyle( color: AppSettings.isDarkMode diff --git a/lib/app/modules/profile/views/renameprofiledialog.dart b/lib/app/modules/profile/views/renameprofiledialog.dart index 4a60e4a6..38cfe4a0 100644 --- a/lib/app/modules/profile/views/renameprofiledialog.dart +++ b/lib/app/modules/profile/views/renameprofiledialog.dart @@ -3,6 +3,7 @@ import 'package:get/get.dart'; import 'package:taskwarrior/app/modules/splash/controllers/splash_controller.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/utilites.dart'; +import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; class RenameProfileDialog extends StatelessWidget { @@ -26,7 +27,10 @@ class RenameProfileDialog extends StatelessWidget { child: Utils.showAlertDialog( scrollable: true, title: Text( - 'Rename Alias', + SentenceManager( + currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageRenameAliasDialogueBoxTitle, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -47,7 +51,9 @@ class RenameProfileDialog extends StatelessWidget { Get.back(); }, child: Text( - 'Cancel', + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageRenameAliasDialogueBoxCancel, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -65,7 +71,9 @@ class RenameProfileDialog extends StatelessWidget { Get.back(); }, child: Text( - 'Submit', + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageRenameAliasDialogueBoxSubmit, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.black diff --git a/lib/app/modules/profile/views/selectprofile.dart b/lib/app/modules/profile/views/selectprofile.dart index c22c4412..ad947b30 100644 --- a/lib/app/modules/profile/views/selectprofile.dart +++ b/lib/app/modules/profile/views/selectprofile.dart @@ -5,6 +5,7 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; class SelectProfile extends StatelessWidget { @@ -44,7 +45,10 @@ class SelectProfile extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Current Profile:', + SentenceManager( + currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageCurrentProfile, key : currentProfileKey, overflow: TextOverflow.fade, style: GoogleFonts.poppins( From 116a355572f333d5f6f2867438455827f8e4ad2a Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 27 Jul 2024 22:34:17 +0530 Subject: [PATCH 45/47] Added multi lang in the dialogue box --- .../views/manage_task_server_page_body.dart | 95 +++++++++++-------- 1 file changed, 58 insertions(+), 37 deletions(-) diff --git a/lib/app/modules/manageTaskServer/views/manage_task_server_page_body.dart b/lib/app/modules/manageTaskServer/views/manage_task_server_page_body.dart index 908dad93..1bebcc06 100644 --- a/lib/app/modules/manageTaskServer/views/manage_task_server_page_body.dart +++ b/lib/app/modules/manageTaskServer/views/manage_task_server_page_body.dart @@ -8,6 +8,7 @@ import 'package:taskwarrior/app/models/storage/set_config.dart'; import 'package:taskwarrior/app/modules/manageTaskServer/views/pem_widget.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; +import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; @@ -76,7 +77,11 @@ class ManageTaskServerPageBody extends StatelessWidget { MainAxisAlignment.start, children: [ Text( - 'Configure TaskRc', + SentenceManager( + currentLanguage: AppSettings + .selectedLanguage) + .sentences + .manageTaskServerPageConfigureTaskRCDialogueBoxTitle, style: TextStyle( fontWeight: TaskWarriorFonts.bold, color: AppSettings.isDarkMode @@ -85,7 +90,11 @@ class ManageTaskServerPageBody extends StatelessWidget { ), ), Text( - 'Paste the taskrc content or select taskrc file', + SentenceManager( + currentLanguage: AppSettings + .selectedLanguage) + .sentences + .manageTaskServerPageConfigureTaskRCDialogueBoxSubtitle, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -107,44 +116,52 @@ class ManageTaskServerPageBody extends StatelessWidget { .taskrcContentController, maxLines: 8, decoration: InputDecoration( - counterStyle: TextStyle( - color: - AppSettings.isDarkMode - ? TaskWarriorColors - .white - : TaskWarriorColors - .black), - suffixIconConstraints: - const BoxConstraints( - maxHeight: 24, - maxWidth: 24, - ), - isDense: true, - suffix: IconButton( - onPressed: () async { - controller - .setContent(context); - }, - icon: const Icon( - Icons.content_paste), - ), - border: - const OutlineInputBorder(), - labelStyle: - GoogleFonts.poppins( - color: AppSettings - .isDarkMode - ? TaskWarriorColors - .white - : TaskWarriorColors - .black), - labelText: - 'Paste your taskrc contents here'), + counterStyle: TextStyle( + color: + AppSettings.isDarkMode + ? TaskWarriorColors + .white + : TaskWarriorColors + .black), + suffixIconConstraints: + const BoxConstraints( + maxHeight: 24, + maxWidth: 24, + ), + isDense: true, + suffix: IconButton( + onPressed: () async { + controller + .setContent(context); + }, + icon: const Icon( + Icons.content_paste), + ), + border: + const OutlineInputBorder(), + labelStyle: GoogleFonts.poppins( + color: + AppSettings.isDarkMode + ? TaskWarriorColors + .white + : TaskWarriorColors + .black), + labelText: SentenceManager( + currentLanguage: + AppSettings + .selectedLanguage) + .sentences + .manageTaskServerPageConfigureTaskRCDialogueBoxInputFieldText, + ), ), ), ), Text( - "Or", + SentenceManager( + currentLanguage: AppSettings + .selectedLanguage) + .sentences + .manageTaskServerPageConfigureTaskRCDialogueBoxOr, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -170,7 +187,11 @@ class ManageTaskServerPageBody extends StatelessWidget { Get.back(); }, child: Text( - 'Select TASKRC file', + SentenceManager( + currentLanguage: AppSettings + .selectedLanguage) + .sentences + .manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white From 262ace51a47d33603e3f12a20d85fcd521e21591 Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 27 Jul 2024 22:46:13 +0530 Subject: [PATCH 46/47] Manage task server page multi lang complete --- .../manage_task_server_page_app_bar.dart | 5 +- .../views/manage_task_server_page_body.dart | 70 +++++++++++++++---- lib/app/utils/language/english_sentences.dart | 15 ++-- lib/app/utils/language/hindi_sentences.dart | 35 ++++++---- lib/app/utils/language/marathi_sentences.dart | 4 ++ lib/app/utils/language/sentences.dart | 2 + 6 files changed, 99 insertions(+), 32 deletions(-) diff --git a/lib/app/modules/manageTaskServer/views/manage_task_server_page_app_bar.dart b/lib/app/modules/manageTaskServer/views/manage_task_server_page_app_bar.dart index ce35ad18..21e0ebe5 100644 --- a/lib/app/modules/manageTaskServer/views/manage_task_server_page_app_bar.dart +++ b/lib/app/modules/manageTaskServer/views/manage_task_server_page_app_bar.dart @@ -13,6 +13,7 @@ import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart'; import 'package:taskwarrior/app/utils/constants/utilites.dart'; import 'package:taskwarrior/app/utils/gen/fonts.gen.dart'; +import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; import 'package:taskwarrior/app/utils/theme/app_settings.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -32,7 +33,9 @@ class ManageTaskServerPageAppBar extends StatelessWidget crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Configure TaskServer", + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageConfigureTaskserver, style: TextStyle( fontFamily: FontFamily.poppins, color: TaskWarriorColors.white, diff --git a/lib/app/modules/manageTaskServer/views/manage_task_server_page_body.dart b/lib/app/modules/manageTaskServer/views/manage_task_server_page_body.dart index 1bebcc06..daaa2150 100644 --- a/lib/app/modules/manageTaskServer/views/manage_task_server_page_body.dart +++ b/lib/app/modules/manageTaskServer/views/manage_task_server_page_body.dart @@ -34,7 +34,9 @@ class ManageTaskServerPageBody extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Configure TASKRC", + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageConfigureTASKRC, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -188,10 +190,10 @@ class ManageTaskServerPageBody extends StatelessWidget { }, child: Text( SentenceManager( - currentLanguage: AppSettings - .selectedLanguage) - .sentences - .manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC, + currentLanguage: AppSettings + .selectedLanguage) + .sentences + .manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -224,8 +226,16 @@ class ManageTaskServerPageBody extends StatelessWidget { children: [ Text( controller.taskrcContentController.text.isEmpty - ? "Set TaskRc" - : "Taskrc file is verified", + ? SentenceManager( + currentLanguage: + AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageSetTaskRC + : SentenceManager( + currentLanguage: + AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageTaskRCFileIsVerified, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -466,19 +476,49 @@ class ManageTaskServerPageBody extends StatelessWidget { storage: controller.storage, pem: pem, optionString: pem == "taskd.certificate" - ? "Configure your certificate" + ? SentenceManager( + currentLanguage: AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageConfigureYourCertificate : pem == "taskd.key" - ? "Configure TaskServer key" + ? SentenceManager( + currentLanguage: + AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageConfigureTaskserverKey : pem == "taskd.ca" - ? "Configure Server Certificate" - : "Configure Server Certificate", + ? SentenceManager( + currentLanguage: + AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageConfigureServerCertificate + : SentenceManager( + currentLanguage: + AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageConfigureServerCertificate, listTileTitle: pem == "taskd.certificate" - ? "Select Certificate" + ? SentenceManager( + currentLanguage: AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageSelectCertificate : pem == "taskd.key" - ? "Select key" + ? SentenceManager( + currentLanguage: + AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageSelectKey : pem == "taskd.ca" - ? "Select Certificate" - : "Select Certificate", + ? SentenceManager( + currentLanguage: + AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageSelectCertificate + : SentenceManager( + currentLanguage: + AppSettings.selectedLanguage) + .sentences + .manageTaskServerPageSelectCertificate, onTapCallBack: controller.onTapPEMWidget, onLongPressCallBack: controller.onLongPressPEMWidget, ), diff --git a/lib/app/utils/language/english_sentences.dart b/lib/app/utils/language/english_sentences.dart index 88d46d8b..23077f1e 100644 --- a/lib/app/utils/language/english_sentences.dart +++ b/lib/app/utils/language/english_sentences.dart @@ -259,13 +259,20 @@ class EnglishSentences extends Sentences { 'Configure Server Certificate'; @override - String get manageTaskServerPageConfigureTaskRCDialogueBoxTitle => 'Configure TaskRC'; + String get manageTaskServerPageConfigureTaskRCDialogueBoxTitle => + 'Configure TaskRC'; @override - String get manageTaskServerPageConfigureTaskRCDialogueBoxSubtitle => 'Paste the TaskRC content or select taskrc file'; + String get manageTaskServerPageConfigureTaskRCDialogueBoxSubtitle => + 'Paste the TaskRC content or select taskrc file'; @override - String get manageTaskServerPageConfigureTaskRCDialogueBoxInputFieldText => 'Paste your TaskRC content here'; + String get manageTaskServerPageConfigureTaskRCDialogueBoxInputFieldText => + 'Paste your TaskRC content here'; @override String get manageTaskServerPageConfigureTaskRCDialogueBoxOr => 'Or'; @override - String get manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC => 'Select TaskRC file'; + String get manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC => + 'Select TaskRC file'; + @override + String get manageTaskServerPageTaskRCFileIsVerified => + 'Task RC File Is Verified'; } diff --git a/lib/app/utils/language/hindi_sentences.dart b/lib/app/utils/language/hindi_sentences.dart index 801aa115..2a885c7e 100644 --- a/lib/app/utils/language/hindi_sentences.dart +++ b/lib/app/utils/language/hindi_sentences.dart @@ -209,7 +209,6 @@ class HindiSentences extends Sentences { String get deleteTaskWarning => 'यह क्रिया अपरिवर्तनीय है और यह सभी स्थानीय रूप से संग्रहीत कार्यों को हटा देगी।'; - @override String get profilePageProfile => 'प्रोफ़ाइल'; @override @@ -217,7 +216,8 @@ class HindiSentences extends Sentences { @override String get profilePageCurrentProfile => 'वर्तमान प्रोफ़ाइल'; @override - String get profilePageManageSelectedProfile => 'चुनी हुई प्रोफ़ाइल प्रबंधित करें'; + String get profilePageManageSelectedProfile => + 'चुनी हुई प्रोफ़ाइल प्रबंधित करें'; @override String get profilePageRenameAlias => 'उपनाम बदलें'; @@ -226,7 +226,8 @@ class HindiSentences extends Sentences { @override String get profilePageExportTasks => 'कार्य निर्यात करें'; @override - String get profilePageCopyConfigToNewProfile => 'नई प्रोफ़ाइल पर कॉन्फ़िगरेशन कॉपी करें'; + String get profilePageCopyConfigToNewProfile => + 'नई प्रोफ़ाइल पर कॉन्फ़िगरेशन कॉपी करें'; @override String get profilePageDeleteProfile => 'प्रोफ़ाइल हटाएँ'; @override @@ -242,31 +243,41 @@ class HindiSentences extends Sentences { String get profilePageRenameAliasDialogueBoxSubmit => 'प्रस्तुत करें'; @override - String get manageTaskServerPageConfigureTaskserver => 'टास्क सर्वर कॉन्फ़िगर करें'; + String get manageTaskServerPageConfigureTaskserver => + 'टास्क सर्वर कॉन्फ़िगर करें'; @override String get manageTaskServerPageConfigureTASKRC => 'TASKRC कॉन्फ़िगर करें'; @override String get manageTaskServerPageSetTaskRC => 'TaskRC सेट करें'; @override - String get manageTaskServerPageConfigureYourCertificate => 'अपने सर्टिफिकेट को कॉन्फ़िगर करें'; + String get manageTaskServerPageConfigureYourCertificate => + 'अपने सर्टिफिकेट को कॉन्फ़िगर करें'; @override String get manageTaskServerPageSelectCertificate => 'सर्टिफिकेट चुनें'; @override - String get manageTaskServerPageConfigureTaskserverKey => 'टास्क सर्वर की कॉन्फ़िगर करें'; + String get manageTaskServerPageConfigureTaskserverKey => + 'टास्क सर्वर की कॉन्फ़िगर करें'; @override String get manageTaskServerPageSelectKey => 'कुंजी चुनें'; @override - String get manageTaskServerPageConfigureServerCertificate => 'सर्वर सर्टिफिकेट कॉन्फ़िगर करें'; + String get manageTaskServerPageConfigureServerCertificate => + 'सर्वर सर्टिफिकेट कॉन्फ़िगर करें'; + @override + String get manageTaskServerPageTaskRCFileIsVerified => + 'Task RC फ़ाइल सत्यापित की गई है'; @override - String get manageTaskServerPageConfigureTaskRCDialogueBoxTitle => 'TaskRC कॉन्फ़िगर करें'; + String get manageTaskServerPageConfigureTaskRCDialogueBoxTitle => + 'TaskRC कॉन्फ़िगर करें'; @override - String get manageTaskServerPageConfigureTaskRCDialogueBoxSubtitle => 'TaskRC सामग्री पेस्ट करें या taskrc फ़ाइल चुनें'; + String get manageTaskServerPageConfigureTaskRCDialogueBoxSubtitle => + 'TaskRC सामग्री पेस्ट करें या taskrc फ़ाइल चुनें'; @override - String get manageTaskServerPageConfigureTaskRCDialogueBoxInputFieldText => 'यहाँ अपनी TaskRC सामग्री पेस्ट करें'; + String get manageTaskServerPageConfigureTaskRCDialogueBoxInputFieldText => + 'यहाँ अपनी TaskRC सामग्री पेस्ट करें'; @override String get manageTaskServerPageConfigureTaskRCDialogueBoxOr => 'या'; @override - String get manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC => 'TaskRC फ़ाइल चुनें'; - + String get manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC => + 'TaskRC फ़ाइल चुनें'; } diff --git a/lib/app/utils/language/marathi_sentences.dart b/lib/app/utils/language/marathi_sentences.dart index 24963d7c..26a11e1a 100644 --- a/lib/app/utils/language/marathi_sentences.dart +++ b/lib/app/utils/language/marathi_sentences.dart @@ -261,6 +261,10 @@ class MarathiSentences extends Sentences { @override String get manageTaskServerPageConfigureServerCertificate => 'सर्व्हर सर्टिफिकेट कॉन्फिगर करा'; + @override +String get manageTaskServerPageTaskRCFileIsVerified => + 'Task RC फाइल पडताळली गेली आहे'; + @override String get manageTaskServerPageConfigureTaskRCDialogueBoxTitle => diff --git a/lib/app/utils/language/sentences.dart b/lib/app/utils/language/sentences.dart index 823262ae..66e9450b 100644 --- a/lib/app/utils/language/sentences.dart +++ b/lib/app/utils/language/sentences.dart @@ -131,10 +131,12 @@ abstract class Sentences { String get manageTaskServerPageConfigureTaskserverKey; String get manageTaskServerPageSelectKey; String get manageTaskServerPageConfigureServerCertificate; + String get manageTaskServerPageTaskRCFileIsVerified; String get manageTaskServerPageConfigureTaskRCDialogueBoxTitle; String get manageTaskServerPageConfigureTaskRCDialogueBoxSubtitle; String get manageTaskServerPageConfigureTaskRCDialogueBoxInputFieldText; String get manageTaskServerPageConfigureTaskRCDialogueBoxOr; String get manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC; + } From db7f89c6f5d4fa80bd9ef0cc81992cebff881c0c Mon Sep 17 00:00:00 2001 From: Chinmay Date: Sat, 27 Jul 2024 22:51:06 +0530 Subject: [PATCH 47/47] Export tasks dialogue box translated --- lib/app/modules/profile/views/profile_view.dart | 10 ++++++++-- lib/app/utils/language/english_sentences.dart | 6 ++++++ lib/app/utils/language/hindi_sentences.dart | 5 +++++ lib/app/utils/language/marathi_sentences.dart | 12 ++++++++---- lib/app/utils/language/sentences.dart | 4 +++- 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart index c2670863..34252ac3 100644 --- a/lib/app/modules/profile/views/profile_view.dart +++ b/lib/app/modules/profile/views/profile_view.dart @@ -101,7 +101,10 @@ class ProfileView extends GetView { builder: (BuildContext context) { return Utils.showAlertDialog( title: Text( - "Export Format", + SentenceManager( + currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageExportTasksDialogueTitle, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white @@ -109,7 +112,10 @@ class ProfileView extends GetView { ), ), content: Text( - "Choose the export format:", + SentenceManager( + currentLanguage: AppSettings.selectedLanguage) + .sentences + .profilePageExportTasksDialogueSubtitle, style: TextStyle( color: AppSettings.isDarkMode ? TaskWarriorColors.white diff --git a/lib/app/utils/language/english_sentences.dart b/lib/app/utils/language/english_sentences.dart index 23077f1e..b145f6b4 100644 --- a/lib/app/utils/language/english_sentences.dart +++ b/lib/app/utils/language/english_sentences.dart @@ -238,6 +238,12 @@ class EnglishSentences extends Sentences { @override String get profilePageRenameAliasDialogueBoxSubmit => 'Submit'; + @override + String get profilePageExportTasksDialogueTitle => 'Export format'; + @override + String get profilePageExportTasksDialogueSubtitle => + 'Choose the export format'; + @override String get manageTaskServerPageConfigureTaskserver => 'Configure Task Server'; @override diff --git a/lib/app/utils/language/hindi_sentences.dart b/lib/app/utils/language/hindi_sentences.dart index 2a885c7e..b959254b 100644 --- a/lib/app/utils/language/hindi_sentences.dart +++ b/lib/app/utils/language/hindi_sentences.dart @@ -242,6 +242,11 @@ class HindiSentences extends Sentences { @override String get profilePageRenameAliasDialogueBoxSubmit => 'प्रस्तुत करें'; + @override + String get profilePageExportTasksDialogueTitle => 'निर्यात प्रारूप'; + @override + String get profilePageExportTasksDialogueSubtitle => 'निर्यात प्रारूप चुनें'; + @override String get manageTaskServerPageConfigureTaskserver => 'टास्क सर्वर कॉन्फ़िगर करें'; diff --git a/lib/app/utils/language/marathi_sentences.dart b/lib/app/utils/language/marathi_sentences.dart index 26a11e1a..50b81c89 100644 --- a/lib/app/utils/language/marathi_sentences.dart +++ b/lib/app/utils/language/marathi_sentences.dart @@ -241,6 +241,11 @@ class MarathiSentences extends Sentences { @override String get profilePageRenameAliasDialogueBoxSubmit => 'सादर करा'; + @override + String get profilePageExportTasksDialogueTitle => 'निर्यात प्रारूप'; + @override + String get profilePageExportTasksDialogueSubtitle => 'निर्यात प्रारूप निवडा'; + @override String get manageTaskServerPageConfigureTaskserver => 'टास्क सर्व्हर कॉन्फिगर करा'; @@ -261,10 +266,9 @@ class MarathiSentences extends Sentences { @override String get manageTaskServerPageConfigureServerCertificate => 'सर्व्हर सर्टिफिकेट कॉन्फिगर करा'; - @override -String get manageTaskServerPageTaskRCFileIsVerified => - 'Task RC फाइल पडताळली गेली आहे'; - + @override + String get manageTaskServerPageTaskRCFileIsVerified => + 'Task RC फाइल पडताळली गेली आहे'; @override String get manageTaskServerPageConfigureTaskRCDialogueBoxTitle => diff --git a/lib/app/utils/language/sentences.dart b/lib/app/utils/language/sentences.dart index 66e9450b..dee2b8a2 100644 --- a/lib/app/utils/language/sentences.dart +++ b/lib/app/utils/language/sentences.dart @@ -118,6 +118,9 @@ abstract class Sentences { String get profilePageDeleteProfile; String get profilePageAddNewProfile; + String get profilePageExportTasksDialogueTitle; + String get profilePageExportTasksDialogueSubtitle; + String get profilePageRenameAliasDialogueBoxTitle; String get profilePageRenameAliasDialogueBoxNewAlias; String get profilePageRenameAliasDialogueBoxCancel; @@ -138,5 +141,4 @@ abstract class Sentences { String get manageTaskServerPageConfigureTaskRCDialogueBoxInputFieldText; String get manageTaskServerPageConfigureTaskRCDialogueBoxOr; String get manageTaskServerPageConfigureTaskRCDialogueBoxSelectTaskRC; - }