From 2944b6d9b5f6fa0ee22b8af1dd33eb168ca87208 Mon Sep 17 00:00:00 2001 From: "kihong.kim" Date: Sat, 24 Jan 2026 23:15:54 +0900 Subject: [PATCH] Tweak bible font and avatar image layout --- docker-compose.yml | 3 + .../lib/screens/admin/admin_screen.dart | 73 ++++++++++++++----- .../lib/widgets/bible_verse_widget.dart | 2 +- flutter_app/lib/widgets/todo_list_widget.dart | 30 ++++++-- 4 files changed, 81 insertions(+), 27 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 9030f22..571c28f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,8 @@ services: context: ./backend ports: - "4000:4000" + volumes: + - backend-uploads:/app/uploads environment: PORT: "4000" MONGODB_URI: "mongodb://mongo:27017/google-tv-dashboard" @@ -25,3 +27,4 @@ services: volumes: mongo-data: + backend-uploads: diff --git a/flutter_app/lib/screens/admin/admin_screen.dart b/flutter_app/lib/screens/admin/admin_screen.dart index 271c93c..0b824e0 100644 --- a/flutter_app/lib/screens/admin/admin_screen.dart +++ b/flutter_app/lib/screens/admin/admin_screen.dart @@ -114,17 +114,27 @@ class _FamilyManagerTabState extends State { return ListTile( leading: CircleAvatar( backgroundColor: memberColor, - backgroundImage: member.iconUrl.isNotEmpty - ? NetworkImage(member.iconUrl) - : null, - child: member.iconUrl.isEmpty - ? Text( + child: member.iconUrl.isNotEmpty + ? ClipOval( + child: Image.network( + member.iconUrl, + width: 40, + height: 40, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) => Text( + member.name.isNotEmpty + ? member.name[0].toUpperCase() + : '?', + style: const TextStyle(fontSize: 20), + ), + ), + ) + : Text( member.name.isNotEmpty ? member.name[0].toUpperCase() : '?', style: const TextStyle(fontSize: 20), - ) - : null, + ), ), title: Text(member.name), subtitle: Text('Order: ${member.order}'), @@ -185,12 +195,16 @@ class _FamilyManagerTabState extends State { children: [ CircleAvatar( backgroundColor: selectedColor, - backgroundImage: selectedIconBytes != null - ? MemoryImage(selectedIconBytes!) - : null, - child: selectedIconBytes == null - ? const Icon(Icons.person, color: Colors.white) - : null, + child: selectedIconBytes != null + ? ClipOval( + child: Image.memory( + selectedIconBytes!, + width: 40, + height: 40, + fit: BoxFit.cover, + ), + ) + : const Icon(Icons.person, color: Colors.white), ), const SizedBox(width: 16), ElevatedButton.icon( @@ -377,12 +391,33 @@ class _FamilyManagerTabState extends State { children: [ CircleAvatar( backgroundColor: selectedColor, - backgroundImage: selectedIconBytes != null - ? MemoryImage(selectedIconBytes!) - : previewImage, - child: (selectedIconBytes == null && previewImage == null) - ? Text(member.name.isNotEmpty ? member.name[0] : '?') - : null, + child: selectedIconBytes != null + ? ClipOval( + child: Image.memory( + selectedIconBytes!, + width: 40, + height: 40, + fit: BoxFit.cover, + ), + ) + : (previewImage != null + ? ClipOval( + child: Image( + image: previewImage!, + width: 40, + height: 40, + fit: BoxFit.cover, + errorBuilder: + (context, error, stackTrace) => Text( + member.name.isNotEmpty + ? member.name[0] + : '?', + ), + ), + ) + : Text(member.name.isNotEmpty + ? member.name[0] + : '?')), ), const SizedBox(width: 16), ElevatedButton.icon( diff --git a/flutter_app/lib/widgets/bible_verse_widget.dart b/flutter_app/lib/widgets/bible_verse_widget.dart index 6f8c8d8..75114b4 100644 --- a/flutter_app/lib/widgets/bible_verse_widget.dart +++ b/flutter_app/lib/widgets/bible_verse_widget.dart @@ -60,7 +60,7 @@ class BibleVerseWidget extends StatelessWidget { Text( verse.text, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.bodyLarge?.copyWith( + style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Colors.white, height: 1.5, fontStyle: FontStyle.italic, diff --git a/flutter_app/lib/widgets/todo_list_widget.dart b/flutter_app/lib/widgets/todo_list_widget.dart index f238ff8..2be0e8f 100644 --- a/flutter_app/lib/widgets/todo_list_widget.dart +++ b/flutter_app/lib/widgets/todo_list_widget.dart @@ -129,11 +129,28 @@ class TodoListWidget extends StatelessWidget { contentPadding: EdgeInsets.zero, leading: CircleAvatar( backgroundColor: memberColor.withOpacity(0.2), - backgroundImage: member.iconUrl.isNotEmpty - ? NetworkImage(member.iconUrl) - : null, - child: member.iconUrl.isEmpty - ? (member.name.isNotEmpty + child: member.iconUrl.isNotEmpty + ? ClipOval( + child: Image.network( + member.iconUrl, + width: 40, + height: 40, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Text( + member.name.isNotEmpty + ? member.name[0].toUpperCase() + : '?', + style: TextStyle( + color: memberColor, + fontWeight: FontWeight.bold, + fontSize: 20, + ), + ); + }, + ), + ) + : (member.name.isNotEmpty ? Text( member.name[0].toUpperCase(), style: TextStyle( @@ -145,8 +162,7 @@ class TodoListWidget extends StatelessWidget { : Icon( Icons.person, color: memberColor, - )) - : null, + )), ), title: Text( todo.title,