From 289d1f142f831f5ae83fdd599f4f049a79ef2e17 Mon Sep 17 00:00:00 2001 From: Chinmay Chaudhari Date: Sat, 13 Jun 2026 23:02:16 +0530 Subject: [PATCH 1/4] refactor: retire the CCSync HTTP sync layer, unify on TaskChampion FFI Removes the deprecated HTTP sync path so all synchronization flows through the native TaskChampion Rust FFI bridge, matching the single-path target architecture. - Delete lib/app/v3/net/{fetch,add_task,complete,delete,modify,origin}.dart and lib/app/v3/db/update.dart (the HTTP push-sync helper). - Rewrite saveCredentials() to validate credentials via the native sync_() FFI call instead of an HTTP GET /tasks probe; drop the taskReplica branch. - Remove the taskc-HTTP sync call sites (home_controller.refreshTasks and its callers, show_tasks, taskc_details, home_page_app_bar) while preserving all local SQLite operations. - Rebrand the 8 ccsync* localization keys to syncServer* and reword copy from "CCSync" to "TaskChampion sync server" across all 9 language files; collapse the mode-branched sync-URL label to the single path. - Drop the obsolete HTTP fetchTasks test group and its generated mocks; realign the localization snapshot tests to the reworded strings. http stays in pubspec (still used by pushNotification_service.dart). flutter analyze: 0 errors. No test regressions vs main (pre-existing headless plugin/MethodChannel failures unchanged). --- .../home/controllers/home_controller.dart | 19 +- .../modules/home/views/home_page_app_bar.dart | 2 +- lib/app/modules/home/views/show_tasks.dart | 4 - ...manage_task_champion_creds_controller.dart | 68 ++- .../manage_task_champion_creds_view.dart | 61 +-- .../controllers/taskc_details_controller.dart | 11 - lib/app/utils/language/bengali_sentences.dart | 22 +- lib/app/utils/language/english_sentences.dart | 22 +- lib/app/utils/language/french_sentences.dart | 24 +- lib/app/utils/language/german_sentences.dart | 22 +- lib/app/utils/language/hindi_sentences.dart | 22 +- lib/app/utils/language/marathi_sentences.dart | 22 +- lib/app/utils/language/sentences.dart | 24 +- lib/app/utils/language/spanish_sentences.dart | 22 +- lib/app/utils/language/urdu_sentences.dart | 22 +- lib/app/v3/db/update.dart | 87 ---- lib/app/v3/models/task.dart | 2 +- lib/app/v3/net/add_task.dart | 37 -- lib/app/v3/net/complete.dart | 41 -- lib/app/v3/net/delete.dart | 35 -- lib/app/v3/net/fetch.dart | 32 -- lib/app/v3/net/modify.dart | 73 ---- lib/app/v3/net/origin.dart | 1 - test/api_service_test.dart | 42 +- test/api_service_test.mocks.dart | 401 ------------------ .../language/bengali_sentences_test.dart | 4 +- .../language/english_sentences_test.dart | 4 +- .../utils/language/french_sentences_test.dart | 4 +- test/utils/language/hindi_sentences_test.dart | 4 +- .../language/marathi_sentences_test.dart | 4 +- test/utils/language/sentences_test.dart | 2 +- .../language/spanish_sentences_test.dart | 4 +- .../utils/taskchampion/taskchampion_test.dart | 6 +- 33 files changed, 169 insertions(+), 981 deletions(-) delete mode 100644 lib/app/v3/db/update.dart delete mode 100644 lib/app/v3/net/add_task.dart delete mode 100644 lib/app/v3/net/complete.dart delete mode 100644 lib/app/v3/net/delete.dart delete mode 100644 lib/app/v3/net/fetch.dart delete mode 100644 lib/app/v3/net/modify.dart delete mode 100644 lib/app/v3/net/origin.dart delete mode 100644 test/api_service_test.mocks.dart diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart index 3cf342f8..a9eb5a3d 100644 --- a/lib/app/modules/home/controllers/home_controller.dart +++ b/lib/app/modules/home/controllers/home_controller.dart @@ -33,9 +33,7 @@ import 'package:taskwarrior/app/utils/app_settings/app_settings.dart'; import 'package:taskwarrior/app/v3/champion/replica.dart'; import 'package:taskwarrior/app/v3/champion/models/task_for_replica.dart'; import 'package:taskwarrior/app/v3/db/task_database.dart'; -import 'package:taskwarrior/app/v3/db/update.dart'; import 'package:taskwarrior/app/v3/models/task.dart'; -import 'package:taskwarrior/app/v3/net/fetch.dart'; import 'package:textfield_tags/textfield_tags.dart'; import 'package:taskwarrior/app/utils/themes/theme_extension.dart'; import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; @@ -168,16 +166,6 @@ class HomeController extends GetxController { debugPrint("Tasks from Replica: ${tasks.length}"); } - 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 { debugPrint("Fetching tasks from DB ${taskReplica.value}"); await _loadTaskChampion(); @@ -580,9 +568,10 @@ class HomeController extends GetxController { await refreshReplicaTasks(); } } else if (taskchampion.value) { - if (clientId != null && encryptionSecret != null) { - await refreshTasks(clientId, encryptionSecret); - } + // CCSync HTTP sync has been retired; the local TaskChampion database is + // the source of truth for this mode, so reload it without a remote + // round-trip. + await fetchTasksFromDB(); } else { await synchronize(context, false); } 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 72643e2d..52a053be 100644 --- a/lib/app/modules/home/views/home_page_app_bar.dart +++ b/lib/app/modules/home/views/home_page_app_bar.dart @@ -186,7 +186,7 @@ class HomePageAppBar extends StatelessWidget implements PreferredSizeWidget { .sentences .homePageFetchingTasks); - await controller.refreshTasks(c, e); + await controller.fetchTasksFromDB(); ScaffoldMessenger.of(context) .hideCurrentSnackBar(); diff --git a/lib/app/modules/home/views/show_tasks.dart b/lib/app/modules/home/views/show_tasks.dart index 008b30fb..8421e18d 100644 --- a/lib/app/modules/home/views/show_tasks.dart +++ b/lib/app/modules/home/views/show_tasks.dart @@ -11,8 +11,6 @@ import 'package:taskwarrior/app/utils/themes/theme_extension.dart'; import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; import 'package:taskwarrior/app/v3/db/task_database.dart'; import 'package:taskwarrior/app/v3/models/task.dart'; -import 'package:taskwarrior/app/v3/net/complete.dart'; -import 'package:taskwarrior/app/v3/net/delete.dart'; class TaskViewBuilder extends StatelessWidget { const TaskViewBuilder({ @@ -230,14 +228,12 @@ class TaskViewBuilder extends StatelessWidget { TaskDatabase taskDatabase = TaskDatabase(); await taskDatabase.open(); taskDatabase.markTaskAsCompleted(uuid); - completeTask('email', uuid); } void _markTaskAsDeleted(String uuid) async { TaskDatabase taskDatabase = TaskDatabase(); await taskDatabase.open(); taskDatabase.markTaskAsDeleted(uuid); - deleteTask('email', uuid); } Color _getPriorityColor(String priority) { diff --git a/lib/app/modules/manage_task_champion_creds/controllers/manage_task_champion_creds_controller.dart b/lib/app/modules/manage_task_champion_creds/controllers/manage_task_champion_creds_controller.dart index 8bf68577..1b418c14 100644 --- a/lib/app/modules/manage_task_champion_creds/controllers/manage_task_champion_creds_controller.dart +++ b/lib/app/modules/manage_task_champion_creds/controllers/manage_task_champion_creds_controller.dart @@ -1,17 +1,15 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:taskwarrior/app/modules/splash/controllers/splash_controller.dart'; import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; -import 'package:taskwarrior/app/v3/net/origin.dart'; -import 'package:http/http.dart' as http; +import 'package:taskwarrior/app/v3/champion/replica.dart'; +import 'package:taskwarrior/rust_bridge/api.dart'; class ManageTaskChampionCredsController extends GetxController { final encryptionSecretController = TextEditingController(); final clientIdController = TextEditingController(); - final ccsyncBackendUrlController = TextEditingController(); + final syncServerUrlController = TextEditingController(); var profilesWidget = Get.find(); RxBool isCheckingCreds = false.obs; RxBool taskReplica = false.obs; @@ -25,50 +23,36 @@ class ManageTaskChampionCredsController extends GetxController { encryptionSecretController.text = await CredentialsStorage.getEncryptionSecret() ?? ''; clientIdController.text = await CredentialsStorage.getClientId() ?? ''; - ccsyncBackendUrlController.text = + syncServerUrlController.text = await CredentialsStorage.getApiUrl() ?? ''; final SharedPreferences prefs = await SharedPreferences.getInstance(); taskReplica.value = prefs.getBool('settings_taskr_repl') ?? false; } + /// Validates and persists sync credentials through a single path: + /// the native TaskChampion sync via the Rust FFI bridge. A successful + /// [sync_] confirms the credentials are valid; invalid credentials raise a + /// Rust-level exception that surfaces here as a thrown error. Future saveCredentials() async { - if (taskReplica.value) { - profilesWidget.setTaskcCreds( - profilesWidget.currentProfile.value, - clientIdController.text, - encryptionSecretController.text, - ccsyncBackendUrlController.text); - return 0; - } isCheckingCreds.value = true; - String baseUrl = ccsyncBackendUrlController.text; - String uuid = clientIdController.text; - String encryptionSecret = encryptionSecretController.text; try { - String url = - '$baseUrl/tasks?email=email&origin=$origin&UUID=$uuid&encryptionSecret=$encryptionSecret'; - - var response = await http.get(Uri.parse(url), headers: { - "Content-Type": "application/json", - }).timeout(const Duration(seconds: 10000)); - debugPrint("Fetch tasks response: ${response.statusCode}"); - debugPrint("Fetch tasks body: ${response.body}"); - if (response.statusCode == 200) { - List allTasks = jsonDecode(response.body); - debugPrint(allTasks.toString()); - profilesWidget.setTaskcCreds( - profilesWidget.currentProfile.value, - clientIdController.text, - encryptionSecretController.text, - ccsyncBackendUrlController.text); - - isCheckingCreds.value = false; - return 0; - } else { - throw Exception('Failed to load tasks'); - } - } catch (e, s) { - debugPrint('Error fetching tasks: $e\n $s'); + profilesWidget.setTaskcCreds( + profilesWidget.currentProfile.value, + clientIdController.text, + encryptionSecretController.text, + syncServerUrlController.text, + ); + final String replicaPath = await Replica.getReplicaPath(); + await sync_( + taskdbDirPath: replicaPath, + url: syncServerUrlController.text, + clientId: clientIdController.text, + encryptionSecret: encryptionSecretController.text, + ); + isCheckingCreds.value = false; + return 0; + } catch (err) { + debugPrint('Credential check failed: $err'); isCheckingCreds.value = false; return 1; } @@ -78,7 +62,7 @@ class ManageTaskChampionCredsController extends GetxController { void onClose() { encryptionSecretController.dispose(); clientIdController.dispose(); - ccsyncBackendUrlController.dispose(); + syncServerUrlController.dispose(); super.onClose(); } } diff --git a/lib/app/modules/manage_task_champion_creds/views/manage_task_champion_creds_view.dart b/lib/app/modules/manage_task_champion_creds/views/manage_task_champion_creds_view.dart index e9b98351..fe9a6da1 100644 --- a/lib/app/modules/manage_task_champion_creds/views/manage_task_champion_creds_view.dart +++ b/lib/app/modules/manage_task_champion_creds/views/manage_task_champion_creds_view.dart @@ -36,22 +36,7 @@ class ManageTaskChampionCredsView ), ], ), - actions: [ - // IconButton( - // icon: Icon( - // Icons.info, - // color: TaskWarriorColors.white, - // ), - // onPressed: () async { - // String url = !controller.taskReplica.value - // ? "https://github.com/its-me-abhishek/ccsync" - // : "https://github.com/GothenburgBitFactory/taskchampion"; - // if (!await launchUrl(Uri.parse(url))) { - // throw Exception('Could not launch $url'); - // } - // }, - // ), - ], + actions: const [], leading: IconButton( icon: Icon(Icons.arrow_back, color: TaskWarriorColors.white), onPressed: () => Get.back(), @@ -74,7 +59,7 @@ class ManageTaskChampionCredsView labelText: SentenceManager( currentLanguage: AppSettings.selectedLanguage) .sentences - .ccsyncClientId, + .syncServerClientId, labelStyle: TextStyle(color: tColors.primaryTextColor), border: const OutlineInputBorder(), ), @@ -93,26 +78,18 @@ class ManageTaskChampionCredsView ), ), const SizedBox(height: 10), - Obx(() => TextField( - style: TextStyle(color: tColors.primaryTextColor), - controller: controller.ccsyncBackendUrlController, - decoration: InputDecoration( - labelText: controller.taskReplica.value - ? SentenceManager( - currentLanguage: - AppSettings.selectedLanguage) - .sentences - .taskchampionBackendUrl - : SentenceManager( - currentLanguage: - AppSettings.selectedLanguage) - .sentences - .ccsyncBackendUrl, - labelStyle: - TextStyle(color: tColors.primaryTextColor), - border: const OutlineInputBorder(), - ), - )), + TextField( + style: TextStyle(color: tColors.primaryTextColor), + controller: controller.syncServerUrlController, + decoration: InputDecoration( + labelText: SentenceManager( + currentLanguage: AppSettings.selectedLanguage) + .sentences + .syncServerBackendUrl, + labelStyle: TextStyle(color: tColors.primaryTextColor), + border: const OutlineInputBorder(), + ), + ), const SizedBox(height: 20), Obx(() => SizedBox( width: double.infinity, @@ -196,7 +173,7 @@ class ManageTaskChampionCredsView SentenceManager( currentLanguage: AppSettings.selectedLanguage) .sentences - .ccsyncEasySyncTitle, + .syncServerEasySyncTitle, style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.w600, @@ -208,7 +185,7 @@ class ManageTaskChampionCredsView SentenceManager( currentLanguage: AppSettings.selectedLanguage) .sentences - .ccsyncIntro, + .syncServerIntro, style: TextStyle( fontSize: 14, color: tColors.primaryTextColor?.withValues(alpha: 0.8), @@ -220,7 +197,7 @@ class ManageTaskChampionCredsView SentenceManager( currentLanguage: AppSettings.selectedLanguage) .sentences - .ccsyncLoginInstruction, + .syncServerLoginInstruction, style: TextStyle( fontSize: 14, color: tColors.primaryTextColor?.withValues(alpha: 0.8), @@ -235,7 +212,7 @@ class ManageTaskChampionCredsView SentenceManager( currentLanguage: AppSettings.selectedLanguage) .sentences - .ccsyncOpenButton, + .syncServerOpenButton, style: TextStyle(color: tColors.primaryTextColor), ), style: OutlinedButton.styleFrom( @@ -261,7 +238,7 @@ class ManageTaskChampionCredsView SentenceManager( currentLanguage: AppSettings.selectedLanguage) .sentences - .ccsyncSelfHosted, + .syncServerSelfHosted, style: TextStyle( fontSize: 13, color: tColors.primaryTextColor?.withValues(alpha: 0.6), diff --git a/lib/app/modules/taskc_details/controllers/taskc_details_controller.dart b/lib/app/modules/taskc_details/controllers/taskc_details_controller.dart index 6116cf7e..a99088ce 100644 --- a/lib/app/modules/taskc_details/controllers/taskc_details_controller.dart +++ b/lib/app/modules/taskc_details/controllers/taskc_details_controller.dart @@ -13,7 +13,6 @@ import 'package:taskwarrior/app/v3/models/annotation.dart'; import 'package:taskwarrior/app/v3/models/task.dart'; import 'package:taskwarrior/app/v3/champion/replica.dart'; import 'package:taskwarrior/app/v3/champion/models/task_for_replica.dart'; -import 'package:taskwarrior/app/v3/net/modify.dart'; enum UnsavedChangesAction { save, discard, cancel } @@ -249,16 +248,6 @@ class TaskcDetailsController extends GetxController { hasChanges.value = false; debugPrint('Task saved in local DB ${description.string}'); processTagsLists(); - await modifyTaskOnTaskwarrior( - description.string, - project.string, - DateTime.parse(due.string).toIso8601String(), - priority.string, - status.string, - initialTask.uuid!, - initialTask.id.toString(), - tags.toList(), - ); } else if (initialTask is TaskForReplica) { debugPrint( 'Saving replica task changes... status ${status.string} ${tags.join(", ")}'); diff --git a/lib/app/utils/language/bengali_sentences.dart b/lib/app/utils/language/bengali_sentences.dart index 4761031c..3e8df8b0 100644 --- a/lib/app/utils/language/bengali_sentences.dart +++ b/lib/app/utils/language/bengali_sentences.dart @@ -2,17 +2,17 @@ import 'package:taskwarrior/app/utils/language/sentences.dart'; class BengaliSentences extends Sentences { @override - String get ccsyncLoginInstruction => - 'CCSync-এ লগইন করুন, আপনার শংসাপত্র কপি করুন এবং উপরে পেস্ট করুন।'; + String get syncServerLoginInstruction => + 'TaskChampion-এ লগইন করুন, আপনার শংসাপত্র কপি করুন এবং উপরে পেস্ট করুন।'; @override - String get ccsyncEasySyncTitle => 'সহজ সিঙ্কের জন্য CCSync ব্যবহার করুন'; + String get syncServerEasySyncTitle => 'সহজ সিঙ্কের জন্য TaskChampion ব্যবহার করুন'; @override - String get ccsyncOpenButton => 'CCSync খুলুন'; + String get syncServerOpenButton => 'TaskChampion খুলুন'; @override - String get ccsyncIntro => - 'CCSync TaskChampion ব্যবহার করে আপনার কাজগুলি একাধিক ডিভাইসে নির্বিঘ্নে সিঙ্ক করে। আপনি যেকোনো ব্রাউজার থেকে আপনার কাজগুলি পরিচালনা করার জন্য একটি ওয়েব ড্যাশবোর্ডও পান।'; + String get syncServerIntro => + 'TaskChampion ব্যবহার করে আপনার কাজগুলি একাধিক ডিভাইসে নির্বিঘ্নে সিঙ্ক করে। আপনি যেকোনো ব্রাউজার থেকে আপনার কাজগুলি পরিচালনা করার জন্য একটি ওয়েব ড্যাশবোর্ডও পান।'; @override - String get ccsyncSelfHosted => + String get syncServerSelfHosted => 'অথবা একটি স্ব-হোস্টেড TaskChampion সিঙ্ক সার্ভার থেকে আপনার নিজস্ব শংসাপত্র আনুন।'; @override String get helloWorld => 'হ্যালো বিশ্ব!'; @@ -204,13 +204,13 @@ class BengaliSentences extends Sentences { @override String get taskchampionTileDescription => - 'Taskwarrior সিঙ্কিং CCSync বা Taskchampion সিঙ্ক সার্ভারে পরিবর্তন করুন'; + 'Taskwarrior সিঙ্কিং TaskChampion সিঙ্ক সার্ভারে পরিবর্তন করুন'; @override String get taskchampionTileTitle => 'Taskchampion সিঙ্ক'; @override - String get ccsyncCredentials => 'CCSync ক্রেডেনশিয়াল'; + String get syncServerCredentials => 'TaskChampion ক্রেডেনশিয়াল'; @override String get deleteTaskConfirmation => 'টাস্ক মুছুন'; @@ -661,9 +661,9 @@ class BengaliSentences extends Sentences { @override String get encryptionSecret => 'এনক্রিপশন সিক্রেট'; @override - String get ccsyncBackendUrl => 'CCSync ব্যাকএন্ড URL'; + String get syncServerBackendUrl => 'TaskChampion ব্যাকএন্ড URL'; @override - String get ccsyncClientId => 'ক্লায়েন্ট আইডি'; + String get syncServerClientId => 'ক্লায়েন্ট আইডি'; @override String get success => 'সফল হয়েছে'; @override diff --git a/lib/app/utils/language/english_sentences.dart b/lib/app/utils/language/english_sentences.dart index a6b0fb00..c793f7e9 100644 --- a/lib/app/utils/language/english_sentences.dart +++ b/lib/app/utils/language/english_sentences.dart @@ -2,17 +2,17 @@ import 'package:taskwarrior/app/utils/language/sentences.dart'; class EnglishSentences extends Sentences { @override - String get ccsyncLoginInstruction => - 'Login to CCSync, copy your credentials, and paste them above.'; + String get syncServerLoginInstruction => + 'Login to TaskChampion, copy your credentials, and paste them above.'; @override - String get ccsyncEasySyncTitle => 'Use CCSync for Easy Sync'; + String get syncServerEasySyncTitle => 'Use TaskChampion for Easy Sync'; @override - String get ccsyncOpenButton => 'Open CCSync'; + String get syncServerOpenButton => 'Open TaskChampion'; @override - String get ccsyncIntro => - 'CCSync uses TaskChampion to sync your tasks across multiple devices seamlessly. You also get a web dashboard to manage your tasks from any browser.'; + String get syncServerIntro => + 'TaskChampion syncs your tasks across multiple devices seamlessly. You also get a web dashboard to manage your tasks from any browser.'; @override - String get ccsyncSelfHosted => + String get syncServerSelfHosted => 'Or bring your own credentials from a self-hosted TaskChampion sync server.'; @override String get helloWorld => 'Hello, World!'; @@ -219,12 +219,12 @@ class EnglishSentences extends Sentences { @override String get taskchampionTileDescription => - 'Switch to Taskwarrior sync with CCSync or Taskchampion Sync Server'; + 'Switch to Taskwarrior sync with a TaskChampion sync server'; @override String get taskchampionTileTitle => 'Taskchampion sync'; @override - String get ccsyncCredentials => 'CCync credentials'; + String get syncServerCredentials => 'TaskChampion credentials'; @override String get deleteTaskConfirmation => 'Delete Tasks'; @@ -650,9 +650,9 @@ class EnglishSentences extends Sentences { @override String get encryptionSecret => 'Encryption Secret'; @override - String get ccsyncBackendUrl => 'CCSync Backend URL'; + String get syncServerBackendUrl => 'TaskChampion Backend URL'; @override - String get ccsyncClientId => 'Client ID'; + String get syncServerClientId => 'Client ID'; @override String get success => 'Success'; @override diff --git a/lib/app/utils/language/french_sentences.dart b/lib/app/utils/language/french_sentences.dart index 788a0cb6..18f57a86 100644 --- a/lib/app/utils/language/french_sentences.dart +++ b/lib/app/utils/language/french_sentences.dart @@ -2,18 +2,18 @@ import 'package:taskwarrior/app/utils/language/sentences.dart'; class FrenchSentences extends Sentences { @override - String get ccsyncLoginInstruction => - 'Connectez-vous à CCSync, copiez vos identifiants et collez-les ci-dessus.'; + String get syncServerLoginInstruction => + 'Connectez-vous à TaskChampion, copiez vos identifiants et collez-les ci-dessus.'; @override - String get ccsyncEasySyncTitle => - 'Utilisez CCSync pour une synchronisation facile'; + String get syncServerEasySyncTitle => + 'Utilisez TaskChampion pour une synchronisation facile'; @override - String get ccsyncOpenButton => 'Ouvrir CCSync'; + String get syncServerOpenButton => 'Ouvrir TaskChampion'; @override - String get ccsyncIntro => - 'CCSync utilise TaskChampion pour synchroniser vos tâches sur plusieurs appareils sans effort. Vous bénéficiez également d’un tableau de bord web pour gérer vos tâches depuis n’importe quel navigateur.'; + String get syncServerIntro => + 'TaskChampion synchronise vos tâches sur plusieurs appareils sans effort. Vous bénéficiez également d’un tableau de bord web pour gérer vos tâches depuis n’importe quel navigateur.'; @override - String get ccsyncSelfHosted => + String get syncServerSelfHosted => 'Ou utilisez vos propres identifiants depuis un serveur TaskChampion auto-hébergé.'; @override String get helloWorld => 'Bonjour, le monde!'; @@ -208,13 +208,13 @@ class FrenchSentences extends Sentences { @override String get taskchampionTileDescription => - 'Basculez la synchronisation de Taskwarrior vers le serveur de synchronisation CCSync ou Taskchampion'; + 'Basculez la synchronisation de Taskwarrior vers le serveur de synchronisation TaskChampion'; @override String get taskchampionTileTitle => 'Synchronisation Taskchampion'; @override - String get ccsyncCredentials => 'Identifiants CCSync'; + String get syncServerCredentials => 'Identifiants TaskChampion'; @override String get deleteTaskConfirmation => 'Supprimer la tâche'; @@ -677,9 +677,9 @@ class FrenchSentences extends Sentences { @override String get encryptionSecret => 'Secret de chiffrement'; @override - String get ccsyncBackendUrl => 'URL du backend CCSync'; + String get syncServerBackendUrl => 'URL du backend TaskChampion'; @override - String get ccsyncClientId => 'ID client'; + String get syncServerClientId => 'ID client'; @override String get success => 'Succès'; @override diff --git a/lib/app/utils/language/german_sentences.dart b/lib/app/utils/language/german_sentences.dart index c38ad4cb..cd9ded85 100644 --- a/lib/app/utils/language/german_sentences.dart +++ b/lib/app/utils/language/german_sentences.dart @@ -2,17 +2,17 @@ import 'package:taskwarrior/app/utils/language/sentences.dart'; class GermanSentences extends Sentences { @override - String get ccsyncLoginInstruction => - 'Melde dich bei CCSync an, kopiere deine Anmeldedaten und füge sie oben ein.'; + String get syncServerLoginInstruction => + 'Melde dich bei TaskChampion an, kopiere deine Anmeldedaten und füge sie oben ein.'; @override - String get ccsyncEasySyncTitle => 'CCSync nutzen für einfachen Sync'; + String get syncServerEasySyncTitle => 'TaskChampion nutzen für einfachen Sync'; @override - String get ccsyncOpenButton => 'CCSync öffnen'; + String get syncServerOpenButton => 'TaskChampion öffnen'; @override - String get ccsyncIntro => - 'CCSync nutzt TaskChampion, um Aufgaben nahtlos über mehrere Geräte hinweg zu synchronisieren. Außerdem erhälst du ein Web-Dashboard, über das du deine Aufgaben von jedem Browser aus verwalten kannst.'; + String get syncServerIntro => + 'TaskChampion synchronisiert deine Aufgaben nahtlos über mehrere Geräte hinweg. Außerdem erhälst du ein Web-Dashboard, über das du deine Aufgaben von jedem Browser aus verwalten kannst.'; @override - String get ccsyncSelfHosted => + String get syncServerSelfHosted => 'Oder bringe deine eigenen Anmeldedaten von einem selbst gehosteten TaskChampion-Synchronisierungsserver mit.'; @override String get helloWorld => 'Hallo Welt!'; @@ -219,12 +219,12 @@ class GermanSentences extends Sentences { @override String get taskchampionTileDescription => - 'Wechsel zu Taskwarrior Sync mit CCSync oder Taskchampion Sync Server'; + 'Wechsel zu Taskwarrior Sync mit einem TaskChampion Sync Server'; @override String get taskchampionTileTitle => 'Taskchampion Sync'; @override - String get ccsyncCredentials => 'CCync Anmeldedaten'; + String get syncServerCredentials => 'TaskChampion Anmeldedaten'; @override String get deleteTaskConfirmation => 'Aufgaben löschen'; @@ -650,9 +650,9 @@ class GermanSentences extends Sentences { @override String get encryptionSecret => 'Encryption Secret'; @override - String get ccsyncBackendUrl => 'CCSync Backend URL'; + String get syncServerBackendUrl => 'TaskChampion Backend URL'; @override - String get ccsyncClientId => 'Client ID'; + String get syncServerClientId => 'Client ID'; @override String get success => 'Erfolg'; @override diff --git a/lib/app/utils/language/hindi_sentences.dart b/lib/app/utils/language/hindi_sentences.dart index 6b5c428b..02b06f47 100644 --- a/lib/app/utils/language/hindi_sentences.dart +++ b/lib/app/utils/language/hindi_sentences.dart @@ -2,17 +2,17 @@ import 'package:taskwarrior/app/utils/language/sentences.dart'; class HindiSentences extends Sentences { @override - String get ccsyncLoginInstruction => - 'CCSync में लॉगिन करें, अपनी क्रेडेंशियल्स कॉपी करें, और उन्हें ऊपर पेस्ट करें।'; + String get syncServerLoginInstruction => + 'TaskChampion में लॉगिन करें, अपनी क्रेडेंशियल्स कॉपी करें, और उन्हें ऊपर पेस्ट करें।'; @override - String get ccsyncEasySyncTitle => 'आसान सिंक के लिए CCSync का उपयोग करें'; + String get syncServerEasySyncTitle => 'आसान सिंक के लिए TaskChampion का उपयोग करें'; @override - String get ccsyncOpenButton => 'CCSync खोलें'; + String get syncServerOpenButton => 'TaskChampion खोलें'; @override - String get ccsyncIntro => - 'CCSync आपके कार्यों को कई डिवाइसों पर TaskChampion के माध्यम से निर्बाध रूप से सिंक करता है। आपको किसी भी ब्राउज़र से अपने कार्यों को प्रबंधित करने के लिए एक वेब डैशबोर्ड भी मिलता है।'; + String get syncServerIntro => + 'TaskChampion आपके कार्यों को कई डिवाइसों पर निर्बाध रूप से सिंक करता है। आपको किसी भी ब्राउज़र से अपने कार्यों को प्रबंधित करने के लिए एक वेब डैशबोर्ड भी मिलता है।'; @override - String get ccsyncSelfHosted => + String get syncServerSelfHosted => 'या अपने स्वयं के TaskChampion सिंक सर्वर से क्रेडेंशियल्स लाएँ।'; @override String get helloWorld => 'नमस्ते दुनिया!'; @@ -220,13 +220,13 @@ class HindiSentences extends Sentences { @override String get taskchampionTileDescription => - 'CCSync या Taskchampion सिंक सर्वर के साथ Taskwarrior सिंक पर स्विच करें'; + 'TaskChampion सिंक सर्वर के साथ Taskwarrior सिंक पर स्विच करें'; @override String get taskchampionTileTitle => 'Taskchampion सिंक'; @override - String get ccsyncCredentials => 'CCync क्रेडेन्शियल'; + String get syncServerCredentials => 'TaskChampion क्रेडेन्शियल'; @override String get deleteTaskConfirmation => 'कार्य हटाएं'; @@ -638,9 +638,9 @@ class HindiSentences extends Sentences { @override String get encryptionSecret => 'एन्क्रिप्शन सीक्रेट'; @override - String get ccsyncBackendUrl => 'CCSync बैकएंड URL'; + String get syncServerBackendUrl => 'TaskChampion बैकएंड URL'; @override - String get ccsyncClientId => 'क्लाइंट आईडी'; + String get syncServerClientId => 'क्लाइंट आईडी'; @override String get success => 'सफलता'; @override diff --git a/lib/app/utils/language/marathi_sentences.dart b/lib/app/utils/language/marathi_sentences.dart index b7045742..8f497220 100644 --- a/lib/app/utils/language/marathi_sentences.dart +++ b/lib/app/utils/language/marathi_sentences.dart @@ -2,18 +2,18 @@ import 'package:taskwarrior/app/utils/language/sentences.dart'; class MarathiSentences extends Sentences { @override - String get ccsyncLoginInstruction => - 'CCSync मध्ये लॉगिन करा, तुमची क्रेडेन्शियल्स कॉपी करा आणि वर पेस्ट करा.'; + String get syncServerLoginInstruction => + 'TaskChampion मध्ये लॉगिन करा, तुमची क्रेडेन्शियल्स कॉपी करा आणि वर पेस्ट करा.'; @override - String get ccsyncEasySyncTitle => 'सोप्या सिंकसाठी CCSync वापरा'; + String get syncServerEasySyncTitle => 'सोप्या सिंकसाठी TaskChampion वापरा'; @override - String get ccsyncOpenButton => 'CCSync उघडा'; + String get syncServerOpenButton => 'TaskChampion उघडा'; @override - String get ccsyncIntro => - 'CCSync TaskChampion वापरून तुमची कामे अनेक उपकरणांवर सहजपणे सिंक करते. तुम्हाला कोणत्याही ब्राउझरमधून तुमची कामे व्यवस्थापित करण्यासाठी वेब डॅशबोर्ड देखील मिळतो.'; + String get syncServerIntro => + 'TaskChampion वापरून तुमची कामे अनेक उपकरणांवर सहजपणे सिंक करते. तुम्हाला कोणत्याही ब्राउझरमधून तुमची कामे व्यवस्थापित करण्यासाठी वेब डॅशबोर्ड देखील मिळतो.'; @override - String get ccsyncSelfHosted => + String get syncServerSelfHosted => 'किंवा स्वतःच्या TaskChampion सिंक सर्व्हरमधून तुमची क्रेडेन्शियल्स वापरा.'; @override String get helloWorld => 'नमस्कार, जग!'; @@ -206,13 +206,13 @@ class MarathiSentences extends Sentences { @override String get taskchampionTileDescription => - 'CCSync किंवा Taskchampion Sync Server सह Taskwarrior सिंक वर स्विच करा'; + 'TaskChampion Sync Server सह Taskwarrior सिंक वर स्विच करा'; @override String get taskchampionTileTitle => 'Taskchampion सिंक'; @override - String get ccsyncCredentials => 'CCync क्रेडेन्शियल'; + String get syncServerCredentials => 'TaskChampion क्रेडेन्शियल'; @override String get deleteTaskConfirmation => 'कार्य हटवा'; @@ -661,9 +661,9 @@ class MarathiSentences extends Sentences { @override String get encryptionSecret => 'एन्क्रिप्शन गुपित'; @override - String get ccsyncBackendUrl => 'CCSync बॅकएंड URL'; + String get syncServerBackendUrl => 'TaskChampion बॅकएंड URL'; @override - String get ccsyncClientId => 'क्लायंट आयडी'; + String get syncServerClientId => 'क्लायंट आयडी'; @override String get success => 'यशस्वी'; @override diff --git a/lib/app/utils/language/sentences.dart b/lib/app/utils/language/sentences.dart index 891f3e30..c8e52200 100644 --- a/lib/app/utils/language/sentences.dart +++ b/lib/app/utils/language/sentences.dart @@ -1,12 +1,12 @@ abstract class Sentences { - /// CCSync UI additional sentences - String get ccsyncLoginInstruction; - String get ccsyncEasySyncTitle; - String get ccsyncOpenButton; - - /// CCSync intro and self-hosted sentences - String get ccsyncIntro; - String get ccsyncSelfHosted; + /// TaskChampion UI additional sentences + String get syncServerLoginInstruction; + String get syncServerEasySyncTitle; + String get syncServerOpenButton; + + /// TaskChampion intro and self-hosted sentences + String get syncServerIntro; + String get syncServerSelfHosted; String get helloWorld; String get homePageTitle; @@ -64,7 +64,7 @@ abstract class Sentences { String get navDrawerReports; String get navDrawerAbout; String get navDrawerSettings; - String get ccsyncCredentials; + String get syncServerCredentials; String get deleteTaskTitle; String get deleteTaskConfirmation; String get deleteTaskWarning; @@ -344,12 +344,12 @@ abstract class Sentences { String get add; String get change; String get dateCanNotBeInPast; - // ccsync credentials page + // sync server credentials page String get configureTaskchampion; String get encryptionSecret; - String get ccsyncBackendUrl; + String get syncServerBackendUrl; String get taskchampionBackendUrl; - String get ccsyncClientId; + String get syncServerClientId; String get success; String get credentialsSavedSuccessfully; String get tip; diff --git a/lib/app/utils/language/spanish_sentences.dart b/lib/app/utils/language/spanish_sentences.dart index 94d6a460..4780fa7f 100644 --- a/lib/app/utils/language/spanish_sentences.dart +++ b/lib/app/utils/language/spanish_sentences.dart @@ -2,17 +2,17 @@ import 'package:taskwarrior/app/utils/language/sentences.dart'; class SpanishSentences extends Sentences { @override - String get ccsyncLoginInstruction => - 'Inicia sesión en CCSync, copia tus credenciales y pégalas arriba.'; + String get syncServerLoginInstruction => + 'Inicia sesión en TaskChampion, copia tus credenciales y pégalas arriba.'; @override - String get ccsyncEasySyncTitle => 'Usa CCSync para una sincronización fácil'; + String get syncServerEasySyncTitle => 'Usa TaskChampion para una sincronización fácil'; @override - String get ccsyncOpenButton => 'Abrir CCSync'; + String get syncServerOpenButton => 'Abrir TaskChampion'; @override - String get ccsyncIntro => - 'CCSync utiliza TaskChampion para sincronizar tus tareas en múltiples dispositivos sin problemas. También obtienes un panel web para gestionar tus tareas desde cualquier navegador.'; + String get syncServerIntro => + 'TaskChampion sincroniza tus tareas en múltiples dispositivos sin problemas. También obtienes un panel web para gestionar tus tareas desde cualquier navegador.'; @override - String get ccsyncSelfHosted => + String get syncServerSelfHosted => 'O utiliza tus propias credenciales de un servidor de sincronización TaskChampion autohospedado.'; @override String get helloWorld => '¡Hola, mundo!'; @@ -206,13 +206,13 @@ class SpanishSentences extends Sentences { @override String get taskchampionTileDescription => - 'Cambia la sincronización de Taskwarrior al servidor de sincronización CCSync o Taskchampion'; + 'Cambia la sincronización de Taskwarrior al servidor de sincronización TaskChampion'; @override String get taskchampionTileTitle => 'Sincronización Taskchampion'; @override - String get ccsyncCredentials => 'Credenciales de CCSync'; + String get syncServerCredentials => 'Credenciales de TaskChampion'; @override String get deleteTaskConfirmation => 'Eliminar tarea'; @@ -665,9 +665,9 @@ class SpanishSentences extends Sentences { @override String get encryptionSecret => 'Secreto de cifrado'; @override - String get ccsyncBackendUrl => 'URL del backend de CCSync'; + String get syncServerBackendUrl => 'URL del backend de TaskChampion'; @override - String get ccsyncClientId => 'ID de cliente'; + String get syncServerClientId => 'ID de cliente'; @override String get success => 'Éxito'; @override diff --git a/lib/app/utils/language/urdu_sentences.dart b/lib/app/utils/language/urdu_sentences.dart index e78c37de..a76a3ab5 100644 --- a/lib/app/utils/language/urdu_sentences.dart +++ b/lib/app/utils/language/urdu_sentences.dart @@ -2,17 +2,17 @@ import 'package:taskwarrior/app/utils/language/sentences.dart'; class UrduSentences extends Sentences { @override - String get ccsyncLoginInstruction => - 'CCSync میں لاگ ان کریں، اپنی اسناد کاپی کریں، اور اوپر پیسٹ کریں۔'; + String get syncServerLoginInstruction => + 'TaskChampion میں لاگ ان کریں، اپنی اسناد کاپی کریں، اور اوپر پیسٹ کریں۔'; @override - String get ccsyncEasySyncTitle => 'آسان سینک کے لیے CCSync کا używaj'; + String get syncServerEasySyncTitle => 'آسان سینک کے لیے TaskChampion کا używaj'; @override - String get ccsyncOpenButton => 'CCSync کھولیں'; + String get syncServerOpenButton => 'TaskChampion کھولیں'; @override - String get ccsyncIntro => - 'CCSync آپ کے کاموں کو کئی آلاتوں میں ہموار طور پر سینک کرنے کے لیے TaskChampion کا gebruikt۔ آپ کو اپنے کاموں کو کسی بھی براؤزر سے manage کرنے کے لیے ویب ڈیش بورد بھی ملتی ہے۔'; + String get syncServerIntro => + 'TaskChampion آپ کے کاموں کو کئی آلاتوں میں ہموار طور پر سینک کرتا ہے۔ آپ کو اپنے کاموں کو کسی بھی براؤزر سے manage کرنے کے لیے ویب ڈیش بورد بھی ملتی ہے۔'; @override - String get ccsyncSelfHosted => + String get syncServerSelfHosted => 'یا اپنے سیلف ہوسٹڈ TaskChampion sync سرور سے اپنی اسناد لائیں۔'; @override String get helloWorld => 'ہیلو، دنیا!'; @@ -221,12 +221,12 @@ class UrduSentences extends Sentences { @override String get taskchampionTileDescription => - 'CCSync یا Taskchampion Sync Server کے ساتھ ٹاسکواریر sync پر سوئچ کریں'; + 'TaskChampion Sync Server کے ساتھ ٹاسکواریر sync پر سوئچ کریں'; @override String get taskchampionTileTitle => 'Taskchampion sync'; @override - String get ccsyncCredentials => 'CCync اسناد'; + String get syncServerCredentials => 'TaskChampion اسناد'; @override String get deleteTaskConfirmation => 'کام حذف کریں'; @@ -653,9 +653,9 @@ class UrduSentences extends Sentences { @override String get encryptionSecret => 'انکرپشن سیکریٹ'; @override - String get ccsyncBackendUrl => 'CCSync بیک اینڈ یو آر ایل'; + String get syncServerBackendUrl => 'TaskChampion بیک اینڈ یو آر ایل'; @override - String get ccsyncClientId => 'کلائنٹ آئی ڈی'; + String get syncServerClientId => 'کلائنٹ آئی ڈی'; @override String get success => 'کامیابی'; @override diff --git a/lib/app/v3/db/update.dart b/lib/app/v3/db/update.dart deleted file mode 100644 index 7d0f549f..00000000 --- a/lib/app/v3/db/update.dart +++ /dev/null @@ -1,87 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:taskwarrior/app/v3/db/task_database.dart'; -import 'package:taskwarrior/app/v3/models/task.dart'; -import 'package:taskwarrior/app/v3/net/add_task.dart'; -import 'package:taskwarrior/app/v3/net/complete.dart'; -import 'package:taskwarrior/app/v3/net/delete.dart'; -import 'package:taskwarrior/app/v3/net/modify.dart'; -import 'package:timezone/timezone.dart'; - -Future updateTasksInDatabase(List tasks) async { - debugPrint( - "Updating tasks in database... Total tasks from server: ${tasks.length}"); - 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 != null ? task.project! : '', - task.due!, - task.priority!, - task.tags != null ? task.tags! : []); - } catch (e) { - debugPrint( - 'Failed to add task without UUID to server: $e ${task.tags} ${task.project}'); - } - } - - // 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 - debugPrint( - 'Inserting new task from server: ${serverTask.description}, modified: ${serverTask.modified}'); - 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 - debugPrint( - 'Updating task on server: ${localTask.description}, modified: ${localTask.modified}'); - await modifyTaskOnTaskwarrior( - localTask.description, - localTask.project!, - localTask.due!, - localTask.priority!, - localTask.status, - localTask.uuid!, - localTask.id.toString(), - localTask.tags != null - ? localTask.tags!.map((e) => e.toString()).toList() - : []); - if (localTask.status == 'completed') { - completeTask('email', localTask.uuid!); - } else if (localTask.status == 'deleted') { - deleteTask('email', localTask.uuid!); - } - } - } - } -} diff --git a/lib/app/v3/models/task.dart b/lib/app/v3/models/task.dart index 91c64045..68b83a69 100644 --- a/lib/app/v3/models/task.dart +++ b/lib/app/v3/models/task.dart @@ -14,7 +14,7 @@ class TaskForC { final String entry; final String? modified; final List? tags; - // newer feilds in CCSync Model + // newer fields in the TaskChampion model final String? start; final String? wait; final String? rtype; diff --git a/lib/app/v3/net/add_task.dart b/lib/app/v3/net/add_task.dart deleted file mode 100644 index 370a5c27..00000000 --- a/lib/app/v3/net/add_task.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:flutter/material.dart'; -import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; -import 'package:taskwarrior/app/v3/db/task_database.dart'; - -Future addTaskAndDeleteFromDatabase(String description, String project, - String due, String priority, List tags) async { - var baseUrl = await CredentialsStorage.getApiUrl(); - String apiUrl = '$baseUrl/add-task'; - var c = await CredentialsStorage.getClientId(); - var e = await CredentialsStorage.getEncryptionSecret(); - debugPrint("Database Adding Tags $tags $description"); - debugPrint(c); - debugPrint(e); - var res = 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, - 'tags': tags - }), - ); - debugPrint('Database res ${res.body}'); - var taskDatabase = TaskDatabase(); - await taskDatabase.open(); - await taskDatabase.deleteTask( - description: description, due: due, project: project, priority: priority); -} diff --git a/lib/app/v3/net/complete.dart b/lib/app/v3/net/complete.dart deleted file mode 100644 index b3718146..00000000 --- a/lib/app/v3/net/complete.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:flutter/material.dart'; -import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; -import 'package:path/path.dart'; - -Future completeTask(String email, String taskUuid) async { - var c = await CredentialsStorage.getClientId(); - var e = await CredentialsStorage.getEncryptionSecret(); - var baseUrl = await CredentialsStorage.getApiUrl(); - final url = Uri.parse('$baseUrl/complete-task'); - final body = jsonEncode({ - 'email': email, - 'encryptionSecret': e, - 'UUID': c, - '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}'); - ScaffoldMessenger.of(context as BuildContext).showSnackBar(const SnackBar( - content: Text( - "Failed to complete task!", - style: TextStyle(color: Colors.red), - ))); - } - } catch (e) { - debugPrint('Error completing task: $e'); - } -} diff --git a/lib/app/v3/net/delete.dart b/lib/app/v3/net/delete.dart deleted file mode 100644 index 8873377b..00000000 --- a/lib/app/v3/net/delete.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:flutter/material.dart'; -import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; - -Future deleteTask(String email, String taskUuid) async { - var baseUrl = await CredentialsStorage.getApiUrl(); - var c = await CredentialsStorage.getClientId(); - var e = await CredentialsStorage.getEncryptionSecret(); - final url = Uri.parse('$baseUrl/delete-task'); - final body = jsonEncode({ - 'email': email, - 'encryptionSecret': e, - 'UUID': c, - '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'); - } -} diff --git a/lib/app/v3/net/fetch.dart b/lib/app/v3/net/fetch.dart deleted file mode 100644 index 54adde77..00000000 --- a/lib/app/v3/net/fetch.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; -import 'package:taskwarrior/app/v3/models/task.dart'; -import 'package:taskwarrior/app/v3/net/origin.dart'; -import 'package:http/http.dart' as http; - -Future> fetchTasks(String uuid, String encryptionSecret) async { - var baseUrl = await CredentialsStorage.getApiUrl(); - try { - String url = - '$baseUrl/tasks?email=email&origin=$origin&UUID=$uuid&encryptionSecret=$encryptionSecret'; - - var response = await http.get(Uri.parse(url), headers: { - "Content-Type": "application/json", - }).timeout(const Duration(milliseconds: 10000)); - debugPrint("Fetch tasks response: ${response.statusCode}"); - debugPrint("Fetch tasks body: ${response.body}"); - if (response.statusCode == 200) { - List allTasks = jsonDecode(response.body); - debugPrint(allTasks.toString()); - return allTasks.map((task) => TaskForC.fromJson(task)).toList(); - } else { - throw Exception('Failed to load tasks'); - } - } catch (e, s) { - debugPrint('Error fetching tasks: $e\n $s'); - - return []; - } -} diff --git a/lib/app/v3/net/modify.dart b/lib/app/v3/net/modify.dart deleted file mode 100644 index 1d32976a..00000000 --- a/lib/app/v3/net/modify.dart +++ /dev/null @@ -1,73 +0,0 @@ -import 'dart:convert'; -import 'package:get/get.dart'; -import 'package:http/http.dart' as http; -import 'package:path/path.dart'; -import 'package:flutter/material.dart'; -import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; -import 'package:taskwarrior/app/v3/db/task_database.dart'; - -Future modifyTaskOnTaskwarrior( - String description, - String project, - String due, - String priority, - String status, - String taskuuid, - String id, - List newTags) async { - var baseUrl = await CredentialsStorage.getApiUrl(); - var c = await CredentialsStorage.getClientId(); - var e = await CredentialsStorage.getEncryptionSecret(); - String apiUrl = '$baseUrl/modify-task'; - debugPrint(c); - debugPrint(e); - debugPrint("modifyTaskOnTaskwarrior called"); - debugPrint("description: $description project: $project due: $due " - "priority: $priority status: $status taskuuid: $taskuuid id: $id tags: $newTags" - "body: ${jsonEncode({ - "email": "e", - "encryptionSecret": e, - "UUID": c, - "description": description, - "priority": priority, - "project": project, - "due": due, - "status": status, - "taskuuid": taskuuid, - "taskId": id, - "tags": newTags.isNotEmpty ? newTags : null - })}"); - final response = 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, - "taskId": id, - "tags": newTags.isNotEmpty ? newTags : null - }), - ); - debugPrint('Modify task response body: ${response.body}'); - if (response.statusCode < 200 || response.statusCode >= 300) { - Get.showSnackbar(GetSnackBar( - title: 'Error', - message: - 'Failed to modify task on Taskwarrior server. ${response.statusCode}', - duration: Duration(seconds: 3), - )); - } - - var taskDatabase = TaskDatabase(); - await taskDatabase.open(); - await taskDatabase.deleteTask( - description: description, due: due, project: project, priority: priority); -} diff --git a/lib/app/v3/net/origin.dart b/lib/app/v3/net/origin.dart deleted file mode 100644 index 4cc70540..00000000 --- a/lib/app/v3/net/origin.dart +++ /dev/null @@ -1 +0,0 @@ -String origin = 'http://localhost:8080'; diff --git a/test/api_service_test.dart b/test/api_service_test.dart index 85d84391..1429ccae 100644 --- a/test/api_service_test.dart +++ b/test/api_service_test.dart @@ -1,33 +1,17 @@ -import 'dart:convert'; - import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/annotations.dart'; -import 'package:mockito/mockito.dart'; -import 'package:http/http.dart' as http; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; -import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart'; import 'package:taskwarrior/app/v3/db/task_database.dart'; import 'package:taskwarrior/app/v3/models/task.dart'; -import 'package:taskwarrior/app/v3/net/fetch.dart'; -import 'package:taskwarrior/app/v3/net/origin.dart'; - -import 'api_service_test.mocks.dart'; - -class MockCredentialsStorage extends Mock implements CredentialsStorage {} - -class MockMethodChannel extends Mock implements MethodChannel {} -@GenerateMocks([MockMethodChannel, http.Client]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); databaseFactory = databaseFactoryFfi; - MockClient mockClient = MockClient(); setUpAll(() { sqfliteFfiInit(); - + // Mock SharedPreferences plugin const MethodChannel('plugins.flutter.io/shared_preferences') .setMockMethodCallHandler((MethodCall methodCall) async { @@ -102,30 +86,6 @@ void main() { }); }); - group('fetchTasks', () { - test('Fetch data successfully', () async { - final responseJson = jsonEncode({'data': 'Mock data'}); - var baseUrl = await CredentialsStorage.getApiUrl(); - when(mockClient.get( - Uri.parse( - '$baseUrl/tasks?email=email&origin=$origin&UUID=123&encryptionSecret=secret'), - headers: { - "Content-Type": "application/json", - })).thenAnswer((_) async => http.Response(responseJson, 200)); - - final result = await fetchTasks('123', 'secret'); - - expect(result, isA>()); - }); - - test('fetchTasks returns empty array', () async { - const uuid = '123'; - const encryptionSecret = 'secret'; - - expect(await fetchTasks(uuid, encryptionSecret), isEmpty); - }); - }); - group('TaskDatabase', () { late TaskDatabase taskDatabase; diff --git a/test/api_service_test.mocks.dart b/test/api_service_test.mocks.dart deleted file mode 100644 index c23b5109..00000000 --- a/test/api_service_test.mocks.dart +++ /dev/null @@ -1,401 +0,0 @@ -// Mocks generated by Mockito 5.4.4 from annotations -// in taskwarrior/test/api_service_test.dart. -// Do not manually edit this file. - -// ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i6; -import 'dart:convert' as _i7; -import 'dart:typed_data' as _i8; - -import 'package:flutter/services.dart' as _i2; -import 'package:http/http.dart' as _i3; -import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i5; - -import 'api_service_test.dart' as _i4; - -// ignore_for_file: type=lint -// ignore_for_file: avoid_redundant_argument_values -// ignore_for_file: avoid_setters_without_getters -// ignore_for_file: comment_references -// ignore_for_file: deprecated_member_use -// ignore_for_file: deprecated_member_use_from_same_package -// ignore_for_file: implementation_imports -// ignore_for_file: invalid_use_of_visible_for_testing_member -// ignore_for_file: prefer_const_constructors -// ignore_for_file: unnecessary_parenthesis -// ignore_for_file: camel_case_types -// ignore_for_file: subtype_of_sealed_class - -class _FakeMethodCodec_0 extends _i1.SmartFake implements _i2.MethodCodec { - _FakeMethodCodec_0( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeBinaryMessenger_1 extends _i1.SmartFake - implements _i2.BinaryMessenger { - _FakeBinaryMessenger_1( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeResponse_2 extends _i1.SmartFake implements _i3.Response { - _FakeResponse_2( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeStreamedResponse_3 extends _i1.SmartFake - implements _i3.StreamedResponse { - _FakeStreamedResponse_3( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -/// A class which mocks [MockMethodChannel]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockMockMethodChannel extends _i1.Mock implements _i4.MockMethodChannel { - MockMockMethodChannel() { - _i1.throwOnMissingStub(this); - } - - @override - String get name => (super.noSuchMethod( - Invocation.getter(#name), - returnValue: _i5.dummyValue( - this, - Invocation.getter(#name), - ), - ) as String); - - @override - _i2.MethodCodec get codec => (super.noSuchMethod( - Invocation.getter(#codec), - returnValue: _FakeMethodCodec_0( - this, - Invocation.getter(#codec), - ), - ) as _i2.MethodCodec); - - @override - _i2.BinaryMessenger get binaryMessenger => (super.noSuchMethod( - Invocation.getter(#binaryMessenger), - returnValue: _FakeBinaryMessenger_1( - this, - Invocation.getter(#binaryMessenger), - ), - ) as _i2.BinaryMessenger); - - @override - _i6.Future invokeMethod( - String? method, [ - dynamic arguments, - ]) => - (super.noSuchMethod( - Invocation.method( - #invokeMethod, - [ - method, - arguments, - ], - ), - returnValue: _i6.Future.value(), - ) as _i6.Future); - - @override - _i6.Future?> invokeListMethod( - String? method, [ - dynamic arguments, - ]) => - (super.noSuchMethod( - Invocation.method( - #invokeListMethod, - [ - method, - arguments, - ], - ), - returnValue: _i6.Future?>.value(), - ) as _i6.Future?>); - - @override - _i6.Future?> invokeMapMethod( - String? method, [ - dynamic arguments, - ]) => - (super.noSuchMethod( - Invocation.method( - #invokeMapMethod, - [ - method, - arguments, - ], - ), - returnValue: _i6.Future?>.value(), - ) as _i6.Future?>); - - @override - void setMethodCallHandler( - _i6.Future Function(_i2.MethodCall)? handler) => - super.noSuchMethod( - Invocation.method( - #setMethodCallHandler, - [handler], - ), - returnValueForMissingStub: null, - ); -} - -/// A class which mocks [Client]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockClient extends _i1.Mock implements _i3.Client { - MockClient() { - _i1.throwOnMissingStub(this); - } - - @override - _i6.Future<_i3.Response> head( - Uri? url, { - Map? headers, - }) => - (super.noSuchMethod( - Invocation.method( - #head, - [url], - {#headers: headers}, - ), - returnValue: _i6.Future<_i3.Response>.value(_FakeResponse_2( - this, - Invocation.method( - #head, - [url], - {#headers: headers}, - ), - )), - ) as _i6.Future<_i3.Response>); - - @override - _i6.Future<_i3.Response> get( - Uri? url, { - Map? headers, - }) => - (super.noSuchMethod( - Invocation.method( - #get, - [url], - {#headers: headers}, - ), - returnValue: _i6.Future<_i3.Response>.value(_FakeResponse_2( - this, - Invocation.method( - #get, - [url], - {#headers: headers}, - ), - )), - ) as _i6.Future<_i3.Response>); - - @override - _i6.Future<_i3.Response> post( - Uri? url, { - Map? headers, - Object? body, - _i7.Encoding? encoding, - }) => - (super.noSuchMethod( - Invocation.method( - #post, - [url], - { - #headers: headers, - #body: body, - #encoding: encoding, - }, - ), - returnValue: _i6.Future<_i3.Response>.value(_FakeResponse_2( - this, - Invocation.method( - #post, - [url], - { - #headers: headers, - #body: body, - #encoding: encoding, - }, - ), - )), - ) as _i6.Future<_i3.Response>); - - @override - _i6.Future<_i3.Response> put( - Uri? url, { - Map? headers, - Object? body, - _i7.Encoding? encoding, - }) => - (super.noSuchMethod( - Invocation.method( - #put, - [url], - { - #headers: headers, - #body: body, - #encoding: encoding, - }, - ), - returnValue: _i6.Future<_i3.Response>.value(_FakeResponse_2( - this, - Invocation.method( - #put, - [url], - { - #headers: headers, - #body: body, - #encoding: encoding, - }, - ), - )), - ) as _i6.Future<_i3.Response>); - - @override - _i6.Future<_i3.Response> patch( - Uri? url, { - Map? headers, - Object? body, - _i7.Encoding? encoding, - }) => - (super.noSuchMethod( - Invocation.method( - #patch, - [url], - { - #headers: headers, - #body: body, - #encoding: encoding, - }, - ), - returnValue: _i6.Future<_i3.Response>.value(_FakeResponse_2( - this, - Invocation.method( - #patch, - [url], - { - #headers: headers, - #body: body, - #encoding: encoding, - }, - ), - )), - ) as _i6.Future<_i3.Response>); - - @override - _i6.Future<_i3.Response> delete( - Uri? url, { - Map? headers, - Object? body, - _i7.Encoding? encoding, - }) => - (super.noSuchMethod( - Invocation.method( - #delete, - [url], - { - #headers: headers, - #body: body, - #encoding: encoding, - }, - ), - returnValue: _i6.Future<_i3.Response>.value(_FakeResponse_2( - this, - Invocation.method( - #delete, - [url], - { - #headers: headers, - #body: body, - #encoding: encoding, - }, - ), - )), - ) as _i6.Future<_i3.Response>); - - @override - _i6.Future read( - Uri? url, { - Map? headers, - }) => - (super.noSuchMethod( - Invocation.method( - #read, - [url], - {#headers: headers}, - ), - returnValue: _i6.Future.value(_i5.dummyValue( - this, - Invocation.method( - #read, - [url], - {#headers: headers}, - ), - )), - ) as _i6.Future); - - @override - _i6.Future<_i8.Uint8List> readBytes( - Uri? url, { - Map? headers, - }) => - (super.noSuchMethod( - Invocation.method( - #readBytes, - [url], - {#headers: headers}, - ), - returnValue: _i6.Future<_i8.Uint8List>.value(_i8.Uint8List(0)), - ) as _i6.Future<_i8.Uint8List>); - - @override - _i6.Future<_i3.StreamedResponse> send(_i3.BaseRequest? request) => - (super.noSuchMethod( - Invocation.method( - #send, - [request], - ), - returnValue: - _i6.Future<_i3.StreamedResponse>.value(_FakeStreamedResponse_3( - this, - Invocation.method( - #send, - [request], - ), - )), - ) as _i6.Future<_i3.StreamedResponse>); - - @override - void close() => super.noSuchMethod( - Invocation.method( - #close, - [], - ), - returnValueForMissingStub: null, - ); -} diff --git a/test/utils/language/bengali_sentences_test.dart b/test/utils/language/bengali_sentences_test.dart index 413c587c..8d8a429c 100644 --- a/test/utils/language/bengali_sentences_test.dart +++ b/test/utils/language/bengali_sentences_test.dart @@ -103,9 +103,9 @@ void main() { expect(bengali.reportsPageAddTasksToSeeReports, 'রিপোর্ট দেখতে টাস্ক যোগ করুন'); expect(bengali.taskchampionTileDescription, - 'Taskwarrior সিঙ্কিং CCSync বা Taskchampion সিঙ্ক সার্ভারে পরিবর্তন করুন'); + 'Taskwarrior সিঙ্কিং TaskChampion সিঙ্ক সার্ভারে পরিবর্তন করুন'); expect(bengali.taskchampionTileTitle, 'Taskchampion সিঙ্ক'); - expect(bengali.ccsyncCredentials, 'CCSync ক্রেডেনশিয়াল'); + expect(bengali.syncServerCredentials, 'TaskChampion ক্রেডেনশিয়াল'); expect(bengali.deleteTaskConfirmation, 'টাস্ক মুছুন'); expect(bengali.deleteTaskTitle, 'সব টাস্ক মুছুন?'); expect(bengali.deleteTaskWarning, diff --git a/test/utils/language/english_sentences_test.dart b/test/utils/language/english_sentences_test.dart index a2e14071..c898749b 100644 --- a/test/utils/language/english_sentences_test.dart +++ b/test/utils/language/english_sentences_test.dart @@ -101,9 +101,9 @@ void main() { expect(english.reportsPageNoTasksFound, 'No Tasks Found'); expect(english.reportsPageAddTasksToSeeReports, 'Add Tasks To See Reports'); expect(english.taskchampionTileDescription, - 'Switch to Taskwarrior sync with CCSync or Taskchampion Sync Server'); + 'Switch to Taskwarrior sync with a TaskChampion sync server'); expect(english.taskchampionTileTitle, 'Taskchampion sync'); - expect(english.ccsyncCredentials, 'CCync credentials'); + expect(english.syncServerCredentials, 'TaskChampion credentials'); expect(english.deleteTaskConfirmation, 'Delete Tasks'); expect(english.deleteTaskTitle, 'Delete All Tasks?'); expect(english.deleteTaskWarning, diff --git a/test/utils/language/french_sentences_test.dart b/test/utils/language/french_sentences_test.dart index 023647ac..51885971 100644 --- a/test/utils/language/french_sentences_test.dart +++ b/test/utils/language/french_sentences_test.dart @@ -107,9 +107,9 @@ void main() { expect(french.reportsPageAddTasksToSeeReports, 'Ajoutez des tâches pour voir les rapports'); expect(french.taskchampionTileDescription, - 'Basculez la synchronisation de Taskwarrior vers le serveur de synchronisation CCSync ou Taskchampion'); + 'Basculez la synchronisation de Taskwarrior vers le serveur de synchronisation TaskChampion'); expect(french.taskchampionTileTitle, 'Synchronisation Taskchampion'); - expect(french.ccsyncCredentials, 'Identifiants CCSync'); + expect(french.syncServerCredentials, 'Identifiants TaskChampion'); expect(french.deleteTaskConfirmation, 'Supprimer la tâche'); expect(french.deleteTaskTitle, 'Supprimer toutes les tâches ?'); expect(french.deleteTaskWarning, diff --git a/test/utils/language/hindi_sentences_test.dart b/test/utils/language/hindi_sentences_test.dart index 45c41702..e6ddd15b 100644 --- a/test/utils/language/hindi_sentences_test.dart +++ b/test/utils/language/hindi_sentences_test.dart @@ -104,9 +104,9 @@ void main() { expect(hindi.reportsPageAddTasksToSeeReports, 'रिपोर्ट देखने के लिए कार्य जोड़ें'); expect(hindi.taskchampionTileDescription, - 'CCSync या Taskchampion सिंक सर्वर के साथ Taskwarrior सिंक पर स्विच करें'); + 'TaskChampion सिंक सर्वर के साथ Taskwarrior सिंक पर स्विच करें'); expect(hindi.taskchampionTileTitle, 'Taskchampion सिंक'); - expect(hindi.ccsyncCredentials, 'CCync क्रेडेन्शियल'); + expect(hindi.syncServerCredentials, 'TaskChampion क्रेडेन्शियल'); expect(hindi.deleteTaskConfirmation, 'कार्य हटाएं'); expect(hindi.deleteTaskTitle, 'सभी कार्य हटाएं?'); expect(hindi.deleteTaskWarning, diff --git a/test/utils/language/marathi_sentences_test.dart b/test/utils/language/marathi_sentences_test.dart index 57e8104c..1e2c4f6e 100644 --- a/test/utils/language/marathi_sentences_test.dart +++ b/test/utils/language/marathi_sentences_test.dart @@ -103,9 +103,9 @@ void main() { expect( marathi.reportsPageAddTasksToSeeReports, 'अहवाल पाहण्यासाठी काम जोडा'); expect(marathi.taskchampionTileDescription, - 'CCSync किंवा Taskchampion Sync Server सह Taskwarrior सिंक वर स्विच करा'); + 'TaskChampion Sync Server सह Taskwarrior सिंक वर स्विच करा'); expect(marathi.taskchampionTileTitle, 'Taskchampion सिंक'); - expect(marathi.ccsyncCredentials, 'CCync क्रेडेन्शियल'); + expect(marathi.syncServerCredentials, 'TaskChampion क्रेडेन्शियल'); expect(marathi.deleteTaskConfirmation, 'कार्य हटवा'); expect(marathi.deleteTaskTitle, 'सर्व कार्य हटवायचे का?'); expect(marathi.deleteTaskWarning, diff --git a/test/utils/language/sentences_test.dart b/test/utils/language/sentences_test.dart index 7c073bdf..68e5655d 100644 --- a/test/utils/language/sentences_test.dart +++ b/test/utils/language/sentences_test.dart @@ -60,7 +60,7 @@ void main() { expect(sentences.navDrawerReports, isA()); expect(sentences.navDrawerAbout, isA()); expect(sentences.navDrawerSettings, isA()); - expect(sentences.ccsyncCredentials, isA()); + expect(sentences.syncServerCredentials, isA()); expect(sentences.deleteTaskTitle, isA()); expect(sentences.deleteTaskConfirmation, isA()); expect(sentences.deleteTaskWarning, isA()); diff --git a/test/utils/language/spanish_sentences_test.dart b/test/utils/language/spanish_sentences_test.dart index f51722c4..2b97a8b9 100644 --- a/test/utils/language/spanish_sentences_test.dart +++ b/test/utils/language/spanish_sentences_test.dart @@ -105,9 +105,9 @@ void main() { expect(spanish.reportsPageAddTasksToSeeReports, 'Agrega tareas para ver informes'); expect(spanish.taskchampionTileDescription, - 'Cambia la sincronización de Taskwarrior al servidor de sincronización CCSync o Taskchampion'); + 'Cambia la sincronización de Taskwarrior al servidor de sincronización TaskChampion'); expect(spanish.taskchampionTileTitle, 'Sincronización Taskchampion'); - expect(spanish.ccsyncCredentials, 'Credenciales de CCSync'); + expect(spanish.syncServerCredentials, 'Credenciales de TaskChampion'); expect(spanish.deleteTaskConfirmation, 'Eliminar tarea'); expect(spanish.deleteTaskTitle, '¿Eliminar todas las tareas?'); expect(spanish.deleteTaskWarning, diff --git a/test/utils/taskchampion/taskchampion_test.dart b/test/utils/taskchampion/taskchampion_test.dart index 0e0fddb1..9dda50a8 100644 --- a/test/utils/taskchampion/taskchampion_test.dart +++ b/test/utils/taskchampion/taskchampion_test.dart @@ -20,7 +20,7 @@ void main() { expect(controller.encryptionSecretController.text, ''); expect(controller.clientIdController.text, ''); - expect(controller.ccsyncBackendUrlController.text, ''); + expect(controller.syncServerUrlController.text, ''); }); test('should load existing credentials', () async { @@ -34,13 +34,13 @@ void main() { await controller.loadCredentials(); expect(controller.encryptionSecretController.text, 'mysecret'); expect(controller.clientIdController.text, 'client123'); - expect(controller.ccsyncBackendUrlController.text, 'https://example.com'); + expect(controller.syncServerUrlController.text, 'https://example.com'); }); test('should save credentials', () async { controller.encryptionSecretController.text = 'secret123'; controller.clientIdController.text = 'clientABC'; - controller.ccsyncBackendUrlController.text = 'https://backend.url'; + controller.syncServerUrlController.text = 'https://backend.url'; await controller.saveCredentials(); From bdab68080ed950fb83d1949e651ffc6015c7afad Mon Sep 17 00:00:00 2001 From: Chinmay Chaudhari Date: Sat, 20 Jun 2026 08:45:59 +0530 Subject: [PATCH 2/4] fix(ccsync): address audit findings on the sync-retirement change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up hardening after an adversarial review of the CCSync retirement: - saveCredentials(): validate the entered credentials with sync_() BEFORE persisting them via setTaskcCreds(), so invalid credentials are never written to the active profile when validation fails. (The prior order — which mirrored the proposal's example — persisted first, leaving bad creds on disk while telling the user the check failed.) Validation is a live sync, so saving now requires connectivity to the sync server. - Remove the orphaned taskchampionBackendUrl localization getter from the abstract Sentences class and all 8 locale implementations; it became dead when the credentials view's mode-branched URL label collapsed to the single syncServerBackendUrl path. - Fix a stray non-Urdu token ("używaj") left in syncServerEasySyncTitle on a line the rebrand already touched. flutter analyze: 0 errors. Full suite unchanged at +317 -18 (no new failures). --- ...manage_task_champion_creds_controller.dart | 26 ++++++++++++------- lib/app/utils/language/bengali_sentences.dart | 2 -- lib/app/utils/language/english_sentences.dart | 2 -- lib/app/utils/language/french_sentences.dart | 2 -- lib/app/utils/language/german_sentences.dart | 2 -- lib/app/utils/language/hindi_sentences.dart | 2 -- lib/app/utils/language/marathi_sentences.dart | 2 -- lib/app/utils/language/sentences.dart | 1 - lib/app/utils/language/spanish_sentences.dart | 2 -- lib/app/utils/language/urdu_sentences.dart | 4 +-- 10 files changed, 17 insertions(+), 28 deletions(-) diff --git a/lib/app/modules/manage_task_champion_creds/controllers/manage_task_champion_creds_controller.dart b/lib/app/modules/manage_task_champion_creds/controllers/manage_task_champion_creds_controller.dart index 1b418c14..a3211a6c 100644 --- a/lib/app/modules/manage_task_champion_creds/controllers/manage_task_champion_creds_controller.dart +++ b/lib/app/modules/manage_task_champion_creds/controllers/manage_task_champion_creds_controller.dart @@ -29,19 +29,18 @@ class ManageTaskChampionCredsController extends GetxController { taskReplica.value = prefs.getBool('settings_taskr_repl') ?? false; } - /// Validates and persists sync credentials through a single path: - /// the native TaskChampion sync via the Rust FFI bridge. A successful - /// [sync_] confirms the credentials are valid; invalid credentials raise a - /// Rust-level exception that surfaces here as a thrown error. + /// Validates and persists sync credentials through a single path: the native + /// TaskChampion sync via the Rust FFI bridge. + /// + /// The entered credentials are validated with a real [sync_] *before* they + /// are persisted — a successful sync confirms they are valid, while invalid + /// credentials raise a Rust-level exception that surfaces here as a thrown + /// error. This ordering guarantees we never write unverified credentials into + /// the active profile. (Because validation is a live sync, saving requires + /// connectivity to the sync server.) Future saveCredentials() async { isCheckingCreds.value = true; try { - profilesWidget.setTaskcCreds( - profilesWidget.currentProfile.value, - clientIdController.text, - encryptionSecretController.text, - syncServerUrlController.text, - ); final String replicaPath = await Replica.getReplicaPath(); await sync_( taskdbDirPath: replicaPath, @@ -49,6 +48,13 @@ class ManageTaskChampionCredsController extends GetxController { clientId: clientIdController.text, encryptionSecret: encryptionSecretController.text, ); + // Only persist after the sync has confirmed the credentials are valid. + profilesWidget.setTaskcCreds( + profilesWidget.currentProfile.value, + clientIdController.text, + encryptionSecretController.text, + syncServerUrlController.text, + ); isCheckingCreds.value = false; return 0; } catch (err) { diff --git a/lib/app/utils/language/bengali_sentences.dart b/lib/app/utils/language/bengali_sentences.dart index 3e8df8b0..46d9f3fb 100644 --- a/lib/app/utils/language/bengali_sentences.dart +++ b/lib/app/utils/language/bengali_sentences.dart @@ -686,6 +686,4 @@ class BengaliSentences extends Sentences { String get storageAndData => 'স্টোরেজ এবং ডাটা'; @override String get advanced => 'উন্নত'; - @override - String get taskchampionBackendUrl => 'Taskchampion ব্যাকএন্ড URL'; } diff --git a/lib/app/utils/language/english_sentences.dart b/lib/app/utils/language/english_sentences.dart index c793f7e9..716a3e96 100644 --- a/lib/app/utils/language/english_sentences.dart +++ b/lib/app/utils/language/english_sentences.dart @@ -675,6 +675,4 @@ class EnglishSentences extends Sentences { String get storageAndData => 'Storage and Data'; @override String get advanced => 'Advanced'; - @override - String get taskchampionBackendUrl => 'Taskchampion URL'; } diff --git a/lib/app/utils/language/french_sentences.dart b/lib/app/utils/language/french_sentences.dart index 18f57a86..d1f15411 100644 --- a/lib/app/utils/language/french_sentences.dart +++ b/lib/app/utils/language/french_sentences.dart @@ -705,6 +705,4 @@ class FrenchSentences extends Sentences { String get storageAndData => 'Stockage et données'; @override String get advanced => 'Avancé'; - @override - String get taskchampionBackendUrl => 'URL de Taskchampion'; } diff --git a/lib/app/utils/language/german_sentences.dart b/lib/app/utils/language/german_sentences.dart index cd9ded85..ed2ef0f2 100644 --- a/lib/app/utils/language/german_sentences.dart +++ b/lib/app/utils/language/german_sentences.dart @@ -675,6 +675,4 @@ class GermanSentences extends Sentences { String get storageAndData => 'Speicher und Daten'; @override String get advanced => 'Fortgeschritten'; - @override - String get taskchampionBackendUrl => 'Taskchampion URL'; } diff --git a/lib/app/utils/language/hindi_sentences.dart b/lib/app/utils/language/hindi_sentences.dart index 02b06f47..2252005a 100644 --- a/lib/app/utils/language/hindi_sentences.dart +++ b/lib/app/utils/language/hindi_sentences.dart @@ -664,6 +664,4 @@ class HindiSentences extends Sentences { String get storageAndData => 'स्टोरेज और डेटा'; @override String get advanced => 'अड्वांस्ड'; - @override - String get taskchampionBackendUrl => 'Taskchampion URL'; } diff --git a/lib/app/utils/language/marathi_sentences.dart b/lib/app/utils/language/marathi_sentences.dart index 8f497220..a96e4959 100644 --- a/lib/app/utils/language/marathi_sentences.dart +++ b/lib/app/utils/language/marathi_sentences.dart @@ -688,6 +688,4 @@ class MarathiSentences extends Sentences { String get storageAndData => 'स्टोरेज आणि डेटा'; @override String get advanced => 'अड्वांस्ड'; - @override - String get taskchampionBackendUrl => 'Taskchampion URL'; } diff --git a/lib/app/utils/language/sentences.dart b/lib/app/utils/language/sentences.dart index c8e52200..d2560cab 100644 --- a/lib/app/utils/language/sentences.dart +++ b/lib/app/utils/language/sentences.dart @@ -348,7 +348,6 @@ abstract class Sentences { String get configureTaskchampion; String get encryptionSecret; String get syncServerBackendUrl; - String get taskchampionBackendUrl; String get syncServerClientId; String get success; String get credentialsSavedSuccessfully; diff --git a/lib/app/utils/language/spanish_sentences.dart b/lib/app/utils/language/spanish_sentences.dart index 4780fa7f..5ed6b740 100644 --- a/lib/app/utils/language/spanish_sentences.dart +++ b/lib/app/utils/language/spanish_sentences.dart @@ -692,6 +692,4 @@ class SpanishSentences extends Sentences { String get storageAndData => 'Almacenamiento y datos'; @override String get advanced => 'Avanzado'; - @override - String get taskchampionBackendUrl => 'Taskchampion URL'; } diff --git a/lib/app/utils/language/urdu_sentences.dart b/lib/app/utils/language/urdu_sentences.dart index a76a3ab5..f8cf270c 100644 --- a/lib/app/utils/language/urdu_sentences.dart +++ b/lib/app/utils/language/urdu_sentences.dart @@ -5,7 +5,7 @@ class UrduSentences extends Sentences { String get syncServerLoginInstruction => 'TaskChampion میں لاگ ان کریں، اپنی اسناد کاپی کریں، اور اوپر پیسٹ کریں۔'; @override - String get syncServerEasySyncTitle => 'آسان سینک کے لیے TaskChampion کا używaj'; + String get syncServerEasySyncTitle => 'آسان سینک کے لیے TaskChampion کا استعمال کریں'; @override String get syncServerOpenButton => 'TaskChampion کھولیں'; @override @@ -679,6 +679,4 @@ class UrduSentences extends Sentences { String get storageAndData => 'اسٹوریج اور ڈیٹا'; @override String get advanced => 'ایڈوانس'; - @override - String get taskchampionBackendUrl => 'Taskchampion یو آر ایل'; } From f013a872441ef4fa0c668ee7ac0d2f473d4a472c Mon Sep 17 00:00:00 2001 From: Chinmay Chaudhari Date: Thu, 9 Jul 2026 01:32:43 +0530 Subject: [PATCH 3/4] refactor(ccsync): remove residual CCSync references from the profile UI Follow-up to the CCSync retirement: the profile page still surfaced the "CCSync" brand -- the "changed profile mode to CCSync" snackbar label and a commented-out "CCSync (v3)" mode radio. Rebrand the label to "Taskchampion" (matching the retained TW3C mode) and delete the dead commented block. --- lib/app/modules/profile/views/profile_view.dart | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/lib/app/modules/profile/views/profile_view.dart b/lib/app/modules/profile/views/profile_view.dart index a50eec66..e3d811ac 100644 --- a/lib/app/modules/profile/views/profile_view.dart +++ b/lib/app/modules/profile/views/profile_view.dart @@ -264,17 +264,6 @@ class ProfileView extends GetView { }); }, ), - // CCSync v3 is deprecated, so hiding it for now - // RadioListTile( - // title: const Text('CCSync (v3)'), - // value: 'TW3', - // groupValue: selectedMode, - // onChanged: (String? value) { - // setState(() { - // selectedMode = value; - // }); - // }, - // ), RadioListTile( title: const Text('TaskServer'), value: 'TW2', @@ -327,8 +316,8 @@ class ProfileView extends GetView { AppSettings.selectedLanguage) .sentences .profilePageSuccessfullyChangedProfileModeTo + - ((selectedMode ?? "") == "TW3" - ? "CCSync" + ((selectedMode ?? "") == "TW3C" + ? "Taskchampion" : "Taskserver"), style: TextStyle( color: tColors.primaryTextColor, From 8aac26ee4d9f3a091f9b53847a366102150f30f8 Mon Sep 17 00:00:00 2001 From: Chinmay Chaudhari Date: Thu, 9 Jul 2026 01:32:43 +0530 Subject: [PATCH 4/4] fix(deps): pin flutter_rust_bridge to 2.11.1 to match generated bindings pubspec used a caret constraint, so `flutter pub get` could resolve the newer 2.12.0 runtime while the committed FFI bindings were generated with codegen 2.11.1. That mismatch crashed the app at RustLib.init() on startup. Pinning the exact 2.11.1 (matching rust/Cargo.toml's =2.11.1) keeps the Dart package, generated bindings, and native library in lockstep. --- pubspec.lock | 108 +++++++++++++++++++++++++++++++++++++-------------- pubspec.yaml | 2 +- 2 files changed, 79 insertions(+), 31 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index c7182030..0659d451 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f + sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d url: "https://pub.dev" source: hosted - version: "85.0.0" + version: "91.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d" + sha256: f51c8499b35f9b26820cfe914828a6a98a94efd5cc78b37bb7d03debae3a1d08 url: "https://pub.dev" source: hosted - version: "7.7.1" + version: "8.4.1" ansicolor: dependency: transitive description: @@ -25,6 +25,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + app_links: + dependency: "direct main" + description: + name: app_links + sha256: "5f88447519add627fe1cbcab4fd1da3d4fed15b9baf29f28b22535c95ecee3e8" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + app_links_linux: + dependency: transitive + description: + name: app_links_linux + sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81 + url: "https://pub.dev" + source: hosted + version: "1.0.3" + app_links_platform_interface: + dependency: transitive + description: + name: app_links_platform_interface + sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + app_links_web: + dependency: transitive + description: + name: app_links_web + sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555 + url: "https://pub.dev" + source: hosted + version: "1.0.4" archive: dependency: transitive description: @@ -65,6 +97,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + build_cli_annotations: + dependency: transitive + description: + name: build_cli_annotations + sha256: e563c2e01de8974566a1998410d3f6f03521788160a02503b0b1f1a46c7b3d95 + url: "https://pub.dev" + source: hosted + version: "2.1.1" build_config: dependency: transitive description: @@ -125,10 +165,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" checked_yaml: dependency: transitive description: @@ -253,10 +293,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" + sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.3" dartx: dependency: transitive description: @@ -519,6 +559,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.32" + flutter_rust_bridge: + dependency: "direct main" + description: + name: flutter_rust_bridge + sha256: "37ef40bc6f863652e865f0b2563ea07f0d3c58d8efad803cc01933a4b2ee067e" + url: "https://pub.dev" + source: hosted + version: "2.11.1" flutter_slidable: dependency: "direct main" description: @@ -601,6 +649,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + gtk: + dependency: transitive + description: + name: gtk + sha256: "4ff85b2a16724029dd9e5bbb5a94b6918f9973f74ba571c949d2002801879cf5" + url: "https://pub.dev" + source: hosted + version: "2.2.0" hashcodes: dependency: transitive description: @@ -721,14 +777,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" json_annotation: dependency: transitive description: @@ -797,18 +845,18 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.19" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" meta: dependency: transitive description: @@ -829,10 +877,10 @@ packages: dependency: "direct main" description: name: mockito - sha256: "2314cbe9165bcd16106513df9cf3c3224713087f09723b128928dc11a4379f99" + sha256: eff30d002f0c8bf073b6f929df4483b543133fcafce056870163587b03f1d422 url: "https://pub.dev" source: hosted - version: "5.5.0" + version: "5.6.4" nm: dependency: transitive description: @@ -1141,10 +1189,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "3.0.0" sizer: dependency: "direct main" description: @@ -1330,26 +1378,26 @@ packages: dependency: "direct main" description: name: test - sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7" + sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7" url: "https://pub.dev" source: hosted - version: "1.26.3" + version: "1.30.0" test_api: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.10" test_core: dependency: transitive description: name: test_core - sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0" + sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51" url: "https://pub.dev" source: hosted - version: "0.6.12" + version: "0.6.16" textfield_tags: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 12e80726..1a45a235 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -66,7 +66,7 @@ dependencies: built_collection: ^5.1.1 textfield_tags: ^3.0.1 path_provider: ^2.1.5 - flutter_rust_bridge: ^2.11.1 + flutter_rust_bridge: 2.11.1 ffi: any # Required for FFI app_links: ^6.4.1