Skip to content

Commit 633349d

Browse files
committed
feat: Add tag showcase view
1 parent 0d0f76c commit 633349d

File tree

4 files changed

+177
-81
lines changed

4 files changed

+177
-81
lines changed

lib/l10n/app_en.arb

+6
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,12 @@
347347
"settingsTagsTypePerson": "PERSON",
348348
"settingsTagsTypeStory": "STORY",
349349
"settingsTagsTypeTag": "TAG",
350+
"settingsTagsDefinitionTitle": "Tag Definition",
351+
"settingsTagsShowCaseNameTooltip": "Enter a clear and relevant name for the tag. Keep it short and descriptive so you can easily categorize your habits Examples: \"Health\", \"Productivity\", \"Mindfulness\".",
352+
"settingsTagsShowCasePrivateTooltip": "Enable this option to make the tag private. Private tags are only visible to you and won't be shared with others.",
353+
"settingsTagsShowCaseHideTooltip": "Enable this option to hide this tag from suggestions. Use it for tags that are personal or not commonly needed.",
354+
"settingsTagsShowCaseTypeTooltip": "Select the type of tag to categorize it properly: \n[Tag]-> General categories like 'Health' or 'Productivity'. \n[Person]-> Use for tagging specific individuals. \n[Story]-> Attach tags to stories for better organization.",
355+
"settingsTagsShowCaseDeleteTooltip": "Remove this tag permanently. This action cannot be undone.",
350356
"settingsThemingAutomatic": "Automatic",
351357
"settingsThemingDark": "Dark Appearance",
352358
"settingsThemingLight": "Light Appearance",

lib/pages/settings/tags/create_tag_page.dart

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:lotti/pages/empty_scaffold.dart';
55
import 'package:lotti/pages/settings/tags/tag_edit_page.dart';
66
import 'package:lotti/services/tags_service.dart';
77
import 'package:lotti/utils/file_utils.dart';
8+
import 'package:showcaseview/showcaseview.dart';
89

910
class CreateTagPage extends StatefulWidget {
1011
const CreateTagPage({
@@ -66,9 +67,11 @@ class _CreateTagPageState extends State<CreateTagPage> {
6667
if (_tagEntity == null) {
6768
return const EmptyScaffoldWithTitle('');
6869
}
69-
return TagEditPage(
70-
tagEntity: _tagEntity!,
71-
newTag: true,
70+
return ShowCaseWidget(
71+
builder: (context) => TagEditPage(
72+
tagEntity: _tagEntity!,
73+
newTag: true,
74+
),
7275
);
7376
}
7477
}

lib/pages/settings/tags/tag_edit_page.dart

+146-64
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_form_builder/flutter_form_builder.dart';
33
import 'package:lotti/classes/tag_type_definitions.dart';
4+
import 'package:lotti/features/manual/widget/showcase_text_style.dart';
5+
import 'package:lotti/features/manual/widget/showcase_with_widget.dart';
46
import 'package:lotti/features/tags/repository/tags_repository.dart';
57
import 'package:lotti/get_it.dart';
68
import 'package:lotti/l10n/app_localizations_context.dart';
@@ -14,6 +16,7 @@ import 'package:lotti/widgets/app_bar/title_app_bar.dart';
1416
import 'package:lotti/widgets/settings/entity_detail_card.dart';
1517
import 'package:lotti/widgets/settings/form/form_switch.dart';
1618
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
19+
import 'package:showcaseview/showcaseview.dart';
1720

1821
class TagEditPage extends StatefulWidget {
1922
const TagEditPage({
@@ -32,6 +35,11 @@ class TagEditPage extends StatefulWidget {
3235
}
3336

3437
class _TagEditPageState extends State<TagEditPage> {
38+
final _tagNameKey = GlobalKey();
39+
final _tagPrivateKey = GlobalKey();
40+
final _tagHideKey = GlobalKey();
41+
final _tagTypeTagKey = GlobalKey();
42+
final _tagDeleteKey = GlobalKey();
3543
final PersistenceLogic persistenceLogic = getIt<PersistenceLogic>();
3644
final _formKey = GlobalKey<FormBuilderState>();
3745
bool dirty = false;
@@ -104,7 +112,9 @@ class _TagEditPageState extends State<TagEditPage> {
104112
);
105113
}
106114

107-
await TagsRepository.upsertTagEntity(newTagEntity);
115+
await TagsRepository.upsertTagEntity(
116+
newTagEntity,
117+
);
108118
maybePop();
109119

110120
setState(() {
@@ -117,18 +127,42 @@ class _TagEditPageState extends State<TagEditPage> {
117127
final errorColor = context.colorScheme.error;
118128

119129
return Scaffold(
120-
appBar: TitleAppBar(
121-
title: '',
130+
appBar: TitleWidgetAppBar(
131+
title: Row(
132+
children: [
133+
const Text(
134+
'Tags Definition',
135+
),
136+
IconButton(
137+
onPressed: () {
138+
ShowCaseWidget.of(context).startShowCase([
139+
_tagNameKey,
140+
_tagPrivateKey,
141+
_tagHideKey,
142+
_tagTypeTagKey,
143+
_tagDeleteKey,
144+
]);
145+
},
146+
icon: const Icon(
147+
Icons.info_outline_rounded,
148+
),
149+
),
150+
],
151+
),
122152
actions: [
123153
if (dirty)
124154
TextButton(
125155
key: const Key('tag_save'),
126156
onPressed: onSavePressed,
127157
child: Padding(
128-
padding: const EdgeInsets.symmetric(horizontal: 12),
158+
padding: const EdgeInsets.symmetric(
159+
horizontal: 12,
160+
),
129161
child: Text(
130162
context.messages.settingsTagsSaveLabel,
131-
style: saveButtonStyle(Theme.of(context)),
163+
style: saveButtonStyle(
164+
Theme.of(context),
165+
),
132166
),
133167
),
134168
),
@@ -147,60 +181,96 @@ class _TagEditPageState extends State<TagEditPage> {
147181
},
148182
child: Column(
149183
children: <Widget>[
150-
FormTextField(
151-
initialValue: widget.tagEntity.tag,
152-
labelText: context.messages.settingsTagsTagName,
153-
name: 'tag',
154-
key: const Key('tag_name_field'),
155-
large: true,
184+
ShowcaseWithWidget(
185+
showcaseKey: _tagNameKey,
186+
startNav: true,
187+
description: ShowcaseTextStyle(
188+
descriptionText:
189+
context.messages.settingsTagsShowCaseNameTooltip,
190+
),
191+
child: FormTextField(
192+
initialValue: widget.tagEntity.tag,
193+
labelText: context.messages.settingsTagsTagName,
194+
name: 'tag',
195+
key: const Key('tag_name_field'),
196+
large: true,
197+
),
156198
),
157199
inputSpacer,
158-
FormSwitch(
159-
name: 'private',
160-
initialValue: widget.tagEntity.private,
161-
title: context.messages.settingsTagsPrivateLabel,
162-
activeColor: errorColor,
163-
),
164-
FormSwitch(
165-
name: 'inactive',
166-
initialValue: widget.tagEntity.inactive,
167-
title: context.messages.settingsTagsHideLabel,
168-
activeColor: errorColor,
200+
ShowcaseWithWidget(
201+
showcaseKey: _tagPrivateKey,
202+
description: ShowcaseTextStyle(
203+
descriptionText:
204+
context.messages.settingsTagsShowCasePrivateTooltip,
205+
),
206+
child: FormSwitch(
207+
name: 'private',
208+
initialValue: widget.tagEntity.private,
209+
title: context.messages.settingsTagsPrivateLabel,
210+
activeColor: errorColor,
211+
),
169212
),
170-
inputSpacer,
171-
FormBuilderChoiceChip<String>(
172-
name: 'type',
173-
initialValue: widget.tagEntity.map(
174-
genericTag: (_) => context.messages.settingsTagsTypeTag,
175-
personTag: (_) => context.messages.settingsTagsTypePerson,
176-
storyTag: (_) =>
177-
context.messages.settingsTagsTypeStory, // 'STORY',
213+
ShowcaseWithWidget(
214+
showcaseKey: _tagHideKey,
215+
description: ShowcaseTextStyle(
216+
descriptionText:
217+
context.messages.settingsTagsShowCaseHideTooltip,
178218
),
179-
decoration: inputDecoration(
180-
labelText: context.messages.settingsTagsTypeLabel,
181-
themeData: Theme.of(context),
219+
child: FormSwitch(
220+
name: 'inactive',
221+
initialValue: widget.tagEntity.inactive,
222+
title: context.messages.settingsTagsHideLabel,
223+
activeColor: errorColor,
182224
),
183-
selectedColor: widget.tagEntity.map(
184-
genericTag: getTagColor,
185-
personTag: getTagColor,
186-
storyTag: getTagColor,
225+
),
226+
inputSpacer,
227+
ShowcaseWithWidget(
228+
showcaseKey: _tagTypeTagKey,
229+
description: ShowcaseTextStyle(
230+
descriptionText:
231+
context.messages.settingsTagsShowCaseTypeTooltip,
187232
),
188-
runSpacing: 4,
189-
spacing: 4,
190-
options: [
191-
FormBuilderChipOption<String>(
192-
value: 'TAG',
193-
child: Text(context.messages.settingsTagsTypeTag),
233+
child: FormBuilderChoiceChip<String>(
234+
name: 'type',
235+
initialValue: widget.tagEntity.map(
236+
genericTag: (_) => context.messages.settingsTagsTypeTag,
237+
personTag: (_) =>
238+
context.messages.settingsTagsTypePerson,
239+
storyTag: (_) =>
240+
context.messages.settingsTagsTypeStory, // 'STORY',
194241
),
195-
FormBuilderChipOption<String>(
196-
value: 'PERSON',
197-
child: Text(context.messages.settingsTagsTypePerson),
242+
decoration: inputDecoration(
243+
labelText: context.messages.settingsTagsTypeLabel,
244+
themeData: Theme.of(context),
198245
),
199-
FormBuilderChipOption<String>(
200-
value: 'STORY',
201-
child: Text(context.messages.settingsTagsTypeStory),
246+
selectedColor: widget.tagEntity.map(
247+
genericTag: getTagColor,
248+
personTag: getTagColor,
249+
storyTag: getTagColor,
202250
),
203-
],
251+
runSpacing: 4,
252+
spacing: 4,
253+
options: [
254+
FormBuilderChipOption<String>(
255+
value: 'TAG',
256+
child: Text(
257+
context.messages.settingsTagsTypeTag,
258+
),
259+
),
260+
FormBuilderChipOption<String>(
261+
value: 'PERSON',
262+
child: Text(
263+
context.messages.settingsTagsTypePerson,
264+
),
265+
),
266+
FormBuilderChipOption<String>(
267+
value: 'STORY',
268+
child: Text(
269+
context.messages.settingsTagsTypeStory,
270+
),
271+
),
272+
],
273+
),
204274
),
205275
],
206276
),
@@ -211,19 +281,29 @@ class _TagEditPageState extends State<TagEditPage> {
211281
mainAxisAlignment: MainAxisAlignment.spaceBetween,
212282
children: [
213283
const Spacer(),
214-
IconButton(
215-
icon: Icon(MdiIcons.trashCanOutline),
216-
iconSize: 24,
217-
tooltip: context.messages.settingsTagsDeleteTooltip,
218-
color: context.colorScheme.outline,
219-
onPressed: () {
220-
TagsRepository.upsertTagEntity(
221-
widget.tagEntity.copyWith(
222-
deletedAt: DateTime.now(),
223-
),
224-
);
225-
Navigator.of(context).maybePop();
226-
},
284+
ShowcaseWithWidget(
285+
showcaseKey: _tagDeleteKey,
286+
endNav: true,
287+
description: ShowcaseTextStyle(
288+
descriptionText:
289+
context.messages.settingsTagsShowCaseDeleteTooltip,
290+
),
291+
child: IconButton(
292+
icon: Icon(
293+
MdiIcons.trashCanOutline,
294+
),
295+
iconSize: 24,
296+
tooltip: context.messages.settingsTagsDeleteTooltip,
297+
color: context.colorScheme.outline,
298+
onPressed: () {
299+
TagsRepository.upsertTagEntity(
300+
widget.tagEntity.copyWith(
301+
deletedAt: DateTime.now(),
302+
),
303+
);
304+
Navigator.of(context).maybePop();
305+
},
306+
),
227307
),
228308
],
229309
),
@@ -252,6 +332,8 @@ class EditExistingTagPage extends StatelessWidget {
252332
return const EmptyScaffoldWithTitle('');
253333
}
254334

255-
return TagEditPage(tagEntity: tagEntity);
335+
return ShowCaseWidget(
336+
builder: (context) => TagEditPage(tagEntity: tagEntity),
337+
);
256338
}
257339
}

test/pages/settings/tags/tag_edit_page_test.dart

+19-14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:lotti/logic/persistence_logic.dart';
77
import 'package:lotti/pages/settings/tags/tag_edit_page.dart';
88
import 'package:lotti/services/tags_service.dart';
99
import 'package:mocktail/mocktail.dart';
10+
import 'package:showcaseview/showcaseview.dart';
1011

1112
import '../../../mocks/mocks.dart';
1213
import '../../../mocks/sync_config_test_mocks.dart';
@@ -52,13 +53,15 @@ void main() {
5253
(tester) async {
5354
await tester.pumpWidget(
5455
makeTestableWidget(
55-
ConstrainedBox(
56-
constraints: const BoxConstraints(
57-
maxHeight: 1000,
58-
maxWidth: 1000,
59-
),
60-
child: TagEditPage(
61-
tagEntity: testTag1,
56+
ShowCaseWidget(
57+
builder: (context) => ConstrainedBox(
58+
constraints: const BoxConstraints(
59+
maxHeight: 1000,
60+
maxWidth: 1000,
61+
),
62+
child: TagEditPage(
63+
tagEntity: testTag1,
64+
),
6265
),
6366
),
6467
),
@@ -92,13 +95,15 @@ void main() {
9295
(tester) async {
9396
await tester.pumpWidget(
9497
makeTestableWidget(
95-
ConstrainedBox(
96-
constraints: const BoxConstraints(
97-
maxHeight: 1000,
98-
maxWidth: 1000,
99-
),
100-
child: TagEditPage(
101-
tagEntity: testStoryTag1,
98+
ShowCaseWidget(
99+
builder: (context) => ConstrainedBox(
100+
constraints: const BoxConstraints(
101+
maxHeight: 1000,
102+
maxWidth: 1000,
103+
),
104+
child: TagEditPage(
105+
tagEntity: testStoryTag1,
106+
),
102107
),
103108
),
104109
),

0 commit comments

Comments
 (0)