Modeling Some Adjustments
First of all, since every object has an id
property, I created the BaseModel
class.
class BaseModel {
String? id;
}
And I separated it into a form of text and media in the form of videos/photos that basically recall memories, allowing them to be inherited from the Memory
class in common.
import 'base.model.dart';
class Memory extends BaseModel {
final String memo;
final DateTime createdAt;
Memory({required this.memo, required this.createdAt});
}
class MediaMemory extends Memory {
final String url;
final String location;
MediaMemory({
required this.url,
required this.location,
required super.memo,
required super.createdAt,
});
}
class WrittenMemory extends Memory {
final String content;
WrittenMemory({
required this.content,
required super.memo,
required super.createdAt,
});
}
Detailed Page for Each Memory
I worked on separating the routes in this way, basically branching according to the type of memories to move to different layout screens.
GoRoute(
path: '/lost_person/:lost_person_id',
builder: (context, state) {
final lostPersonId = state.pathParameters['lost_person_id']!;
return LostPersonDetailScreen(lostPersonId: lostPersonId);
},
routes: [
GoRoute(
path: '/memories',
builder: (context, state) {
final lostPersonId = state.pathParameters['lost_person_id']!;
return MemoryDetailScreen(lostPersonId: lostPersonId);
},
),
GoRoute(
path: '/item/:item_id',
builder: (context, state) {
final itemId = state.pathParameters['item_id']!;
final itemType = state.uri.queryParameters['item_type'] ?? '';
switch (itemType) {
case 'written':
return WrittenMemoryDetailPage(itemId: itemId);
default:
return MediaMemoryDetailPage(itemId: itemId);
}
},
),
],
),
The core of this is to receive the type of each memory via state.uri.queryParameters
and move to the corresponding layout screen. When moving, we apply a URL of this form.
context.push('/lost_person/1/item/1?item_type=media');
The detailed screen displaying photos or videos has this layout.

The detailed screen displaying text has this layout.

Additional Actions
The additional action is simple; just display a modal on the pre-made FAB.
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () => showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: const Icon(Icons.photo),
title: const Text('Upload Photo'),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
leading: const Icon(Icons.videocam),
title: const Text('Upload Video'),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
leading: const Icon(Icons.contact_page_outlined),
title: const Text('Upload a Written Memory'),
onTap: () {
Navigator.pop(context);
},
),
],
),
);
},
),
),
Personally, I think a BottomSheet
is neat.

It is still a long way to go, but somehow it seems I have managed to establish the layout related to the core functionalities of the screen. I plan to refine the screen a little more before adding server actions to finalize it.