多语言支持
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../l10n/app_localizations.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
import '../theme/app_text_styles.dart';
|
||||
import '../models/distraction_type.dart';
|
||||
@@ -76,11 +77,15 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
void _showBackgroundNotification() {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final minutes = _remainingSeconds ~/ 60;
|
||||
final seconds = _remainingSeconds % 60;
|
||||
final timeStr = '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
|
||||
_notificationService.showOngoingFocusNotification(
|
||||
remainingMinutes: minutes,
|
||||
remainingSeconds: seconds,
|
||||
title: l10n.notificationFocusInProgress,
|
||||
timeRemainingText: l10n.notificationRemaining(timeStr),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,11 +99,15 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
// Update background notification every 30 seconds when in background
|
||||
if (_isInBackground && _remainingSeconds > 0) {
|
||||
if (_remainingSeconds % 30 == 0) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final minutes = _remainingSeconds ~/ 60;
|
||||
final seconds = _remainingSeconds % 60;
|
||||
final timeStr = '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
|
||||
_notificationService.updateOngoingFocusNotification(
|
||||
remainingMinutes: minutes,
|
||||
remainingSeconds: seconds,
|
||||
title: l10n.notificationFocusInProgress,
|
||||
timeRemainingText: l10n.notificationRemaining(timeStr),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -118,10 +127,26 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
|
||||
_saveFocusSession(completed: true);
|
||||
|
||||
// Send completion notification
|
||||
if (!mounted) return;
|
||||
|
||||
// Send completion notification with localized text
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final minuteText = l10n.minutes(widget.durationMinutes);
|
||||
final notificationBody = _distractions.isEmpty
|
||||
? l10n.notificationFocusCompleteBodyNoDistractions(
|
||||
widget.durationMinutes,
|
||||
minuteText,
|
||||
)
|
||||
: l10n.notificationFocusCompleteBody(
|
||||
widget.durationMinutes,
|
||||
minuteText,
|
||||
);
|
||||
|
||||
await _notificationService.showFocusCompletedNotification(
|
||||
minutes: widget.durationMinutes,
|
||||
distractionCount: _distractions.length,
|
||||
title: l10n.notificationFocusCompleteTitle,
|
||||
body: notificationBody,
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
@@ -152,20 +177,22 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
void _stopEarly() {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final actualMinutes = ((widget.durationMinutes * 60 - _remainingSeconds) / 60).floor();
|
||||
final minuteText = actualMinutes == 1 ? l10n.minutes(1) : l10n.minutes(actualMinutes);
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Stop early?'),
|
||||
title: Text(l10n.stopEarly),
|
||||
content: Text(
|
||||
"That's totally fine — you still focused for $actualMinutes ${actualMinutes == 1 ? 'minute' : 'minutes'}!",
|
||||
l10n.stopEarlyMessage(actualMinutes, minuteText),
|
||||
style: AppTextStyles.bodyText,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('Keep going'),
|
||||
child: Text(l10n.keepGoing),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
@@ -184,7 +211,7 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('Yes, stop'),
|
||||
child: Text(l10n.yesStop),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -210,6 +237,16 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
void _showDistractionSheet() {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
// Map distraction types to translations
|
||||
final distractionOptions = [
|
||||
(type: DistractionType.phoneNotification, label: l10n.distractionPhoneNotification),
|
||||
(type: DistractionType.socialMedia, label: l10n.distractionSocialMedia),
|
||||
(type: DistractionType.thoughts, label: l10n.distractionThoughts),
|
||||
(type: DistractionType.other, label: l10n.distractionOther),
|
||||
];
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: AppColors.white,
|
||||
@@ -245,9 +282,9 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Title
|
||||
const Text(
|
||||
'What pulled you away?',
|
||||
style: TextStyle(
|
||||
Text(
|
||||
l10n.whatPulledYouAway,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Nunito',
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -257,24 +294,24 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Distraction options
|
||||
...DistractionType.all.map((type) {
|
||||
...distractionOptions.map((option) {
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: Text(
|
||||
DistractionType.getEmoji(type),
|
||||
DistractionType.getEmoji(option.type),
|
||||
style: const TextStyle(fontSize: 24),
|
||||
),
|
||||
title: Text(
|
||||
DistractionType.getDisplayName(type),
|
||||
option.label,
|
||||
style: AppTextStyles.bodyText,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
_recordDistraction(type);
|
||||
_recordDistraction(option.type);
|
||||
},
|
||||
),
|
||||
if (type != DistractionType.all.last)
|
||||
if (option != distractionOptions.last)
|
||||
const Divider(color: AppColors.divider),
|
||||
],
|
||||
);
|
||||
@@ -289,7 +326,7 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
Navigator.pop(context);
|
||||
_recordDistraction(null);
|
||||
},
|
||||
child: const Text('Skip this time'),
|
||||
child: Text(l10n.skipThisTime),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -302,6 +339,8 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
void _recordDistraction(String? type) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
setState(() {
|
||||
if (type != null) {
|
||||
_distractions.add(type);
|
||||
@@ -310,9 +349,9 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
|
||||
// Show encouragement toast
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text("It happens. Let's gently come back."),
|
||||
duration: Duration(seconds: 2),
|
||||
SnackBar(
|
||||
content: Text(l10n.distractionEncouragement),
|
||||
duration: const Duration(seconds: 2),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
@@ -326,6 +365,8 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.background,
|
||||
body: SafeArea(
|
||||
@@ -365,18 +406,18 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
'I got distracted',
|
||||
style: TextStyle(
|
||||
Text(
|
||||
l10n.iGotDistracted,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Nunito',
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
const Text(
|
||||
'🤚',
|
||||
style: const TextStyle(fontSize: 20),
|
||||
style: TextStyle(fontSize: 20),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -403,7 +444,7 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
children: [
|
||||
Icon(_isPaused ? Icons.play_arrow : Icons.pause),
|
||||
const SizedBox(width: 8),
|
||||
Text(_isPaused ? 'Resume' : 'Pause'),
|
||||
Text(_isPaused ? l10n.resume : l10n.pause),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -422,9 +463,9 @@ class _FocusScreenState extends State<FocusScreen> with WidgetsBindingObserver {
|
||||
padding: const EdgeInsets.only(bottom: 24.0),
|
||||
child: TextButton(
|
||||
onPressed: _stopEarly,
|
||||
child: const Text(
|
||||
'Stop session',
|
||||
style: TextStyle(
|
||||
child: Text(
|
||||
l10n.stopSession,
|
||||
style: const TextStyle(
|
||||
color: AppColors.textSecondary,
|
||||
fontSize: 14,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user