feat(app): add manual entry and sharing flows

This commit is contained in:
JiWoong Sul
2025-11-19 16:36:39 +09:00
parent 5ade584370
commit 947fe59486
110 changed files with 5937 additions and 3781 deletions

View File

@@ -26,7 +26,7 @@ class CategorySelector extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final categoriesAsync = ref.watch(categoriesProvider);
return categoriesAsync.when(
data: (categories) {
return SizedBox(
@@ -39,7 +39,9 @@ class CategorySelector extends ConsumerWidget {
context: context,
label: '전체',
icon: Icons.restaurant_menu,
color: isDark ? AppColors.darkPrimary : AppColors.lightPrimary,
color: isDark
? AppColors.darkPrimary
: AppColors.lightPrimary,
isSelected: selectedCategory == null,
onTap: () => onCategorySelected(null),
),
@@ -49,7 +51,7 @@ class CategorySelector extends ConsumerWidget {
final isSelected = multiSelect
? selectedCategories?.contains(category) ?? false
: selectedCategory == category;
return Padding(
padding: const EdgeInsets.only(right: 8),
child: _buildCategoryChip(
@@ -74,30 +76,26 @@ class CategorySelector extends ConsumerWidget {
},
loading: () => const SizedBox(
height: 50,
child: Center(
child: CircularProgressIndicator(),
),
child: Center(child: CircularProgressIndicator()),
),
error: (error, stack) => const SizedBox(
height: 50,
child: Center(
child: Text('카테고리를 불러올 수 없습니다'),
),
child: Center(child: Text('카테고리를 불러올 수 없습니다')),
),
);
}
void _handleMultiSelect(String category) {
if (onMultipleSelected == null || selectedCategories == null) return;
final List<String> updatedCategories = List.from(selectedCategories!);
if (updatedCategories.contains(category)) {
updatedCategories.remove(category);
} else {
updatedCategories.add(category);
}
onMultipleSelected!(updatedCategories);
}
@@ -110,7 +108,7 @@ class CategorySelector extends ConsumerWidget {
required VoidCallback onTap,
}) {
final isDark = Theme.of(context).brightness == Brightness.dark;
return Material(
color: Colors.transparent,
child: InkWell(
@@ -120,11 +118,11 @@ class CategorySelector extends ConsumerWidget {
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: isSelected
color: isSelected
? color.withOpacity(0.2)
: isDark
? AppColors.darkSurface
: AppColors.lightBackground,
: isDark
? AppColors.darkSurface
: AppColors.lightBackground,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isSelected ? color : Colors.transparent,
@@ -137,21 +135,21 @@ class CategorySelector extends ConsumerWidget {
Icon(
icon,
size: 20,
color: isSelected
? color
: isDark
? AppColors.darkTextSecondary
: AppColors.lightTextSecondary,
color: isSelected
? color
: isDark
? AppColors.darkTextSecondary
: AppColors.lightTextSecondary,
),
const SizedBox(width: 6),
Text(
label,
style: TextStyle(
color: isSelected
? color
: isDark
? AppColors.darkText
: AppColors.lightText,
color: isSelected
? color
: isDark
? AppColors.darkText
: AppColors.lightText,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
),
),
@@ -180,7 +178,7 @@ class CategorySelectionDialog extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final categoriesAsync = ref.watch(categoriesProvider);
return AlertDialog(
backgroundColor: isDark ? AppColors.darkSurface : AppColors.lightSurface,
title: Column(
@@ -193,7 +191,9 @@ class CategorySelectionDialog extends ConsumerWidget {
subtitle!,
style: TextStyle(
fontSize: 14,
color: isDark ? AppColors.darkTextSecondary : AppColors.lightTextSecondary,
color: isDark
? AppColors.darkTextSecondary
: AppColors.lightTextSecondary,
),
),
],
@@ -214,12 +214,14 @@ class CategorySelectionDialog extends ConsumerWidget {
itemBuilder: (context, index) {
final category = categories[index];
final isSelected = selectedCategories.contains(category);
return _CategoryGridItem(
category: category,
isSelected: isSelected,
onTap: () {
final updatedCategories = List<String>.from(selectedCategories);
final updatedCategories = List<String>.from(
selectedCategories,
);
if (isSelected) {
updatedCategories.remove(category);
} else {
@@ -231,12 +233,9 @@ class CategorySelectionDialog extends ConsumerWidget {
},
),
),
loading: () => const Center(
child: CircularProgressIndicator(),
),
error: (error, stack) => Center(
child: Text('카테고리를 불러올 수 없습니다: $error'),
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stack) =>
Center(child: Text('카테고리를 불러올 수 없습니다: $error')),
),
actions: [
TextButton(
@@ -244,7 +243,9 @@ class CategorySelectionDialog extends ConsumerWidget {
child: Text(
'취소',
style: TextStyle(
color: isDark ? AppColors.darkTextSecondary : AppColors.lightTextSecondary,
color: isDark
? AppColors.darkTextSecondary
: AppColors.lightTextSecondary,
),
),
),
@@ -274,7 +275,7 @@ class _CategoryGridItem extends StatelessWidget {
final color = CategoryMapper.getColor(category);
final icon = CategoryMapper.getIcon(category);
final displayName = CategoryMapper.getDisplayName(category);
return Material(
color: Colors.transparent,
child: InkWell(
@@ -284,11 +285,11 @@ class _CategoryGridItem extends StatelessWidget {
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: isSelected
color: isSelected
? color.withOpacity(0.2)
: isDark
? AppColors.darkCard
: AppColors.lightCard,
: isDark
? AppColors.darkCard
: AppColors.lightCard,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isSelected ? color : Colors.transparent,
@@ -301,22 +302,22 @@ class _CategoryGridItem extends StatelessWidget {
Icon(
icon,
size: 28,
color: isSelected
? color
: isDark
? AppColors.darkTextSecondary
: AppColors.lightTextSecondary,
color: isSelected
? color
: isDark
? AppColors.darkTextSecondary
: AppColors.lightTextSecondary,
),
const SizedBox(height: 4),
Text(
displayName,
style: TextStyle(
fontSize: 12,
color: isSelected
? color
: isDark
? AppColors.darkText
: AppColors.lightText,
color: isSelected
? color
: isDark
? AppColors.darkText
: AppColors.lightText,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
),
textAlign: TextAlign.center,
@@ -329,4 +330,4 @@ class _CategoryGridItem extends StatelessWidget {
),
);
}
}
}