diff --git a/lib/api_service.dart b/lib/api_service.dart index 176c04ce..61de4d97 100644 --- a/lib/api_service.dart +++ b/lib/api_service.dart @@ -67,7 +67,7 @@ class Tasks { } } -String baseUrl = 'http://YOUR_IP:8000'; +String baseUrl = 'http://192.168.1.104:8000'; String origin = 'http://localhost:8080'; Future> fetchTasks(String uuid, String encryptionSecret) async { @@ -175,7 +175,6 @@ Future deleteTask(String email, String taskUuid) async { }, body: body, ); - if (response.statusCode == 200) { debugPrint('Task deleted successfully on server'); } else { diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 53074874..6deb7899 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -27,12 +27,15 @@ 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/credentials_storage.dart'; +import 'package:taskwarrior/app/utils/taskchampion/websocket.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'; import 'package:taskwarrior/app/utils/taskfunctions/tags.dart'; import 'package:taskwarrior/app/utils/app_settings/app_settings.dart'; import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; +import 'package:web_socket_channel/status.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; class HomeController extends GetxController { final SplashController splashController = Get.find(); @@ -55,6 +58,7 @@ class HomeController extends GetxController { final ScrollController scrollController = ScrollController(); final RxBool showbtn = false.obs; late TaskDatabase taskdb; + WebSocketChannel? wsChannel; var tasks = [].obs; @override @@ -74,11 +78,18 @@ class HomeController extends GetxController { taskdb.open(); getUniqueProjects(); _loadTaskChampion(); + ever(taskchampion, (bool value) async { + if (value) { + wsChannel = await initCCSyncUpdatesWs(); + } else { + if (wsChannel != null) wsChannel?.sink.close(goingAway); + } + }); if (Platform.isAndroid) { handleHomeWidgetClicked(); } fetchTasksFromDB(); - everAll([ + everAll([ pendingFilter, waitingFilter, projectFilter, @@ -86,13 +97,12 @@ class HomeController extends GetxController { selectedSort, selectedTags, ], (_) { - if (Platform.isAndroid) { - WidgetController widgetController = - Get.put(WidgetController()); - widgetController.fetchAllData(); + if (Platform.isAndroid) { + WidgetController widgetController = Get.put(WidgetController()); + widgetController.fetchAllData(); - widgetController.update(); - } + widgetController.update(); + } }); } @@ -128,6 +138,10 @@ class HomeController extends GetxController { Future _loadTaskChampion() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); taskchampion.value = prefs.getBool('taskchampion') ?? false; + if (taskchampion.value) { + initCCSyncUpdatesWs(); + debugPrint('Task Champion is enabled'); + } } void addListenerToScrollController() { @@ -508,17 +522,14 @@ class HomeController extends GetxController { final projectcontroller = TextEditingController(); var due = Rxn(); RxString dueString = ''.obs; - final priorityList = ['L','X','M','H']; + final priorityList = ['L', 'X', 'M', 'H']; final priorityColors = [ TaskWarriorColors.green, TaskWarriorColors.grey, TaskWarriorColors.yellow, TaskWarriorColors.red, - - - ]; - RxString priority = 'X'.obs; + RxString priority = 'None'.obs; final tagcontroller = TextEditingController(); RxList tags = [].obs; @@ -582,10 +593,9 @@ class HomeController extends GetxController { void initLanguageAndDarkMode() { isDarkModeOn.value = AppSettings.isDarkMode; selectedLanguage.value = AppSettings.selectedLanguage; - HomeWidget.saveWidgetData("themeMode", AppSettings.isDarkMode ? "dark" : "light"); - HomeWidget.updateWidget( - androidName: "TaskWarriorWidgetProvider" - ); + HomeWidget.saveWidgetData( + "themeMode", AppSettings.isDarkMode ? "dark" : "light"); + HomeWidget.updateWidget(androidName: "TaskWarriorWidgetProvider"); // print("called and value is${isDarkModeOn.value}"); } @@ -679,6 +689,7 @@ class HomeController extends GetxController { }, ); } + late RxString uuid = "".obs; late RxBool isHomeWidgetTaskTapped = false.obs; @@ -693,7 +704,7 @@ class HomeController extends GetxController { Get.toNamed(Routes.DETAIL_ROUTE, arguments: ["uuid", uuid.value]); }); } - }else if(uri.host == "addclicked"){ + } else if (uri.host == "addclicked") { showAddDialogAfterWidgetClick(); } } @@ -706,15 +717,73 @@ class HomeController extends GetxController { } debugPrint('uuid is $uuid'); Get.toNamed(Routes.DETAIL_ROUTE, arguments: ["uuid", uuid.value]); - }else if(uri.host == "addclicked"){ + } else if (uri.host == "addclicked") { showAddDialogAfterWidgetClick(); } } - }); } + void showAddDialogAfterWidgetClick() { - Widget showDialog = taskchampion.value ? AddTaskToTaskcBottomSheet(homeController: this) : AddTaskBottomSheet(homeController: this); + Widget showDialog = taskchampion.value + ? AddTaskToTaskcBottomSheet(homeController: this) + : AddTaskBottomSheet(homeController: this); Get.dialog(showDialog); } + + Future initCCSyncUpdatesWs() async { + Map successMessages = { + "Add Task": "Task added successfully", + "Edit Task": "Task edited successfully", + "Complete Task": "Task completed successfully", + "Delete Task": "Task deleted successfully", + }; + Map failureMessages = { + "Add Task": "Task addition failed", + "Edit Task": "Task edit failed", + "Complete Task": "Task completion failed", + "Delete Task": "Task deletion failed", + }; + String? clientId = await CredentialsStorage.getClientId(); + return listenForTaskUpdates(getWsUrl(baseUrl, clientId), + (TaskUpdate update) { + debugPrint("Success: ${update.job} ${successMessages[update.job]!}"); + if (successMessages.containsKey(update.job)) { + ScaffoldMessenger.of(Get.context!).showSnackBar(SnackBar( + content: Text( + '${successMessages[update.job]}', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor, + ), + ), + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.ksecondaryBackgroundColor + : TaskWarriorColors.kLightSecondaryBackgroundColor, + duration: const Duration(seconds: 2))); + } + }, (TaskUpdate update) { + ScaffoldMessenger.of(Get.context!).showSnackBar(SnackBar( + content: Text( + '${failureMessages[update.job]}', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor, + ), + ), + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.ksecondaryBackgroundColor + : TaskWarriorColors.kLightSecondaryBackgroundColor, + duration: const Duration(seconds: 2))); + }); + } + + @override + void onClose() { + super.onClose(); + taskdb.close(); + if (wsChannel != null) wsChannel?.sink.close(); + } } 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 ae29a077..209c21bd 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 @@ -356,19 +356,6 @@ class AddTaskToTaskcBottomSheet extends StatelessWidget { homeController.due.value = null; homeController.priority.value = 'M'; homeController.projectcontroller.text = ''; - 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/utils/taskchampion/websocket.dart b/lib/app/utils/taskchampion/websocket.dart new file mode 100644 index 00000000..90f14419 --- /dev/null +++ b/lib/app/utils/taskchampion/websocket.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; + +class TaskUpdate { + final String status; + final String job; + const TaskUpdate(this.status, this.job); + TaskUpdate.fromJson(Map json) + : status = json['status'], + job = json['job']; + Map toJson() => { + 'status': status, + 'job': job, + }; +} + +Future listenForTaskUpdates(url, onSuccess, onFailure) async { + final webSocketChannel = WebSocketChannel.connect( + Uri.parse(url), + ); + await webSocketChannel.ready; + webSocketChannel.stream.listen((message) { + debugPrint(message); + TaskUpdate update = + TaskUpdate.fromJson(jsonDecode(message) as Map); + if (update.status == 'success') { + onSuccess(update); + } + if (update.status == 'failure') { + onFailure(update); + } + }); + return webSocketChannel; +} + +String getWsUrl(url, clientId) { + return url.replaceFirst('http', 'ws') + '/ws?clientID=' + clientId; +} diff --git a/pubspec.yaml b/pubspec.yaml index 19db109c..8204a524 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -64,6 +64,7 @@ dependencies: url_launcher: ^6.1.14 uuid: ^4.2.2 built_collection: ^5.1.1 + web_socket_channel: ^2.4.0 dev_dependencies: build_runner: null