Skip to content

Commit 9741929

Browse files
committed
complete integration with local rust Replica
1 parent 8aa192f commit 9741929

File tree

11 files changed

+256
-93
lines changed

11 files changed

+256
-93
lines changed

lib/app/modules/home/controllers/home_controller.dart

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -117,23 +117,16 @@ class HomeController extends GetxController {
117117
widgetController.updateWidget();
118118
}
119119
});
120-
tryRust();
121-
}
122-
123-
Future<void> tryRust() async {
124-
Directory? someDir = await getDownloadsDirectory();
125-
126-
addTask(taskdbDirPath: someDir != null ? someDir.path : "", map: {
127-
'description': "some task from bridge 2",
128-
"uuid": "270750a0-1801-4a24-8b29-a7aaf62fc74d",
129-
"tags": "t1 t2 t3"
130-
});
131-
132-
debugPrint(
133-
"tryRustHere: ${await getAllTasksJson(taskdbDirPath: someDir != null ? someDir.path : "")}");
134120
}
135121

136122
Future<List<String>> getUniqueProjects() async {
123+
if (taskReplica.value) {
124+
return tasksFromReplica
125+
.where((task) => task.project != null)
126+
.map((task) => task.project!)
127+
.toSet()
128+
.toList();
129+
}
137130
var taskDatabase = TaskDatabase();
138131
List<String> uniqueProjects = await taskDatabase.fetchUniqueProjects();
139132
debugPrint('Unique projects: $uniqueProjects');
@@ -146,6 +139,12 @@ class HomeController extends GetxController {
146139
debugPrint('Deleted all tasks from db');
147140
}
148141

142+
Future<void> refreshReplicaTaskList() async {
143+
if (!taskReplica.value) return;
144+
tasksFromReplica.value = await Replica.getAllTasksFromReplica();
145+
debugPrint("Tasks from Replica: ${tasks.length}");
146+
}
147+
149148
Future<void> refreshTasks(String clientId, String encryptionSecret) async {
150149
TaskDatabase taskDatabase = TaskDatabase();
151150
await taskDatabase.open();
@@ -181,6 +180,7 @@ class HomeController extends GetxController {
181180

182181
Future<void> refreshReplicaTasks() async {
183182
if (!taskReplica.value) return;
183+
await Replica.sync();
184184
tasksFromReplica.value = await Replica.getAllTasksFromReplica();
185185
debugPrint("Tasks from Replica: ${tasks.length}");
186186
}

lib/app/modules/home/views/add_task_bottom_sheet_new.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ class AddTaskBottomSheet extends StatelessWidget {
224224
onDateChanges: (List<DateTime?> p0) {
225225
homeController.selectedDates.value = p0;
226226
},
227-
onlyDueDate: forTaskC,
227+
onlyDueDate: forTaskC || forReplica,
228228
);
229229

230230
Widget buildPriority(BuildContext context) => Column(

lib/app/modules/home/views/filter_drawer_home_page.dart

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ class FilterDrawer extends StatelessWidget {
2424
Widget build(BuildContext context) {
2525
homeController.initFilterDrawerTour();
2626
homeController.showFilterDrawerTour(context);
27-
TaskwarriorColorTheme tColors = Theme.of(context).extension<TaskwarriorColorTheme>()!;
27+
TaskwarriorColorTheme tColors =
28+
Theme.of(context).extension<TaskwarriorColorTheme>()!;
2829
var tileColor = AppSettings.isDarkMode
2930
? TaskWarriorColors.ksecondaryBackgroundColor
3031
: TaskWarriorColors.kLightPrimaryBackgroundColor;
@@ -122,47 +123,51 @@ class FilterDrawer extends StatelessWidget {
122123
const Divider(
123124
color: Color.fromARGB(0, 48, 46, 46),
124125
),
125-
Container(
126-
decoration: BoxDecoration(
127-
color: tileColor,
128-
borderRadius: BorderRadius.circular(8),
129-
border: Border.all(color: TaskWarriorColors.borderColor),
130-
),
131-
child: Padding(
132-
padding: const EdgeInsets.all(8.0),
133-
child: Row(
134-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
135-
children: [
136-
Text(
137-
!filters.waitingFilter
138-
? SentenceManager(
139-
currentLanguage:
140-
homeController.selectedLanguage.value)
141-
.sentences
142-
.filterDrawerShowWaiting
143-
: SentenceManager(
144-
currentLanguage:
145-
homeController.selectedLanguage.value)
146-
.sentences
147-
.filterDrawerHideWaiting,
148-
style: TextStyle(
149-
fontFamily: FontFamily.poppins,
150-
fontSize: TaskWarriorFonts.fontSizeMedium,
151-
color: tColors.primaryTextColor,
152-
)),
153-
Switch(
154-
value: filters.waitingFilter,
155-
onChanged: (_) => filters.toggleWaitingFilter(),
156-
)
157-
],
126+
Visibility(
127+
visible: !homeController.taskReplica.value,
128+
child: Container(
129+
decoration: BoxDecoration(
130+
color: tileColor,
131+
borderRadius: BorderRadius.circular(8),
132+
border: Border.all(color: TaskWarriorColors.borderColor),
133+
),
134+
child: Padding(
135+
padding: const EdgeInsets.all(8.0),
136+
child: Row(
137+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
138+
children: [
139+
Text(
140+
!filters.waitingFilter
141+
? SentenceManager(
142+
currentLanguage: homeController
143+
.selectedLanguage.value)
144+
.sentences
145+
.filterDrawerShowWaiting
146+
: SentenceManager(
147+
currentLanguage: homeController
148+
.selectedLanguage.value)
149+
.sentences
150+
.filterDrawerHideWaiting,
151+
style: TextStyle(
152+
fontFamily: FontFamily.poppins,
153+
fontSize: TaskWarriorFonts.fontSizeMedium,
154+
color: tColors.primaryTextColor,
155+
)),
156+
Switch(
157+
value: filters.waitingFilter,
158+
onChanged: (_) => filters.toggleWaitingFilter(),
159+
)
160+
],
161+
),
158162
),
159163
),
160164
),
161165
const Divider(
162166
color: Color.fromARGB(0, 48, 46, 46),
163167
),
164168
Visibility(
165-
visible: !homeController.taskchampion.value,
169+
visible: !homeController.taskchampion.value &&
170+
!homeController.taskReplica.value,
166171
child: Container(
167172
key: homeController.projectsKey,
168173
width: MediaQuery.of(context).size.width * 1,
@@ -182,7 +187,8 @@ class FilterDrawer extends StatelessWidget {
182187
),
183188
),
184189
Visibility(
185-
visible: homeController.taskchampion.value,
190+
visible: homeController.taskchampion.value ||
191+
homeController.taskReplica.value,
186192
child: FutureBuilder<List<String>>(
187193
future: homeController.getUniqueProjects(),
188194
builder: (BuildContext context,
@@ -219,7 +225,8 @@ class FilterDrawer extends StatelessWidget {
219225
color: Color.fromARGB(0, 48, 46, 46),
220226
),
221227
Visibility(
222-
visible: !homeController.taskchampion.value,
228+
visible: !homeController.taskchampion.value &&
229+
!homeController.taskReplica.value,
223230
child: Container(
224231
key: homeController.filterTagKey,
225232
width: MediaQuery.of(context).size.width * 1,
@@ -273,7 +280,8 @@ class FilterDrawer extends StatelessWidget {
273280
),
274281
),
275282
Visibility(
276-
visible: !homeController.taskchampion.value,
283+
visible: !homeController.taskchampion.value &&
284+
!homeController.taskReplica.value,
277285
child: const Divider(
278286
color: Color.fromARGB(0, 48, 46, 46),
279287
),

lib/app/modules/home/views/home_page_app_bar.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,13 @@ class HomePageAppBar extends StatelessWidget implements PreferredSizeWidget {
131131
onPressed: controller.isRefreshing.value
132132
? null
133133
: () async {
134+
debugPrint("Refresh button pressed");
134135
if (controller.taskReplica.value) {
135136
var c = await CredentialsStorage.getClientId();
136137
var e =
137138
await CredentialsStorage.getEncryptionSecret();
139+
debugPrint(
140+
"controller.taskReplica.value ${controller.taskReplica.value} Replica Credentials: c=$c e=$e");
138141
if (c == null || e == null) {
139142
_showResultSnackBar(
140143
context,
@@ -146,9 +149,11 @@ class HomePageAppBar extends StatelessWidget implements PreferredSizeWidget {
146149
true);
147150
return;
148151
}
152+
debugPrint("Refreshing Replica tasks");
149153
controller.isRefreshing.value = true;
150154
await controller.refreshReplicaTasks();
151155
controller.isRefreshing.value = false;
156+
return;
152157
}
153158

154159
if (controller.taskchampion.value) {

lib/app/modules/home/views/show_tasks_replica.dart

Lines changed: 81 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import 'package:flutter/material.dart';
22
import 'package:get/get.dart';
3+
import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart';
34
import 'package:google_fonts/google_fonts.dart';
5+
import 'package:flutter_slidable/flutter_slidable.dart';
6+
import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart';
47
import 'package:taskwarrior/app/routes/app_pages.dart';
58
import 'package:taskwarrior/app/utils/app_settings/app_settings.dart';
6-
import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart';
79
import 'package:taskwarrior/app/utils/constants/taskwarrior_fonts.dart';
810
import 'package:taskwarrior/app/utils/themes/theme_extension.dart';
911
import 'package:taskwarrior/app/utils/language/sentence_manager.dart';
12+
import 'package:taskwarrior/app/v3/champion/Replica.dart';
1013
import 'package:taskwarrior/app/v3/champion/models/task_for_replica.dart';
1114

12-
/// A lightweight view builder for TaskForReplica objects.
13-
/// This mirrors `TaskViewBuilder` but only uses fields available on the
14-
/// `TaskForReplica` model (modified, due, status, description, tags, uuid, priority).
1515
class TaskReplicaViewBuilder extends StatelessWidget {
1616
const TaskReplicaViewBuilder({
1717
super.key,
@@ -32,22 +32,15 @@ class TaskReplicaViewBuilder extends StatelessWidget {
3232
Theme.of(context).extension<TaskwarriorColorTheme>()!;
3333

3434
return Obx(() {
35-
// We receive the tasks list from the caller so we copy it here.
3635
List<TaskForReplica> tasks = List<TaskForReplica>.from(replicaTasks);
37-
38-
// Project filtering is not meaningful for TaskForReplica if project is not set
3936
if (project != null && project != 'All Projects') {
40-
// TaskForReplica doesn't have a `project` field by default, so skip filtering.
37+
tasks = tasks.where((task) => task.project == project).toList();
4138
}
42-
43-
// Default sort: by modified desc if available
4439
tasks.sort((a, b) {
4540
final am = a.modified ?? 0;
4641
final bm = b.modified ?? 0;
4742
return bm.compareTo(am);
4843
});
49-
50-
// Apply pending/completed filter
5144
tasks = tasks.where((task) {
5245
if (pendingFilter) {
5346
return task.status == 'pending';
@@ -56,7 +49,6 @@ class TaskReplicaViewBuilder extends StatelessWidget {
5649
}
5750
}).toList();
5851

59-
// Only allow sorting by fields that exist on TaskForReplica
6052
tasks.sort((a, b) {
6153
switch (selectedSort) {
6254
case 'Modified+':
@@ -106,7 +98,26 @@ class TaskReplicaViewBuilder extends StatelessWidget {
10698
itemCount: tasks.length,
10799
itemBuilder: (context, index) {
108100
final task = tasks[index];
109-
return Card(
101+
// Determine if due is within 24 hours or already past (only for pending filter)
102+
final bool isDueSoon = (() {
103+
if (!pendingFilter) return false;
104+
// Only apply due-soon highlighting when delay-task setting is enabled
105+
try {
106+
final HomeController hc = Get.find<HomeController>();
107+
if (!hc.useDelayTask.value) return false;
108+
} catch (_) {
109+
return false;
110+
}
111+
final dueStr = task.due;
112+
if (dueStr == null || dueStr.isEmpty) return false;
113+
final parsed = DateTime.tryParse(dueStr);
114+
if (parsed == null) return false;
115+
final now = DateTime.now().toUtc();
116+
final threshold = now.add(const Duration(hours: 24));
117+
return parsed.toUtc().isBefore(threshold);
118+
})();
119+
120+
final card = Card(
110121
color: tColors.secondaryBackgroundColor,
111122
child: InkWell(
112123
splashColor: tColors.primaryBackgroundColor,
@@ -115,7 +126,9 @@ class TaskReplicaViewBuilder extends StatelessWidget {
115126
child: Container(
116127
decoration: BoxDecoration(
117128
border: Border.all(
118-
color: tColors.primaryTextColor!,
129+
color: isDueSoon
130+
? Colors.red
131+
: tColors.primaryTextColor!,
119132
),
120133
color: tColors.primaryBackgroundColor,
121134
borderRadius: BorderRadius.circular(8.0),
@@ -144,6 +157,49 @@ class TaskReplicaViewBuilder extends StatelessWidget {
144157
),
145158
),
146159
);
160+
161+
// Only enable swipe actions (complete/delete) when pendingFilter is true
162+
if (pendingFilter) {
163+
return Slidable(
164+
startActionPane: ActionPane(
165+
motion: const BehindMotion(),
166+
children: [
167+
SlidableAction(
168+
onPressed: (ctx) {
169+
completeTask(task);
170+
},
171+
icon: Icons.done,
172+
label: SentenceManager(
173+
currentLanguage:
174+
AppSettings.selectedLanguage)
175+
.sentences
176+
.complete,
177+
backgroundColor: TaskWarriorColors.green,
178+
),
179+
],
180+
),
181+
endActionPane: ActionPane(
182+
motion: const DrawerMotion(),
183+
children: [
184+
SlidableAction(
185+
onPressed: (ctx) {
186+
deleteTask(task);
187+
},
188+
icon: Icons.delete,
189+
label: SentenceManager(
190+
currentLanguage:
191+
AppSettings.selectedLanguage)
192+
.sentences
193+
.delete,
194+
backgroundColor: TaskWarriorColors.red,
195+
),
196+
],
197+
),
198+
child: card,
199+
);
200+
}
201+
202+
return card;
147203
},
148204
),
149205
);
@@ -162,4 +218,14 @@ class TaskReplicaViewBuilder extends StatelessWidget {
162218
return Colors.grey;
163219
}
164220
}
221+
222+
void completeTask(TaskForReplica task) async {
223+
await Replica.modifyTaskInReplica(task.copyWith(status: 'completed'));
224+
Get.find<HomeController>().refreshReplicaTaskList();
225+
}
226+
227+
void deleteTask(TaskForReplica task) async {
228+
await Replica.deleteTaskFromReplica(task.uuid);
229+
Get.find<HomeController>().refreshReplicaTaskList();
230+
}
165231
}

lib/app/modules/profile/views/profile_view.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,11 @@ class ProfileView extends GetView<ProfileController> {
9999
),
100100
() {
101101
if (controller.profilesWidget
102-
.getMode(controller.currentProfile.value) ==
103-
'TW3') {
102+
.getMode(controller.currentProfile.value) ==
103+
'TW3' ||
104+
controller.profilesWidget
105+
.getMode(controller.currentProfile.value) ==
106+
'TW3C') {
104107
Get.toNamed(Routes.MANAGE_TASK_CHAMPION_CREDS);
105108
return;
106109
}

lib/app/modules/splash/controllers/splash_controller.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class SplashController extends GetxController {
8989
await prefs.setBool('settings_taskc', getMode(profile) == 'TW3');
9090
await prefs.setBool('settings_taskr_repl', getMode(profile) == 'TW3C');
9191
Get.find<HomeController>().taskchampion.value = getMode(profile) == 'TW3';
92+
Get.find<HomeController>().taskReplica.value = getMode(profile) == 'TW3C';
9293
Get.find<HomeController>().tasks.value = <TaskForC>[].obs;
9394
currentProfile.value = _profiles.getCurrentProfile()!;
9495
}

0 commit comments

Comments
 (0)