Skip to content

Commit ae62112

Browse files
author
davidwei
committed
more improvement on FAB based on review feedback
1 parent 3374035 commit ae62112

8 files changed

Lines changed: 226 additions & 310 deletions

File tree

lib/screens/components/create_note_fab.dart

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,49 @@
1-
21
import 'package:flutter/material.dart';
2+
import 'package:happy_notes/entities/note.dart';
33
import 'package:happy_notes/screens/components/shared_fab.dart';
4+
import 'package:happy_notes/screens/new_note/new_note.dart';
5+
import 'package:happy_notes/utils/util.dart';
46

5-
/// Floating Action Button for creating notes with visibility indicator
6-
///
7-
/// Displays a FAB with color-coded background and icon:
8-
/// - Public notes: Primary theme color with blue globe icon
9-
/// - Private notes: Light grey with dark grey lock icon
7+
/// Floating Action Button for creating notes.
108
class CreateNoteFAB extends StatelessWidget {
119
final bool isPrivate;
12-
final VoidCallback onPressed;
10+
final String heroTag;
11+
final String successMessage;
12+
final VoidCallback? onPressed;
1313

1414
const CreateNoteFAB({
1515
super.key,
1616
required this.isPrivate,
17-
required this.onPressed,
17+
required this.heroTag,
18+
this.successMessage = 'Note saved successfully.',
19+
this.onPressed,
1820
});
1921

22+
Future<void> _handleCreateNote(BuildContext context) async {
23+
final scaffoldMessenger = ScaffoldMessenger.of(context);
24+
// NewNote pops with Note on successful save, and null on cancel/back.
25+
final Note? savedNote = await Navigator.push<Note>(
26+
context,
27+
MaterialPageRoute(
28+
builder: (context) => NewNote(isPrivate: isPrivate),
29+
),
30+
);
31+
if (savedNote != null) {
32+
Util.showInfo(scaffoldMessenger, successMessage);
33+
}
34+
}
35+
2036
@override
2137
Widget build(BuildContext context) {
22-
// Wrapper around SharedFab to preserve external API while improving visuals
23-
return Positioned(
24-
right: 16,
25-
bottom: 16,
26-
child: Opacity(
27-
opacity: 0.95,
28-
child: SharedFab(
29-
icon: Icons.edit_outlined,
30-
isPrivate: isPrivate,
31-
busy: false,
32-
mini: false,
33-
onPressed: onPressed,
34-
heroTag: 'fab_home',
35-
),
38+
return Opacity(
39+
opacity: 0.85,
40+
child: SharedFab(
41+
icon: Icons.edit_outlined,
42+
isPrivate: isPrivate,
43+
busy: false,
44+
mini: false,
45+
onPressed: onPressed ?? () => _handleCreateNote(context),
46+
heroTag: heroTag,
3647
),
3748
);
3849
}

lib/screens/home_page/home_page.dart

Lines changed: 47 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import '../../dependency_injection.dart';
1717
import '../account/user_session.dart';
1818
import '../new_note/new_note.dart';
1919
import '../components/controllers/tag_cloud_controller.dart';
20-
import 'package:happy_notes/screens/components/shared_fab.dart';
20+
import 'package:happy_notes/screens/components/create_note_fab.dart';
2121
import '../components/tappable_app_bar_title.dart';
2222

2323
class HomePage extends StatefulWidget {
@@ -65,8 +65,9 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
6565
_handleAppResumed();
6666
}
6767

68-
_wasInBackground =
69-
(state == AppLifecycleState.paused || state == AppLifecycleState.hidden || state == AppLifecycleState.inactive);
68+
_wasInBackground = (state == AppLifecycleState.paused ||
69+
state == AppLifecycleState.hidden ||
70+
state == AppLifecycleState.inactive);
7071
}
7172

7273
void _handleAppResumed() {
@@ -76,7 +77,9 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
7677
final notesProvider = Provider.of<NotesProvider>(context, listen: false);
7778

7879
// Auto-reload if logged in but notes list is empty (iOS Safari memory management fix)
79-
if (authProvider.isAuthenticated && notesProvider.notes.isEmpty && !notesProvider.isLoadingList) {
80+
if (authProvider.isAuthenticated &&
81+
notesProvider.notes.isEmpty &&
82+
!notesProvider.isLoadingList) {
8083
notesProvider.loadPage(1);
8184
}
8285
}
@@ -137,58 +140,49 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
137140
FloatingPagination(
138141
currentPage: notesProvider.currentPage,
139142
totalPages: notesProvider.totalPages,
140-
navigateToPage: (pageNumber) => navigateToPage(pageNumber),
143+
navigateToPage: (pageNumber) =>
144+
navigateToPage(pageNumber),
141145
),
142146
],
143147
);
144148
},
145149
),
146-
Positioned(
147-
right: 16,
148-
bottom: 16,
149-
child: Opacity(
150-
opacity: 0.85,
151-
child: SharedFab(
152-
icon: Icons.edit_outlined,
150+
],
151+
),
152+
floatingActionButton: CreateNoteFAB(
153+
isPrivate: AppConfig.privateNoteOnlyIsEnabled,
154+
heroTag: 'fab_home',
155+
onPressed: () async {
156+
final scaffoldMessenger = ScaffoldMessenger.of(context);
157+
final provider = Provider.of<NotesProvider>(context, listen: false);
158+
final Note? savedNote = await Navigator.push<Note>(
159+
context,
160+
MaterialPageRoute(
161+
builder: (context) => NewNote(
153162
isPrivate: AppConfig.privateNoteOnlyIsEnabled,
154-
busy: false,
155-
mini: false,
156-
onPressed: () async {
157-
final scaffoldMessenger = ScaffoldMessenger.of(context);
158-
final provider = Provider.of<NotesProvider>(context, listen: false);
159-
final Note? savedNote = await Navigator.push<Note>(
160-
context,
161-
MaterialPageRoute(
162-
builder: (context) => NewNote(
163-
isPrivate: AppConfig.privateNoteOnlyIsEnabled,
164-
),
165-
),
166-
);
167-
if (!mounted) return;
168-
if (savedNote != null) {
169-
if (provider.currentPage == 1) {
170-
if (_scrollController.hasClients && _scrollController.offset > 0) {
171-
_scrollController.animateTo(
172-
0,
173-
duration: const Duration(milliseconds: 300),
174-
curve: Curves.easeInOut,
175-
);
176-
}
177-
} else {
178-
Util.showInfo(scaffoldMessenger, 'Note saved successfully.');
179-
}
180-
}
181-
},
182163
),
183164
),
184-
),
185-
],
165+
);
166+
if (!mounted) return;
167+
if (savedNote != null) {
168+
if (provider.currentPage == 1) {
169+
if (_scrollController.hasClients &&
170+
_scrollController.offset > 0) {
171+
_scrollController.animateTo(
172+
0,
173+
duration: const Duration(milliseconds: 300),
174+
curve: Curves.easeInOut,
175+
);
176+
}
177+
} else {
178+
Util.showInfo(scaffoldMessenger, 'Note saved successfully.');
179+
}
180+
}
181+
},
186182
),
187183
);
188184
}
189185

190-
191-
192186
Widget _buildBody(NotesProvider notesProvider) {
193187
if (notesProvider.isLoadingList) {
194188
return const Center(child: CircularProgressIndicator());
@@ -292,21 +286,25 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
292286
final saved = await Navigator.push<bool>(
293287
context,
294288
MaterialPageRoute(
295-
builder: (context) => NoteDetail(note: note, enterEditing: note.userId == UserSession().id),
289+
builder: (context) => NoteDetail(
290+
note: note,
291+
enterEditing: note.userId == UserSession().id),
296292
),
297293
);
298294
_handleEditResult(saved);
299295
},
300296
onDelete: (note) async {
301297
final result = await notesProvider.deleteNote(note.id);
302298
if (!result.isSuccess && mounted) {
303-
Util.showError(ScaffoldMessenger.of(context), result.errorMessage!);
299+
Util.showError(
300+
ScaffoldMessenger.of(context), result.errorMessage!);
304301
}
305302
},
306303
),
307304
noteCallbacks: NoteListCallbacks(
308305
onRefresh: refreshPage,
309-
onTagTap: (note, tag) => NavigationHelper.onTagTap(context, note, tag),
306+
onTagTap: (note, tag) =>
307+
NavigationHelper.onTagTap(context, note, tag),
310308
onDateHeaderTap: (date) => Navigator.push(
311309
context,
312310
MaterialPageRoute(
@@ -315,7 +313,8 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
315313
),
316314
),
317315
config: const ListItemConfig(
318-
showDate: false, // Don't show individual dates when showDateHeader is true
316+
showDate:
317+
false, // Don't show individual dates when showDateHeader is true
319318
showAuthor: false,
320319
enableDismiss: true,
321320
),

lib/screens/memories/memories.dart

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import 'package:flutter/material.dart';
22
import 'package:provider/provider.dart';
33
import '../../app_config.dart';
4-
import '../../entities/note.dart';
5-
import '../../utils/util.dart';
6-
import '../components/shared_fab.dart';
7-
import '../new_note/new_note.dart';
4+
import '../components/create_note_fab.dart';
85
import '../components/memory_list.dart';
96
import '../account/user_session.dart';
107
import '../../utils/navigation_helper.dart';
@@ -68,44 +65,14 @@ class MemoriesState extends State<Memories> with RouteAware {
6865
},
6966
),
7067
),
71-
body: Stack(
72-
children: [
73-
_buildBody(),
74-
Positioned(
75-
right: 16,
76-
bottom: 16,
77-
child: Opacity(
78-
opacity: 0.85,
79-
child: SharedFab(
80-
icon: Icons.edit_outlined,
81-
isPrivate: AppConfig.privateNoteOnlyIsEnabled,
82-
busy: false,
83-
mini: false,
84-
heroTag: 'fab_memories',
85-
onPressed: () async {
86-
final scaffoldMessenger = ScaffoldMessenger.of(context);
87-
final Note? savedNote = await Navigator.push<Note>(
88-
context,
89-
MaterialPageRoute(
90-
builder: (context) => NewNote(
91-
isPrivate: AppConfig.privateNoteOnlyIsEnabled,
92-
),
93-
),
94-
);
95-
if (!mounted) return;
96-
if (savedNote != null) {
97-
Util.showInfo(scaffoldMessenger, 'Note saved successfully.');
98-
}
99-
},
100-
),
101-
),
102-
),
103-
],
68+
body: _buildBody(),
69+
floatingActionButton: CreateNoteFAB(
70+
isPrivate: AppConfig.privateNoteOnlyIsEnabled,
71+
heroTag: 'fab_memories',
10472
),
10573
);
10674
}
10775

108-
10976
Widget _buildBody() {
11077
return Consumer<MemoriesProvider>(
11178
builder: (context, memoriesProvider, child) {

0 commit comments

Comments
 (0)