Replace the Inbox badge button in MonthHeader with a bottom-nav tab (hidden when notification parsing is disabled). Redirect /inbox → /home when parsing is off, register the Inbox shell branch unconditionally, and add a settings action to the Inbox screen. Move the parsing tile to the top of the profile screen so settings stay reachable when the tab is hidden. Add tests for the nav tab visibility and inbox routing, plus a release-install PowerShell helper that preserves app data. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
113 lines
3.4 KiB
Dart
113 lines
3.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:intl/intl.dart';
|
|
|
|
import '../../../../app/l10n/l10n.dart';
|
|
import '../../../../app/theme/app_colors.dart';
|
|
import '../state/selected_category_filter.dart';
|
|
|
|
class MonthHeader extends ConsumerWidget {
|
|
const MonthHeader({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final p = context.palette;
|
|
final l10n = context.l10n;
|
|
final locale = Localizations.localeOf(context).toString();
|
|
final month = ref.watch(selectedMonthProvider);
|
|
|
|
final now = DateTime.now();
|
|
final isCurrentMonth =
|
|
month.year == now.year && month.month == now.month;
|
|
|
|
final monthName = DateFormat.MMMM(locale).format(month);
|
|
final monthCap = '${monthName[0].toUpperCase()}${monthName.substring(1)}';
|
|
final title = '$monthCap ${month.year}';
|
|
|
|
return Padding(
|
|
padding: const EdgeInsets.fromLTRB(16, 14, 16, 8),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
l10n.budget,
|
|
style: TextStyle(
|
|
fontSize: 11,
|
|
color: p.ink2,
|
|
letterSpacing: 0.6,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
_NavButton(
|
|
icon: Icons.chevron_left,
|
|
color: p.ink2,
|
|
onTap: () =>
|
|
ref.read(selectedMonthProvider.notifier).previous(),
|
|
),
|
|
const SizedBox(width: 2),
|
|
Text(
|
|
title,
|
|
style: TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.w600,
|
|
color: p.ink,
|
|
),
|
|
),
|
|
if (!isCurrentMonth) ...[
|
|
const SizedBox(width: 2),
|
|
_NavButton(
|
|
icon: Icons.chevron_right,
|
|
color: p.ink2,
|
|
onTap: () =>
|
|
ref.read(selectedMonthProvider.notifier).next(),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
IconButton(
|
|
onPressed: () {},
|
|
padding: EdgeInsets.zero,
|
|
constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
|
|
icon: Icon(Icons.search, size: 20, color: p.ink2),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _NavButton extends StatelessWidget {
|
|
const _NavButton({
|
|
required this.icon,
|
|
required this.color,
|
|
required this.onTap,
|
|
});
|
|
|
|
final IconData icon;
|
|
final Color color;
|
|
final VoidCallback onTap;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GestureDetector(
|
|
onTap: onTap,
|
|
behavior: HitTestBehavior.opaque,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(2),
|
|
child: Icon(icon, size: 20, color: color),
|
|
),
|
|
);
|
|
}
|
|
}
|