Skip to content

Commit 4327d71

Browse files
feat : added task swipe tour (#460)
* rebase * added tests * reverted changes to pubspec.lock and GeneratedPluginRegistrant.swift
1 parent 64f8e2b commit 4327d71

File tree

6 files changed

+199
-6
lines changed

6 files changed

+199
-6
lines changed

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import 'package:taskwarrior/app/routes/app_pages.dart';
2323
import 'package:taskwarrior/app/services/tag_filter.dart';
2424
import 'package:taskwarrior/app/tour/filter_drawer_tour.dart';
2525
import 'package:taskwarrior/app/tour/home_page_tour.dart';
26+
import 'package:taskwarrior/app/tour/task_swipe_tour.dart';
2627
import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart';
2728
import 'package:taskwarrior/app/utils/language/supported_language.dart';
2829
import 'package:taskwarrior/app/utils/taskchampion/credentials_storage.dart';
@@ -673,6 +674,34 @@ class HomeController extends GetxController {
673674
);
674675
}
675676

677+
final taskItemKey = GlobalKey();
678+
679+
void initTaskSwipeTutorial() {
680+
tutorialCoachMark = TutorialCoachMark(
681+
targets: addTaskSwipeTutorialTargets(taskItemKey: taskItemKey),
682+
colorShadow: TaskWarriorColors.black,
683+
paddingFocus: 10,
684+
opacityShadow: 1.00,
685+
hideSkip: true,
686+
onFinish: () {
687+
SaveTourStatus.saveTaskSwipeTutorialStatus(true);
688+
},
689+
);
690+
}
691+
692+
void showTaskSwipeTutorial(BuildContext context) {
693+
SaveTourStatus.getTaskSwipeTutorialStatus().then((value) {
694+
print("value is $value");
695+
print("tasks is ${tasks.isNotEmpty}");
696+
if (value == false) {
697+
initTaskSwipeTutorial();
698+
tutorialCoachMark.show(context: context);
699+
} else {
700+
debugPrint('User has already seen the task swipe tutorial');
701+
}
702+
});
703+
}
704+
676705
late RxString uuid = "".obs;
677706
late RxBool isHomeWidgetTaskTapped = false.obs;
678707

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,7 @@ class TasksBuilder extends StatelessWidget {
7070
action: SnackBarAction(
7171
label: 'Undo',
7272
onPressed: () {
73-
undoChanges(
74-
context, id, 'pending');
75-
73+
undoChanges(context, id, 'pending');
7674
},
7775
),
7876
));
@@ -170,9 +168,13 @@ class TasksBuilder extends StatelessWidget {
170168
primary: false,
171169
itemBuilder: (context, index) {
172170
var task = taskData[index];
171+
final itemKey = index == 0
172+
? storageWidget.taskItemKey
173+
: ValueKey(task.uuid);
174+
173175
return pendingFilter
174176
? Slidable(
175-
key: ValueKey(task.uuid),
177+
key: itemKey,
176178
startActionPane: ActionPane(
177179
motion: const BehindMotion(),
178180
children: [

lib/app/tour/task_swipe_tour.dart

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:google_fonts/google_fonts.dart';
3+
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
4+
5+
List<TargetFocus> addTaskSwipeTutorialTargets({
6+
required GlobalKey taskItemKey,
7+
}) {
8+
List<TargetFocus> targets = [];
9+
10+
targets.add(
11+
TargetFocus(
12+
identify: "taskSwipeTutorial",
13+
keyTarget: taskItemKey,
14+
alignSkip: Alignment.bottomRight,
15+
radius: 10,
16+
shape: ShapeLightFocus.RRect,
17+
contents: [
18+
TargetContent(
19+
align: ContentAlign.bottom,
20+
builder: (context, controller) {
21+
return Container(
22+
alignment: Alignment.center,
23+
child: Column(
24+
crossAxisAlignment: CrossAxisAlignment.center,
25+
mainAxisAlignment: MainAxisAlignment.center,
26+
children: <Widget>[
27+
Text(
28+
"Task Swipe Actions",
29+
textAlign: TextAlign.center,
30+
style: GoogleFonts.poppins(
31+
color: Colors.white,
32+
fontWeight: FontWeight.bold,
33+
fontSize: 22.0,
34+
),
35+
),
36+
const SizedBox(height: 8),
37+
Text(
38+
"This is how you manage your tasks quickly : ",
39+
textAlign: TextAlign.center,
40+
style: GoogleFonts.poppins(
41+
color: Colors.white,
42+
fontStyle: FontStyle.italic,
43+
fontSize: 16.0,
44+
),
45+
),
46+
Padding(
47+
padding: const EdgeInsets.only(top: 16.0),
48+
child: Row(
49+
mainAxisAlignment: MainAxisAlignment.center,
50+
children: [
51+
const Icon(Icons.arrow_right_alt,
52+
color: Colors.green, size: 28),
53+
const SizedBox(width: 8),
54+
Flexible(
55+
child: Text(
56+
"Swipe RIGHT to COMPLETE",
57+
textAlign: TextAlign.left,
58+
style: GoogleFonts.poppins(
59+
color: Colors.white,
60+
fontWeight: FontWeight.w500,
61+
),
62+
),
63+
),
64+
],
65+
),
66+
),
67+
Padding(
68+
padding: const EdgeInsets.only(top: 10.0),
69+
child: Row(
70+
mainAxisAlignment: MainAxisAlignment.center,
71+
children: [
72+
const Icon(Icons.arrow_right_alt,
73+
textDirection: TextDirection.rtl,
74+
color: Colors.red,
75+
size: 28),
76+
const SizedBox(width: 8),
77+
Flexible(
78+
child: Text(
79+
"Swipe LEFT to DELETE",
80+
textAlign: TextAlign.left,
81+
style: GoogleFonts.poppins(
82+
color: Colors.white,
83+
fontWeight: FontWeight.w500,
84+
),
85+
),
86+
),
87+
],
88+
),
89+
),
90+
],
91+
),
92+
);
93+
},
94+
),
95+
],
96+
),
97+
);
98+
99+
return targets;
100+
}

lib/app/utils/app_settings/save_tour_status.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,12 @@ class SaveTourStatus {
5454
static Future<bool> getManageTaskServerTourStatus() async {
5555
return _preferences?.getBool('manage_task_server_tour') ?? false;
5656
}
57+
58+
static Future saveTaskSwipeTutorialStatus(bool status) async {
59+
await _preferences?.setBool('task_swipe_tutorial_completed', status);
60+
}
61+
62+
static Future<bool> getTaskSwipeTutorialStatus() async {
63+
return _preferences?.getBool('task_swipe_tutorial_completed') ?? false;
64+
}
5765
}

pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ dependencies:
5151
package_info_plus: ^8.3.0
5252
pem: ^2.0.1
5353
permission_handler: ^11.4.0
54-
shared_preferences: ^2.2.2
54+
shared_preferences: ^2.5.2
5555
shared_preferences_web: ^2.0.3
5656
sizer: ^3.0.5
5757
sqflite: ^2.3.3+1
@@ -61,7 +61,7 @@ dependencies:
6161
timezone: ^0.10.0
6262
tuple: ^2.0.0
6363
tutorial_coach_mark: ^1.2.11
64-
url_launcher: ^6.1.14
64+
url_launcher: ^6.3.1
6565
uuid: ^4.2.2
6666
built_collection: ^5.1.1
6767
textfield_tags: ^3.0.1

test/tour/task_swipe_tour_test.dart

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_test/flutter_test.dart';
3+
import 'package:mockito/mockito.dart';
4+
import 'package:taskwarrior/app/tour/task_swipe_tour.dart';
5+
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
6+
7+
class MockTutorialCoachMarkController extends Mock
8+
implements TutorialCoachMarkController {}
9+
10+
void main() {
11+
group('Task Swipe Tour', () {
12+
late GlobalKey taskItemKey;
13+
final controller = MockTutorialCoachMarkController();
14+
15+
setUp(() {
16+
taskItemKey = GlobalKey();
17+
});
18+
19+
test('should return a list of TargetFocus with correct properties', () {
20+
final targets = addTaskSwipeTutorialTargets(
21+
taskItemKey: taskItemKey,
22+
);
23+
24+
expect(targets.length, 1);
25+
26+
expect(targets[0].keyTarget, taskItemKey);
27+
expect(targets[0].identify, "taskSwipeTutorial");
28+
expect(targets[0].alignSkip, Alignment.bottomRight);
29+
expect(targets[0].shape, ShapeLightFocus.RRect);
30+
expect(targets[0].radius, 10);
31+
});
32+
33+
testWidgets('should render correct text for task swipe TargetContent',
34+
(WidgetTester tester) async {
35+
final targets = addTaskSwipeTutorialTargets(
36+
taskItemKey: taskItemKey,
37+
);
38+
39+
final content = targets[0].contents!.first;
40+
41+
await tester.pumpWidget(MaterialApp(
42+
home: Builder(
43+
builder: (context) => content.builder!(context, controller),
44+
),
45+
));
46+
47+
expect(find.text("Task Swipe Actions"), findsOneWidget);
48+
expect(find.text("This is how you manage your tasks quickly : "),
49+
findsOneWidget);
50+
expect(find.text("Swipe RIGHT to COMPLETE"), findsOneWidget);
51+
expect(find.text("Swipe LEFT to DELETE"), findsOneWidget);
52+
});
53+
});
54+
}

0 commit comments

Comments
 (0)