diff --git a/lib/constants.dart b/lib/constants.dart index cfd1985b..69327b9b 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -enum Themes { device, light, dark, oled, materialYou } +enum Themes { device, light, dark, oled, materialYou, dracula } enum HabitType { boolean, numeric } diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index c22317d4..4710d501 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -749,6 +749,7 @@ class S { 'dark': 'Dark', 'oled': 'OLED black', 'materialYou': 'Material You', + 'dracula': 'Dracula', 'other': 'Device', }, name: 'themeSelect', diff --git a/lib/habits/edit_habit_screen.dart b/lib/habits/edit_habit_screen.dart index dcd118e7..d73a0b0b 100644 --- a/lib/habits/edit_habit_screen.dart +++ b/lib/habits/edit_habit_screen.dart @@ -171,11 +171,12 @@ class _EditHabitScreenState extends State { accountant.text = widget.habitData!.accountant; habitType = widget.habitData!.habitType; targetValue.text = numberFormatter.format(widget.habitData!.targetValue); - partialValue.text = numberFormatter.format(widget.habitData!.partialValue); + partialValue.text = + numberFormatter.format(widget.habitData!.partialValue); unit.text = widget.habitData!.unit; selectedCategories = List.from(widget.habitData!.categories); } - + // Load categories when screen initializes WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of(context, listen: false).loadCategories(); @@ -212,14 +213,19 @@ class _EditHabitScreenState extends State { IconButton( icon: Icon( widget.habitData!.archived ? Icons.unarchive : Icons.archive, - semanticLabel: widget.habitData!.archived ? S.of(context).unarchive : S.of(context).archive, + semanticLabel: widget.habitData!.archived + ? S.of(context).unarchive + : S.of(context).archive, ), color: Colors.orange, - tooltip: widget.habitData!.archived ? S.of(context).unarchiveHabit : S.of(context).archiveHabit, + tooltip: widget.habitData!.archived + ? S.of(context).unarchiveHabit + : S.of(context).archiveHabit, onPressed: () { Navigator.of(context).pop(); if (widget.habitData != null) { - final habitsManager = Provider.of(context, listen: false); + final habitsManager = + Provider.of(context, listen: false); if (widget.habitData!.archived) { habitsManager.unarchiveHabit(widget.habitData!.id!); } else { @@ -273,14 +279,17 @@ class _EditHabitScreenState extends State { unit: unit.text.toString(), categories: selectedCategories, ); - final habitsManager = Provider.of(context, listen: false); + final habitsManager = + Provider.of(context, listen: false); habitsManager.editHabit(habitData); // Update habit-category associations if (widget.habitData!.id != null) { - habitsManager.updateHabitCategories(widget.habitData!.id!, selectedCategories); + habitsManager.updateHabitCategories( + widget.habitData!.id!, selectedCategories); } } else { - final habitsManager = Provider.of(context, listen: false); + final habitsManager = + Provider.of(context, listen: false); habitsManager.addHabit( title.text.toString(), twoDayRule, @@ -336,37 +345,34 @@ class _EditHabitScreenState extends State { hint: S.of(context).exercise, label: S.of(context).habit, ), - - ListTile( - contentPadding: - const EdgeInsets.symmetric(horizontal: 25), - title: Text( - S.of(context).habitType, - ), - trailing: DropdownButton( - value: habitType, - onChanged: (value) { - setState(() { - habitType = value!; - }); - }, - icon: const Icon(Icons.expand_more), - iconSize: 24, - elevation: 16, - items: [ - DropdownMenuItem( - value: HabitType.boolean, - child: Text(S.of(context).booleanHabit), - ), - DropdownMenuItem( - value: HabitType.numeric, - child: Text(S.of(context).numericHabit), - ), - ], - ), + contentPadding: const EdgeInsets.symmetric(horizontal: 25), + title: Text( + S.of(context).habitType, + ), + trailing: DropdownButton( + value: habitType, + onChanged: (value) { + setState(() { + habitType = value!; + }); + }, + icon: const Icon(Icons.expand_more), + iconSize: 24, + elevation: 16, + items: [ + DropdownMenuItem( + value: HabitType.boolean, + child: Text(S.of(context).booleanHabit), + ), + DropdownMenuItem( + value: HabitType.numeric, + child: Text(S.of(context).numericHabit), ), + ], + ), + ), if (habitType == HabitType.numeric) ...[ Container( // margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 20), @@ -382,19 +388,27 @@ class _EditHabitScreenState extends State { style: DefaultTextStyle.of(context).style, children: [ TextSpan( - text: S.of(context).numericHabitDescription), + text: S + .of(context) + .numericHabitDescription), WidgetSpan( child: Padding( - padding: - const EdgeInsets.fromLTRB(10, 0, 0, 0), + padding: const EdgeInsets.fromLTRB( + 10, 0, 0, 0), child: GestureDetector( onTap: () { - showSmallTooltip(context, S.of(context).numericHabit, - S.of(context).numericHabitDescription); + showSmallTooltip( + context, + S.of(context).numericHabit, + S + .of(context) + .numericHabitDescription); }, - child: const Icon( + child: Icon( Icons.info, - color: Colors.grey, + color: Theme.of(context) + .colorScheme + .primary, size: 20, ), ), @@ -412,12 +426,15 @@ class _EditHabitScreenState extends State { flex: 2, child: TextFormField( controller: targetValue, - keyboardType: const TextInputType.numberWithOptions(decimal: true), + keyboardType: + const TextInputType.numberWithOptions( + decimal: true), decoration: InputDecoration( labelText: S.of(context).targetValue, hintText: '100', border: OutlineInputBorder(), - contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), + contentPadding: EdgeInsets.symmetric( + horizontal: 12, vertical: 8), ), ), ), @@ -430,7 +447,8 @@ class _EditHabitScreenState extends State { labelText: S.of(context).unit, hintText: 'push-ups', border: OutlineInputBorder(), - contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), + contentPadding: EdgeInsets.symmetric( + horizontal: 12, vertical: 8), ), ), ), @@ -439,12 +457,14 @@ class _EditHabitScreenState extends State { const SizedBox(height: 12), TextFormField( controller: partialValue, - keyboardType: const TextInputType.numberWithOptions(decimal: true), + keyboardType: const TextInputType.numberWithOptions( + decimal: true), decoration: InputDecoration( labelText: S.of(context).partialValue, hintText: '10', border: OutlineInputBorder(), - contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), + contentPadding: EdgeInsets.symmetric( + horizontal: 12, vertical: 8), helperText: S.of(context).partialValueDescription, ), ), @@ -454,8 +474,7 @@ class _EditHabitScreenState extends State { ), ], Container( - margin: - const EdgeInsets.symmetric(horizontal: 10), + margin: const EdgeInsets.symmetric(horizontal: 10), child: Row( children: [ Checkbox( @@ -467,14 +486,14 @@ class _EditHabitScreenState extends State { value: twoDayRule, ), Text(S.of(context).useTwoDayRule), - IconButton( - onPressed: () { + GestureDetector( + onTap: () { showSmallTooltip(context, S.of(context).twoDayRule, S.of(context).twoDayRuleDescription); }, - icon: const Icon( + child: Icon( Icons.info, - color: Colors.grey, + color: Theme.of(context).colorScheme.primary, size: 20, ), ), @@ -493,14 +512,18 @@ class _EditHabitScreenState extends State { children: [ // Categories ListTile with plus sign ListTile( - contentPadding: const EdgeInsets.symmetric(horizontal: 25), + contentPadding: + const EdgeInsets.symmetric(horizontal: 25), title: Text(S.of(context).categories), trailing: IconButton( onPressed: () async { - final result = await Navigator.of(context).push>( + final result = await Navigator.of(context) + .push>( MaterialPageRoute( - builder: (context) => CategorySelectionScreen( - initialSelectedCategories: selectedCategories, + builder: (context) => + CategorySelectionScreen( + initialSelectedCategories: + selectedCategories, onCategoriesChanged: (categories) { // This callback is called when saving }, @@ -517,11 +540,12 @@ class _EditHabitScreenState extends State { iconSize: 24, ), ), - + // Categories chips (styled like category_filter_row.dart) if (selectedCategories.isNotEmpty) Container( - padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 4), + padding: const EdgeInsets.symmetric( + horizontal: 25, vertical: 4), child: Wrap( spacing: 8.0, runSpacing: 4.0, @@ -531,13 +555,11 @@ class _EditHabitScreenState extends State { category.title, style: const TextStyle( fontWeight: FontWeight.w600, - color: Colors.grey, ), ), avatar: Icon( category.icon, size: 18, - color: Colors.grey, ), selected: true, onSelected: (selected) { @@ -546,12 +568,6 @@ class _EditHabitScreenState extends State { selectedCategories.remove(category); }); }, - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - selectedColor: Theme.of(context).colorScheme.primaryContainer, - side: BorderSide( - color: Theme.of(context).colorScheme.outline.withValues(alpha: 0.3), - width: 1, - ), showCheckmark: false, ); }).toList(), @@ -586,9 +602,10 @@ class _EditHabitScreenState extends State { style: DefaultTextStyle.of(context).style, children: [ TextSpan( - text: S - .of(context) - .advancedHabitBuildingDescription), + text: S + .of(context) + .advancedHabitBuildingDescription, + ), WidgetSpan( child: Padding( padding: @@ -597,9 +614,11 @@ class _EditHabitScreenState extends State { onTap: () { showAdvancedTooltip(context); }, - child: const Icon( + child: Icon( Icons.info, - color: Colors.grey, + color: Theme.of(context) + .colorScheme + .primary, size: 20, ), ), @@ -690,9 +709,8 @@ class _EditHabitScreenState extends State { S.of(context).remainderOfReward, ); }, - icon: const Icon( + icon: Icon( Icons.info, - color: Colors.grey, size: 20, ), ), @@ -753,7 +771,6 @@ class _EditHabitScreenState extends State { }, icon: const Icon( Icons.info, - color: Colors.grey, size: 20, ), ), diff --git a/lib/habits/habit.dart b/lib/habits/habit.dart index ecb1ec90..3e4e81a5 100644 --- a/lib/habits/habit.dart +++ b/lib/habits/habit.dart @@ -63,9 +63,11 @@ class Habit extends StatefulWidget { 'notification': habitData.notification ? 1 : 0, 'notTime': '${habitData.notTime.hour}:${habitData.notTime.minute}', 'events': habitData.events.map((key, value) { - return MapEntry(key.toString(), value.length > 2 - ? [value[0].toString(), value[1], value[2]] - : [value[0].toString(), value[1]]); + return MapEntry( + key.toString(), + value.length > 2 + ? [value[0].toString(), value[1], value[2]] + : [value[0].toString(), value[1]]); }), 'sanction': habitData.sanction, 'showSanction': habitData.showSanction ? 1 : 0, @@ -74,7 +76,8 @@ class Habit extends StatefulWidget { 'targetValue': habitData.targetValue, 'partialValue': habitData.partialValue, 'unit': habitData.unit, - 'categories': habitData.categories.map((category) => category.toJson()).toList(), + 'categories': + habitData.categories.map((category) => category.toJson()).toList(), 'archived': habitData.archived ? 1 : 0, }; } @@ -112,9 +115,10 @@ class Habit extends StatefulWidget { SplayTreeMap result = SplayTreeMap(); input.forEach((key, value) { - final dayType = DayType.values.firstWhere((e) => e.toString() == reformatOld(value[0])); + final dayType = DayType.values + .firstWhere((e) => e.toString() == reformatOld(value[0])); final comment = value[1]; - + // Handle progress data for numeric habits if (value.length > 2 && dayType == DayType.progress) { final progressValue = (value[2] as num?)?.toDouble() ?? 0.0; @@ -184,9 +188,10 @@ class HabitState extends State { content: Text( '${S.of(context).congratulationsReward}\n${widget.habitData.reward}', textAlign: TextAlign.center, - style: const TextStyle(color: Colors.white), + style: TextStyle(color: Theme.of(context).colorScheme.onPrimary), ), - backgroundColor: Theme.of(context).colorScheme.primary, + backgroundColor: + Provider.of(context, listen: false).checkColor, behavior: SnackBarBehavior.floating, ), ); @@ -207,7 +212,7 @@ class HabitState extends State { content: Text( '${S.of(context).ohNoSanction}\n${widget.habitData.sanction}', textAlign: TextAlign.center, - style: const TextStyle(color: Colors.white), + style: TextStyle(color: Theme.of(context).colorScheme.onPrimary), ), backgroundColor: Provider.of(context, listen: false).failColor, @@ -389,24 +394,26 @@ class HabitState extends State { Color _getEventColor(List events) { final eventType = events[0] as DayType; - + switch (eventType) { case DayType.check: - return Provider.of(context, listen: false).checkColor; + return Provider.of(context).checkColor; case DayType.fail: - return Provider.of(context, listen: false).failColor; + return Provider.of(context).failColor; case DayType.skip: - return Provider.of(context, listen: false).skipColor; + return Provider.of(context).skipColor; case DayType.progress: // For progress events, check if it's 100% completion if (widget.habitData.isNumeric && events.length > 2) { final progressValue = (events[2] as num?)?.toDouble() ?? 0.0; if (progressValue >= widget.habitData.targetValue) { // 100% or more = green check color - return Provider.of(context, listen: false).checkColor; + return Provider.of(context, listen: false) + .checkColor; } } - return Provider.of(context, listen: false).progressColor; + return Provider.of(context, listen: false) + .progressColor; case DayType.clear: default: return Colors.transparent; @@ -415,22 +422,22 @@ class HabitState extends State { Widget _getEventIcon(List events) { final eventType = events[0] as DayType; - + switch (eventType) { case DayType.check: - return const Icon( + return Icon( Icons.check, - color: Colors.white, + color: Provider.of(context).iconColor, ); case DayType.fail: - return const Icon( + return Icon( Icons.close, - color: Colors.white, + color: Provider.of(context).iconColor, ); case DayType.skip: - return const Icon( + return Icon( Icons.last_page, - color: Colors.white, + color: Provider.of(context).iconColor, ); case DayType.progress: // For progress events, check if it's 100% completion @@ -438,9 +445,9 @@ class HabitState extends State { final progressValue = (events[2] as num?)?.toDouble() ?? 0.0; if (progressValue >= widget.habitData.targetValue) { // 100% or more = green check icon - return const Icon( + return Icon( Icons.check, - color: Colors.white, + color: Provider.of(context).iconColor, ); } } @@ -455,8 +462,9 @@ class HabitState extends State { // For progress events, show a circular progress indicator if (events.length > 2 && widget.habitData.isNumeric) { final progressValue = (events[2] as num?)?.toDouble() ?? 0.0; - final percentage = (progressValue / widget.habitData.targetValue).clamp(0.0, 1.0); - + final percentage = + (progressValue / widget.habitData.targetValue).clamp(0.0, 1.0); + return Stack( children: [ Center( @@ -466,16 +474,19 @@ class HabitState extends State { child: CircularProgressIndicator( value: percentage, strokeWidth: 3, - backgroundColor: Colors.white.withValues(alpha: 0.3), - valueColor: const AlwaysStoppedAnimation(Colors.white), + backgroundColor: Provider.of(context) + .progressColor + .withValues(alpha: 0.3), + valueColor: AlwaysStoppedAnimation( + Provider.of(context).iconColor), ), ), ), Center( child: Text( '${(percentage * 100).round()}%', - style: const TextStyle( - color: Colors.white, + style: TextStyle( + color: Provider.of(context).iconColor, fontSize: 8, fontWeight: FontWeight.bold, ), @@ -516,11 +527,12 @@ class HabitState extends State { lastDayKey = checkDayKey; } - if (widget.habitData.events[checkDayKey]![0] == DayType.check - || (widget.habitData.events[checkDayKey]![0] == DayType.progress - && widget.habitData.events[checkDayKey]![2] >= widget.habitData.targetValue)) { - inStreak++; - } + if (widget.habitData.events[checkDayKey]![0] == DayType.check || + (widget.habitData.events[checkDayKey]![0] == DayType.progress && + widget.habitData.events[checkDayKey]![2] >= + widget.habitData.targetValue)) { + inStreak++; + } checkDayKey = widget.habitData.events.lastKeyBefore(checkDayKey!); } @@ -537,9 +549,10 @@ class HabitState extends State { while (widget.habitData.events[trueLastKey] != null && widget.habitData.events[trueLastKey]![0] != null && (widget.habitData.events[trueLastKey]![0] == DayType.clear || - (widget.habitData.events[trueLastKey]![0] == DayType.progress && - widget.habitData.events[trueLastKey]![2] < widget.habitData.targetValue))) { - trueLastKey = widget.habitData.events.lastKeyBefore(trueLastKey!); + (widget.habitData.events[trueLastKey]![0] == DayType.progress && + widget.habitData.events[trueLastKey]![2] < + widget.habitData.targetValue))) { + trueLastKey = widget.habitData.events.lastKeyBefore(trueLastKey!); } var checkDayKey = trueLastKey; @@ -550,8 +563,9 @@ class HabitState extends State { if (widget.habitData.events[checkDayKey]![0] != DayType.clear) { // End if fail and next is not check, clear or progress if (widget.habitData.events[checkDayKey]![0] == DayType.fail && - (lastDay != DayType.check && lastDay != DayType.clear && - (lastDay != DayType.progress))) { + (lastDay != DayType.check && + lastDay != DayType.clear && + (lastDay != DayType.progress))) { break; } diff --git a/lib/habits/habit_header.dart b/lib/habits/habit_header.dart index f8a3e634..315994db 100644 --- a/lib/habits/habit_header.dart +++ b/lib/habits/habit_header.dart @@ -3,6 +3,7 @@ import 'package:habo/constants.dart'; import 'package:habo/generated/l10n.dart'; import 'package:habo/habits/habit.dart'; import 'package:habo/habits/habits_manager.dart'; +import 'package:habo/settings/settings_manager.dart'; import 'package:provider/provider.dart'; class HabitHeader extends StatelessWidget { @@ -32,7 +33,7 @@ class HabitHeader extends StatelessWidget { child: Text( Provider.of(context) .getNameOfHabit(widget.habitData.id!), - style: const TextStyle(fontSize: 20), + style: Theme.of(context).textTheme.titleLarge, overflow: TextOverflow.ellipsis, ), ), @@ -45,7 +46,6 @@ class HabitHeader extends StatelessWidget { Icons.edit_outlined, semanticLabel: S.of(context).modify, ), - color: Colors.grey, tooltip: S.of(context).modify, onPressed: () { widget.navigateToEditPage(context); @@ -61,10 +61,13 @@ class HabitHeader extends StatelessWidget { border: Border.all( color: (_orangeStreak) ? HaboColors.orange - : HaboColors.primary, + : Provider.of(context, listen: false) + .checkColor, ), - color: - (_orangeStreak) ? HaboColors.orange : HaboColors.primary, + color: (_orangeStreak) + ? HaboColors.orange + : Provider.of(context, listen: false) + .checkColor, borderRadius: const BorderRadius.all(Radius.circular(20)), boxShadow: [ BoxShadow( @@ -76,7 +79,9 @@ class HabitHeader extends StatelessWidget { child: Text( '$_streak', textAlign: TextAlign.right, - style: const TextStyle(fontSize: 16, color: Colors.white), + style: TextStyle( + fontSize: 16, + color: Provider.of(context).iconColor), ), ), ), diff --git a/lib/habits/habits_screen.dart b/lib/habits/habits_screen.dart index 8388390b..e1c1e3f7 100644 --- a/lib/habits/habits_screen.dart +++ b/lib/habits/habits_screen.dart @@ -1,7 +1,6 @@ import 'package:awesome_dialog/awesome_dialog.dart'; import 'package:awesome_notifications/awesome_notifications.dart'; import 'package:flutter/material.dart'; -import 'package:habo/constants.dart'; import 'package:habo/generated/l10n.dart'; import 'package:habo/notifications.dart'; import 'package:provider/provider.dart'; @@ -192,7 +191,7 @@ class _HabitsScreenState extends State { btnOkText: S.of(context).allow, btnCancelText: S.of(context).cancel, btnCancelColor: Colors.grey, - btnOkColor: HaboColors.primary, + btnOkColor: Theme.of(context).colorScheme.primary, btnCancelOnPress: () {}, btnOkOnPress: () { AwesomeNotifications() diff --git a/lib/habits/one_day_button.dart b/lib/habits/one_day_button.dart index 9a60a841..5c0a09b7 100644 --- a/lib/habits/one_day_button.dart +++ b/lib/habits/one_day_button.dart @@ -64,7 +64,8 @@ class OneDayButton extends StatelessWidget { key: const Key('Plus'), icon: Icon( Icons.add, - color: Provider.of(context, listen: false).progressColor, + color: Provider.of(context, listen: false) + .progressColor, semanticLabel: 'Add Progress', ), ), @@ -120,21 +121,21 @@ class OneDayButton extends StatelessWidget { child: Container( alignment: Alignment.center, child: DropdownButton( - iconSize: 0, - elevation: 3, - alignment: Alignment.center, - borderRadius: BorderRadius.circular(10.0), - underline: Container(), - items: icons.map( - (InButton value) { - return DropdownMenuItem( - key: value.key, - value: value, - child: Center(child: value), - ); - }, - ).toList(), - value: icons[index], + iconSize: 0, + elevation: 3, + alignment: Alignment.center, + borderRadius: BorderRadius.circular(10.0), + underline: Container(), + items: icons.map( + (InButton value) { + return DropdownMenuItem( + key: value.key, + value: value, + child: Center(child: value), + ); + }, + ).toList(), + value: icons[index], onTap: () { parent.setSelectedDay(date); }, @@ -144,7 +145,8 @@ class OneDayButton extends StatelessWidget { value.key == const Key('Fail') || value.key == const Key('Skip')) { // For numeric habits, Check means complete the habit fully - if (value.key == const Key('Check') && parent.widget.habitData.isNumeric) { + if (value.key == const Key('Check') && + parent.widget.habitData.isNumeric) { Provider.of(context, listen: false) .playCheckSound(); // Complete the habit with full target value @@ -232,7 +234,7 @@ class OneDayButton extends StatelessWidget { btnOkText: S.of(context).save, btnCancelText: S.of(context).close, btnCancelColor: Colors.grey, - btnOkColor: HaboColors.primary, + btnOkColor: Theme.of(context).colorScheme.primary, btnCancelOnPress: () {}, btnOkOnPress: () { Provider.of(context, listen: false).addEvent( @@ -261,7 +263,7 @@ class OneDayButton extends StatelessWidget { void _showProgressInputModal(BuildContext context) { final habitData = parent.widget.habitData; final currentProgress = habitData.getProgressForDate(date); - + showDialog( context: context, builder: (BuildContext context) { @@ -276,7 +278,7 @@ class OneDayButton extends StatelessWidget { Provider.of(context, listen: false) .addEvent(id, date, [DayType.progress, '', progressValue]); parent.events[date] = [DayType.progress, '', progressValue]; - + // Play appropriate sound and show notification if (progressValue >= habitData.targetValue) { parent.showRewardNotification(date); @@ -286,7 +288,7 @@ class OneDayButton extends StatelessWidget { Provider.of(context, listen: false) .playClickSound(); } - + callback(); }, ); diff --git a/lib/model/settings_data.dart b/lib/model/settings_data.dart index 5ca64f57..d49086c2 100644 --- a/lib/model/settings_data.dart +++ b/lib/model/settings_data.dart @@ -17,6 +17,7 @@ class SettingsData { Color failColor = HaboColors.red; Color skipColor = HaboColors.skip; Color progressColor = HaboColors.progress; + Color iconColor = Colors.white; bool biometricLock = false; String lastWhatsNewVersion = ''; @@ -29,8 +30,7 @@ class SettingsData { (json['showDailyNot'] != null) ? json['showDailyNot'] : true, soundEffects = (json['soundEffects'] != null) ? json['soundEffects'] : true, - soundVolume = - (json['soundVolume'] != null) ? json['soundVolume'] : 3.0, + soundVolume = (json['soundVolume'] != null) ? json['soundVolume'] : 3.0, showMonthName = (json['showMonthName'] != null) ? json['showMonthName'] : true, seenOnboarding = @@ -40,7 +40,6 @@ class SettingsData { dailyNotTime = (json['notTime'] != null) ? parseTimeOfDay(json['notTime']) : const TimeOfDay(hour: 20, minute: 0), - checkColor = (json['checkColor'] != null) ? Color(json['checkColor']) : HaboColors.primary, @@ -50,12 +49,14 @@ class SettingsData { skipColor = (json['skipColor'] != null) ? Color(json['skipColor']) : HaboColors.skip, + iconColor = (json['iconColor'] != null) + ? Color(json['iconColor']) + : Colors.white, progressColor = (json['progressColor'] != null) ? Color(json['progressColor']) : HaboColors.progress, - biometricLock = (json['biometricLock'] != null) - ? json['biometricLock'] - : false, + biometricLock = + (json['biometricLock'] != null) ? json['biometricLock'] : false, lastWhatsNewVersion = (json['lastWhatsNewVersion'] != null) ? json['lastWhatsNewVersion'] : ''; @@ -74,6 +75,7 @@ class SettingsData { 'checkColor': checkColor.toARGB32(), 'failColor': failColor.toARGB32(), 'skipColor': skipColor.toARGB32(), + 'iconColor': iconColor.toARGB32(), 'progressColor': progressColor.toARGB32(), 'biometricLock': biometricLock, 'lastWhatsNewVersion': lastWhatsNewVersion, diff --git a/lib/onboarding/onboarding.dart b/lib/onboarding/onboarding.dart index 536ae4c9..663a91e1 100644 --- a/lib/onboarding/onboarding.dart +++ b/lib/onboarding/onboarding.dart @@ -197,7 +197,8 @@ class Onboarding extends StatelessWidget { }, next: const Icon(Icons.arrow_forward), showSkipButton: true, - dotsDecorator: const DotsDecorator(activeColor: HaboColors.primary), + dotsDecorator: + DotsDecorator(activeColor: Theme.of(context).colorScheme.primary), skip: Text(S.of(context).skip), ); } diff --git a/lib/screens/category_selection_screen.dart b/lib/screens/category_selection_screen.dart index 40b98616..a9dbb1f8 100644 --- a/lib/screens/category_selection_screen.dart +++ b/lib/screens/category_selection_screen.dart @@ -84,7 +84,6 @@ class _CategorySelectionScreenState extends State { avatar: Icon( category.icon, size: 18, - color: Theme.of(context).colorScheme.primary, ), label: Text(category.title), deleteIcon: const Icon(Icons.close, size: 16), @@ -397,7 +396,8 @@ class _CategorySelectionScreenState extends State { ); _editTitleController.text = ''; _editSelectedIcon = Icons.category; - _editSelectedFontFamily = null; // Material Icons don't need explicit font family + _editSelectedFontFamily = + null; // Material Icons don't need explicit font family }); } @@ -465,7 +465,8 @@ class _CategorySelectionScreenState extends State { return; } - await habitsManager.addCategory(title, _editSelectedIcon.codePoint, _editSelectedFontFamily); + await habitsManager.addCategory( + title, _editSelectedIcon.codePoint, _editSelectedFontFamily); // Find the newly created category and auto-select it final newCategory = habitsManager.allCategories diff --git a/lib/settings/color_icon.dart b/lib/settings/color_icon.dart index dbd3b28c..45ef92a2 100644 --- a/lib/settings/color_icon.dart +++ b/lib/settings/color_icon.dart @@ -9,12 +9,14 @@ class ColorIcon extends StatefulWidget { required this.color, required this.icon, required this.defaultColor, - required this.onPicked}); + required this.onPicked, + this.iconColor = Colors.white}); final Color color; final IconData icon; final Color defaultColor; final Function onPicked; + final Color iconColor; @override State createState() => _ColorIconState(); @@ -29,6 +31,12 @@ class _ColorIconState extends State { tempColor = widget.color.withValues(alpha: 1.0); } + @override + void didUpdateWidget(covariant ColorIcon oldWidget) { + super.didUpdateWidget(oldWidget); + tempColor = widget.color.withValues(alpha: 1.0); + } + @override Widget build(BuildContext context) { return Padding( @@ -47,7 +55,7 @@ class _ColorIconState extends State { widget.icon, size: 16, ), - color: Colors.white, + color: widget.iconColor, onPressed: () { showDialog( context: context, @@ -74,9 +82,8 @@ class _ColorIconState extends State { const EdgeInsets.symmetric( vertical: 10, horizontal: 20), ), - foregroundColor: - const WidgetStatePropertyAll( - Colors.white), + foregroundColor: WidgetStatePropertyAll( + widget.iconColor), backgroundColor: const WidgetStatePropertyAll( Colors.grey), @@ -96,9 +103,8 @@ class _ColorIconState extends State { foregroundColor: const WidgetStatePropertyAll( Colors.white), - backgroundColor: - WidgetStatePropertyAll( - widget.defaultColor), + backgroundColor: WidgetStatePropertyAll( + widget.defaultColor), ), onPressed: () { setState( diff --git a/lib/settings/settings_manager.dart b/lib/settings/settings_manager.dart index b6e84e1c..1a17021c 100644 --- a/lib/settings/settings_manager.dart +++ b/lib/settings/settings_manager.dart @@ -62,9 +62,12 @@ class SettingsManager extends ChangeNotifier { } void playCheckSound() { - if (_settingsData.soundEffects && _soundsLoaded && _settingsData.soundVolume > 0) { + if (_settingsData.soundEffects && + _soundsLoaded && + _settingsData.soundVolume > 0) { try { - final volume = _settingsData.soundVolume / 5.0; // Convert 0-5 to 0.0-1.0 + final volume = + _settingsData.soundVolume / 5.0; // Convert 0-5 to 0.0-1.0 SoLoud.instance.play(_checkSource, volume: volume); } catch (e) { // Handle playback error gracefully @@ -75,9 +78,12 @@ class SettingsManager extends ChangeNotifier { } void playClickSound() { - if (_settingsData.soundEffects && _soundsLoaded && _settingsData.soundVolume > 0) { + if (_settingsData.soundEffects && + _soundsLoaded && + _settingsData.soundVolume > 0) { try { - final volume = _settingsData.soundVolume / 5.0; // Convert 0-5 to 0.0-1.0 + final volume = + _settingsData.soundVolume / 5.0; // Convert 0-5 to 0.0-1.0 SoLoud.instance.play(_clickSource, volume: volume); } catch (e) { // Handle playback error gracefully @@ -111,7 +117,9 @@ class SettingsManager extends ChangeNotifier { case Themes.oled: return HaboTheme.oledTheme; case Themes.materialYou: - return HaboTheme.darkTheme; // Fallback for Material You + return HaboTheme.darkTheme; // + case Themes.dracula: + return HaboTheme.draculaTheme; default: return HaboTheme.darkTheme; } @@ -128,7 +136,9 @@ class SettingsManager extends ChangeNotifier { case Themes.oled: return HaboTheme.oledTheme; case Themes.materialYou: - return HaboTheme.lightTheme; // Fallback for Material You + return HaboTheme.lightTheme; // Fa + case Themes.dracula: + return HaboTheme.draculaTheme; default: return HaboTheme.lightTheme; } @@ -186,6 +196,10 @@ class SettingsManager extends ChangeNotifier { return _settingsData.progressColor; } + Color get iconColor { + return _settingsData.iconColor; + } + bool get getBiometricLock { return _settingsData.biometricLock; } @@ -210,6 +224,19 @@ class SettingsManager extends ChangeNotifier { set setTheme(Themes value) { _settingsData.theme = value; + if (value == Themes.dracula) { + _settingsData.checkColor = draculaGreen; + _settingsData.failColor = draculaRed; + _settingsData.skipColor = draculaYellow; + _settingsData.progressColor = draculaCyan; + _settingsData.iconColor = draculaSelection; + } else { + _settingsData.checkColor = HaboColors.primary; + _settingsData.failColor = HaboColors.red; + _settingsData.skipColor = HaboColors.skip; + _settingsData.progressColor = HaboColors.progress; + _settingsData.iconColor = Colors.white; + } saveData(); notifyListeners(); } diff --git a/lib/settings/settings_screen.dart b/lib/settings/settings_screen.dart index d8d69564..ae9a69a8 100644 --- a/lib/settings/settings_screen.dart +++ b/lib/settings/settings_screen.dart @@ -103,7 +103,7 @@ class _SettingsScreenState extends State { btnOkText: S.of(context).restore, btnCancelText: S.of(context).cancel, btnCancelColor: Colors.grey, - btnOkColor: HaboColors.primary, + btnOkColor: Theme.of(context).colorScheme.primary, btnCancelOnPress: () {}, btnOkOnPress: () async { await Provider.of(context, listen: false).loadBackup(); @@ -133,7 +133,7 @@ class _SettingsScreenState extends State { S.of(context).settings, ), backgroundColor: Colors.transparent, - iconTheme: Theme.of(context).iconTheme, + // iconTheme: Theme.of(context).iconTheme, ), body: SingleChildScrollView( child: Center( @@ -375,10 +375,12 @@ class _SettingsScreenState extends State { mainAxisSize: MainAxisSize.min, children: [ ColorIcon( - color: Provider.of(context, - listen: false) - .checkColor, + color: Provider.of( + context, + ).checkColor, icon: Icons.check, + iconColor: + Provider.of(context).iconColor, defaultColor: HaboColors.primary, onPicked: (value) { Provider.of(context, @@ -387,10 +389,11 @@ class _SettingsScreenState extends State { }, ), ColorIcon( - color: Provider.of(context, - listen: false) + color: Provider.of(context) .progressColor, icon: Icons.trending_up, + iconColor: + Provider.of(context).iconColor, defaultColor: HaboColors.progress, onPicked: (value) { Provider.of(context, @@ -399,10 +402,11 @@ class _SettingsScreenState extends State { }, ), ColorIcon( - color: Provider.of(context, - listen: false) - .failColor, + color: + Provider.of(context).failColor, icon: Icons.close, + iconColor: + Provider.of(context).iconColor, defaultColor: HaboColors.red, onPicked: (value) { Provider.of(context, @@ -411,10 +415,11 @@ class _SettingsScreenState extends State { }, ), ColorIcon( - color: Provider.of(context, - listen: false) - .skipColor, + color: + Provider.of(context).skipColor, icon: Icons.last_page, + iconColor: + Provider.of(context).iconColor, defaultColor: HaboColors.skip, onPicked: (value) { Provider.of(context, diff --git a/lib/statistics/monthly_graph.dart b/lib/statistics/monthly_graph.dart index eb8be0db..fc0f233a 100644 --- a/lib/statistics/monthly_graph.dart +++ b/lib/statistics/monthly_graph.dart @@ -42,8 +42,7 @@ class _MonthlyGraphState extends State { padding: const EdgeInsets.all(4.0), child: Material( color: showCheck - ? Provider.of(context, listen: false) - .checkColor + ? Provider.of(context).checkColor : Theme.of(context).colorScheme.primaryContainer, borderRadius: BorderRadius.circular(10.0), elevation: 2, @@ -52,15 +51,19 @@ class _MonthlyGraphState extends State { height: 32, child: IconButton( splashColor: Colors.transparent, - icon: const Icon( + icon: Icon( Icons.check, + color: showCheck + ? Provider.of(context).iconColor + : Provider.of(context) + .checkColor, size: 16, ), color: showCheck ? Colors.white - : Provider.of(context, - listen: false) - .checkColor, + : Provider.of( + context, + ).checkColor, onPressed: () { showCheck = !showCheck; setState(() {}); @@ -73,8 +76,7 @@ class _MonthlyGraphState extends State { padding: const EdgeInsets.all(4.0), child: Material( color: showProgress - ? Provider.of(context, listen: false) - .progressColor + ? Provider.of(context).progressColor : Theme.of(context).colorScheme.primaryContainer, borderRadius: BorderRadius.circular(10.0), elevation: 2, @@ -83,13 +85,17 @@ class _MonthlyGraphState extends State { height: 32, child: IconButton( splashColor: Colors.transparent, - icon: const Icon( + icon: Icon( Icons.trending_up, + color: showProgress + ? Provider.of(context).iconColor + : Provider.of(context) + .progressColor, size: 16, ), color: showProgress ? Colors.white - : Provider.of(context, listen: false) + : Provider.of(context) .progressColor, onPressed: () { showProgress = !showProgress; @@ -103,8 +109,7 @@ class _MonthlyGraphState extends State { padding: const EdgeInsets.all(4.0), child: Material( color: showSkip - ? Provider.of(context, listen: false) - .skipColor + ? Provider.of(context).skipColor : Theme.of(context).colorScheme.primaryContainer, borderRadius: BorderRadius.circular(10.0), elevation: 2, @@ -113,15 +118,18 @@ class _MonthlyGraphState extends State { height: 32, child: IconButton( splashColor: Colors.transparent, - icon: const Icon( + icon: Icon( Icons.last_page, + color: showSkip + ? Provider.of(context).iconColor + : Provider.of(context).skipColor, size: 16, ), color: showSkip ? Colors.white - : Provider.of(context, - listen: false) - .skipColor, + : Provider.of( + context, + ).skipColor, onPressed: () { showSkip = !showSkip; setState(() {}); @@ -134,8 +142,9 @@ class _MonthlyGraphState extends State { padding: const EdgeInsets.all(4.0), child: Material( color: showFail - ? Provider.of(context, listen: false) - .failColor + ? Provider.of( + context, + ).failColor : Theme.of(context).colorScheme.primaryContainer, borderRadius: BorderRadius.circular(10.0), elevation: 2, @@ -144,15 +153,18 @@ class _MonthlyGraphState extends State { height: 32, child: IconButton( splashColor: Colors.transparent, - icon: const Icon( + icon: Icon( Icons.close, + color: showFail + ? Provider.of(context).iconColor + : Provider.of(context).failColor, size: 16, ), color: showFail ? Colors.white - : Provider.of(context, - listen: false) - .failColor, + : Provider.of( + context, + ).failColor, onPressed: () { showFail = !showFail; setState(() {}); @@ -287,32 +299,36 @@ class _MonthlyGraphState extends State { BarChartRodData( toY: widget.data.monthlyCheck[year]![DayType.check]![i] .toDouble(), - color: Provider.of(context, listen: false) - .checkColor, + color: Provider.of( + context, + ).checkColor, width: width, ), if (showProgress) BarChartRodData( toY: widget.data.monthlyCheck[year]![DayType.progress]![i] .toDouble(), - color: Provider.of(context, listen: false) - .progressColor, + color: Provider.of( + context, + ).progressColor, width: width, ), if (showSkip) BarChartRodData( toY: widget.data.monthlyCheck[year]![DayType.skip]![i] .toDouble(), - color: Provider.of(context, listen: false) - .skipColor, + color: Provider.of( + context, + ).skipColor, width: width, ), if (showFail) BarChartRodData( toY: widget.data.monthlyCheck[year]![DayType.fail]![i] .toDouble(), - color: Provider.of(context, listen: false) - .failColor, + color: Provider.of( + context, + ).failColor, width: width, ), if (!showCheck && !showProgress && !showSkip && !showFail) diff --git a/lib/statistics/overall_statistics_card.dart b/lib/statistics/overall_statistics_card.dart index 6abd1e7b..13c2c3bf 100644 --- a/lib/statistics/overall_statistics_card.dart +++ b/lib/statistics/overall_statistics_card.dart @@ -30,8 +30,7 @@ class OverallStatisticsCard extends StatelessWidget { PieChartData( sections: showingSections(context), ), - duration: - const Duration(milliseconds: 150), // Optional + duration: const Duration(milliseconds: 150), // Optional curve: Curves.linear, // Optional ), Center( @@ -157,12 +156,11 @@ class OverallStatisticsCard extends StatelessWidget { return [ if (total.checks != 0) PieChartSectionData( - color: - Provider.of(context, listen: false).checkColor, + color: Provider.of(context).checkColor, value: total.checks.toDouble(), - badgeWidget: const Icon( + badgeWidget: Icon( Icons.check, - color: Colors.white, + color: Provider.of(context).iconColor, ), title: '', radius: 25.0, @@ -171,11 +169,11 @@ class OverallStatisticsCard extends StatelessWidget { ), if (total.skips != 0) PieChartSectionData( - color: Provider.of(context, listen: false).skipColor, + color: Provider.of(context).skipColor, value: total.skips.toDouble(), - badgeWidget: const Icon( + badgeWidget: Icon( Icons.last_page, - color: Colors.white, + color: Provider.of(context).iconColor, ), title: '', radius: 25.0, @@ -184,12 +182,11 @@ class OverallStatisticsCard extends StatelessWidget { ), if (total.progress != 0) PieChartSectionData( - color: Provider.of(context, listen: false) - .progressColor, + color: Provider.of(context).progressColor, value: total.progress.toDouble(), - badgeWidget: const Icon( + badgeWidget: Icon( Icons.trending_up, - color: Colors.white, + color: Provider.of(context).iconColor, ), title: '', radius: 25.0, @@ -198,11 +195,11 @@ class OverallStatisticsCard extends StatelessWidget { ), if (total.fails != 0) PieChartSectionData( - color: Provider.of(context, listen: false).failColor, + color: Provider.of(context).failColor, value: total.fails.toDouble(), - badgeWidget: const Icon( + badgeWidget: Icon( Icons.close, - color: Colors.white, + color: Provider.of(context).iconColor, ), title: '', radius: 25.0, diff --git a/lib/statistics/statistics_card.dart b/lib/statistics/statistics_card.dart index eb0a3db1..d7b0c0d0 100644 --- a/lib/statistics/statistics_card.dart +++ b/lib/statistics/statistics_card.dart @@ -31,10 +31,7 @@ class StatisticsCard extends StatelessWidget { Expanded( child: Text( data.title, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), + style: Theme.of(context).textTheme.headlineSmall, overflow: TextOverflow.ellipsis, ), ), @@ -50,16 +47,17 @@ class StatisticsCard extends StatelessWidget { children: [ Text( S.of(context).topStreak, - style: const TextStyle( - fontSize: 18, - ), + style: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(fontWeight: FontWeight.bold), ), Text( data.topStreak.toString(), - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - ), + style: Theme.of(context) + .textTheme + .displaySmall + ?.copyWith(fontWeight: FontWeight.bold), ), ], ), @@ -67,16 +65,17 @@ class StatisticsCard extends StatelessWidget { children: [ Text( S.of(context).currentStreak, - style: const TextStyle( - fontSize: 18, - ), + style: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(fontWeight: FontWeight.bold), ), Text( data.actualStreak.toString(), - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - ), + style: Theme.of(context) + .textTheme + .displaySmall + ?.copyWith(fontWeight: FontWeight.bold), ), ], ), @@ -102,9 +101,7 @@ class StatisticsCard extends StatelessWidget { children: [ Icon( Icons.check, - color: - Provider.of(context, listen: false) - .checkColor, + color: Provider.of(context).checkColor, ), Text( data.checks.toString(), @@ -124,8 +121,7 @@ class StatisticsCard extends StatelessWidget { Icon( Icons.trending_up, color: - Provider.of(context, listen: false) - .progressColor, + Provider.of(context).progressColor, ), Text( data.progress.toString(), @@ -144,9 +140,7 @@ class StatisticsCard extends StatelessWidget { children: [ Icon( Icons.last_page, - color: - Provider.of(context, listen: false) - .skipColor, + color: Provider.of(context).skipColor, ), Text( data.skips.toString(), @@ -165,9 +159,7 @@ class StatisticsCard extends StatelessWidget { children: [ Icon( Icons.close, - color: - Provider.of(context, listen: false) - .failColor, + color: Provider.of(context).failColor, ), Text( data.fails.toString(), diff --git a/lib/statistics/statistics_screen.dart b/lib/statistics/statistics_screen.dart index 1310bd0d..436d73f5 100644 --- a/lib/statistics/statistics_screen.dart +++ b/lib/statistics/statistics_screen.dart @@ -35,7 +35,6 @@ class _StatisticsScreenState extends State { S.of(context).statistics, ), backgroundColor: Colors.transparent, - iconTheme: Theme.of(context).iconTheme, ), body: FutureBuilder( future: Provider.of(context).getFutureStatsData(), diff --git a/lib/themes.dart b/lib/themes.dart index 795b3a17..48dee531 100644 --- a/lib/themes.dart +++ b/lib/themes.dart @@ -8,6 +8,12 @@ class HaboTheme { return ThemeData( useMaterial3: true, scaffoldBackgroundColor: const Color(0xFFFAFAFA), + iconButtonTheme: const IconButtonThemeData( + style: ButtonStyle( + foregroundColor: WidgetStatePropertyAll( + Colors.grey, + )), + ), dialogTheme: const DialogThemeData(surfaceTintColor: Colors.white), brightness: Brightness.light, primaryColor: const Color(0xFF09BF30), @@ -15,11 +21,15 @@ class HaboTheme { hourMinuteColor: Colors.grey[100], dialBackgroundColor: Colors.grey[100], ), + chipTheme: ChipThemeData( + backgroundColor: Colors.grey.withAlpha(50), + ), colorScheme: ColorScheme.light( primaryContainer: Colors.white, secondaryContainer: Colors.grey[100], tertiaryContainer: HaboColors.primary, onPrimaryContainer: HaboColors.primary, + onPrimary: Color(0xFF505050), primary: HaboColors.primary, outline: const Color(0xFF505050), ), @@ -37,6 +47,10 @@ class HaboTheme { systemNavigationBarIconBrightness: Brightness.dark, ), ), + listTileTheme: ListTileThemeData( + titleTextStyle: ThemeData.light().textTheme.titleMedium, + subtitleTextStyle: ThemeData.light().textTheme.bodyMedium, + ), canvasColor: Colors.white, focusColor: Colors.white, ); @@ -46,6 +60,12 @@ class HaboTheme { return ThemeData( useMaterial3: true, scaffoldBackgroundColor: const Color(0xFF303030), + iconButtonTheme: const IconButtonThemeData( + style: ButtonStyle( + foregroundColor: WidgetStatePropertyAll( + Colors.grey, + )), + ), dialogTheme: const DialogThemeData( backgroundColor: Color(0xFF505050), surfaceTintColor: Colors.transparent, @@ -84,6 +104,10 @@ class HaboTheme { systemNavigationBarIconBrightness: Brightness.light, ), ), + listTileTheme: ListTileThemeData( + titleTextStyle: ThemeData.dark().textTheme.titleMedium, + subtitleTextStyle: ThemeData.dark().textTheme.bodyMedium, + ), canvasColor: Color(0xFF505050), focusColor: Color(0xFF505050), ); @@ -93,6 +117,12 @@ class HaboTheme { return ThemeData( useMaterial3: true, scaffoldBackgroundColor: Colors.black, + iconButtonTheme: const IconButtonThemeData( + style: ButtonStyle( + foregroundColor: WidgetStatePropertyAll( + Colors.grey, + )), + ), dialogTheme: const DialogThemeData( backgroundColor: Color(0xFF282828), surfaceTintColor: Colors.transparent, @@ -131,10 +161,107 @@ class HaboTheme { systemNavigationBarIconBrightness: Brightness.light, ), ), + listTileTheme: ListTileThemeData( + titleTextStyle: ThemeData.dark().textTheme.titleMedium, + subtitleTextStyle: ThemeData.dark().textTheme.bodyMedium, + ), canvasColor: Color(0xFF282828), focusColor: Color(0xFF282828), ); } + + static ThemeData get draculaTheme { + return ThemeData( + useMaterial3: true, + scaffoldBackgroundColor: draculaBackground, + textTheme: const TextTheme( + titleLarge: TextStyle(color: draculaYellow), + titleMedium: TextStyle(color: draculaYellow), + titleSmall: TextStyle(color: draculaYellow), + labelLarge: TextStyle(color: draculaPink), + labelMedium: TextStyle(color: draculaPink), + labelSmall: TextStyle(color: draculaPink), + bodyLarge: TextStyle(color: draculaForeground), + bodyMedium: TextStyle(color: draculaForeground), + bodySmall: TextStyle(color: draculaForeground), + displayLarge: TextStyle(color: draculaGreen), + displayMedium: TextStyle(color: draculaGreen), + displaySmall: TextStyle(color: draculaGreen), + headlineLarge: TextStyle(color: draculaPurple), + headlineMedium: TextStyle(color: draculaPurple), + headlineSmall: TextStyle(color: draculaPurple), + ), + iconButtonTheme: const IconButtonThemeData( + style: ButtonStyle( + foregroundColor: WidgetStatePropertyAll(Color(0xFFFF79C6))), + ), + chipTheme: ChipThemeData( + backgroundColor: draculaSelection, + ), + dialogTheme: const DialogThemeData( + backgroundColor: Color(0xFF21222C), + surfaceTintColor: Colors.transparent, + ), + primaryColor: Colors.grey, + fontFamily: GoogleFonts.nunito().fontFamily, + switchTheme: SwitchThemeData( + thumbColor: WidgetStateProperty.resolveWith(getSwitchColorThumb), + trackColor: WidgetStateProperty.resolveWith(getSwitchTrackDraculaColor), + ), + timePickerTheme: const TimePickerThemeData( + dayPeriodTextColor: draculaGreen, + hourMinuteColor: draculaGreen, + dialBackgroundColor: Color(0xFF191919), + dialTextColor: Colors.white, + backgroundColor: draculaBackground, + ), + colorScheme: const ColorScheme.dark( + primaryContainer: draculaBackground, + secondaryContainer: Color(0xFF191919), + tertiaryContainer: draculaGreen, + onPrimary: draculaForeground, + primary: draculaPink, + outline: draculaSelection, + ), + floatingActionButtonTheme: const FloatingActionButtonThemeData( + backgroundColor: draculaPurple, + ), + appBarTheme: const AppBarTheme( + elevation: 0, + systemOverlayStyle: SystemUiOverlayStyle( + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.dark, + systemNavigationBarColor: Colors.black, + systemNavigationBarDividerColor: Colors.black, + systemNavigationBarIconBrightness: Brightness.light, + ), + iconTheme: IconThemeData(color: draculaPurple), + actionsIconTheme: IconThemeData(color: draculaOrange), + titleTextStyle: TextStyle( + color: draculaYellow, + fontSize: 20, + ), + ), + menuButtonTheme: MenuButtonThemeData( + style: ButtonStyle( + backgroundColor: WidgetStatePropertyAll(draculaGreen), + textStyle: WidgetStatePropertyAll( + const TextStyle(color: draculaRed), + ), + ), + ), + listTileTheme: ListTileThemeData( + titleTextStyle: ThemeData.dark().textTheme.titleMedium?.copyWith( + color: draculaYellow, + ), + subtitleTextStyle: ThemeData.dark().textTheme.bodyMedium?.copyWith( + color: draculaCyan, + ), + ), + canvasColor: Color(0xFF282828), + focusColor: draculaSelection, + ); + } } Color getSwitchColorThumb(Set states) { @@ -162,3 +289,32 @@ Color getSwitchTrackColor(Set states) { return const Color(0xFF353535); } + +Color getSwitchTrackDraculaColor(Set states) { + const Set interactiveStates = { + WidgetState.pressed, + WidgetState.hovered, + WidgetState.focused, + }; + + if (states.any(interactiveStates.contains)) { + return const Color(0xFF505050); + } + + if (states.contains(WidgetState.selected)) { + return Color(0xFFFF5555); + } + + return const Color(0xFF353535); +} + +const draculaBackground = Color(0xFF282A36); +const draculaForeground = Color(0xFFF8F8F2); +const draculaYellow = Color(0xFFF1FA8C); +const draculaRed = Color(0xFFFF5555); +const draculaPink = Color(0xFFFF79C6); +const draculaOrange = Color(0xFFFFB86C); +const draculaGreen = Color(0xFF50FA7B); +const draculaPurple = Color(0xFFBD93F9); +const draculaSelection = Color(0xFF44475A); +const draculaCyan = Color(0xFF8BE9FD); diff --git a/lib/whats_new/whats_new.dart b/lib/whats_new/whats_new.dart index d6d7d84b..06491912 100644 --- a/lib/whats_new/whats_new.dart +++ b/lib/whats_new/whats_new.dart @@ -1,6 +1,5 @@ import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:habo/constants.dart'; import 'package:habo/generated/l10n.dart'; import 'package:habo/settings/settings_manager.dart'; import 'package:introduction_screen/introduction_screen.dart'; @@ -37,23 +36,25 @@ class WhatsNew extends StatelessWidget { top: true, bottom: false, child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - S.of(context).whatsNewTitle, - style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold), - ), - if (version.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 4.0), - child: Text( - S.of(context).whatsNewVersion(version), - style: theme.textTheme.bodySmall?.copyWith( - color: theme.textTheme.bodySmall?.color?.withValues(alpha: 0.7), + mainAxisSize: MainAxisSize.min, + children: [ + Text( + S.of(context).whatsNewTitle, + style: + const TextStyle(fontSize: 24, fontWeight: FontWeight.bold), + ), + if (version.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 4.0), + child: Text( + S.of(context).whatsNewVersion(version), + style: theme.textTheme.bodySmall?.copyWith( + color: theme.textTheme.bodySmall?.color + ?.withValues(alpha: 0.7), + ), ), ), - ), - ], + ], ), ), bodyWidget: SafeArea( @@ -62,86 +63,69 @@ class WhatsNew extends StatelessWidget { top: false, bottom: false, child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row(children: [ - const Icon(Icons.push_pin_outlined, color: HaboColors.primary), - const SizedBox(width: 10), - Expanded( - child: Text( - S.of(context).featureNumericTitle, - style: theme.textTheme.titleMedium, - ), - ), - ]), - const SizedBox(height: 6), - Padding( - padding: const EdgeInsets.only(left: 34.0), - child: Text(S.of(context).featureNumericDesc), - ), - const SizedBox(height: 16), - - Row(children: [ - const Icon(Icons.link, color: HaboColors.primary), - const SizedBox(width: 10), - Expanded( - child: Text( - S.of(context).featureDeepLinksTitle, - style: theme.textTheme.titleMedium, + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row(children: [ + Icon(Icons.push_pin_outlined, + color: theme.colorScheme.primary), + const SizedBox(width: 10), + Expanded( + child: Text( + S.of(context).featureNumericTitle, + style: theme.textTheme.titleMedium, + ), ), + ]), + const SizedBox(height: 6), + Padding( + padding: const EdgeInsets.only(left: 34.0), + child: Text(S.of(context).featureNumericDesc), ), - ]), - const SizedBox(height: 6), - Padding( - padding: const EdgeInsets.only(left: 34.0), - child: Text(S.of(context).featureDeepLinksDesc), - ), - const SizedBox(height: 16), + const SizedBox(height: 16), - Row(children: [ - const Icon(Icons.category, color: HaboColors.primary), - const SizedBox(width: 10), - Expanded( - child: Text( - S.of(context).featureCategoriesTitle, - style: theme.textTheme.titleMedium, + Row(children: [ + Icon(Icons.link, color: theme.colorScheme.primary), + const SizedBox(width: 10), + Expanded( + child: Text( + S.of(context).featureDeepLinksTitle, + style: theme.textTheme.titleMedium, + ), ), + ]), + const SizedBox(height: 6), + Padding( + padding: const EdgeInsets.only(left: 34.0), + child: Text(S.of(context).featureDeepLinksDesc), ), - ]), - const SizedBox(height: 6), - Padding( - padding: const EdgeInsets.only(left: 34.0), - child: Text(S.of(context).featureCategoriesDesc), - ), - const SizedBox(height: 16), + const SizedBox(height: 16), - Row(children: [ - const Icon(Icons.inventory_2_outlined, color: HaboColors.primary), - const SizedBox(width: 10), - Expanded( - child: Text( - S.of(context).featureArchiveTitle, - style: theme.textTheme.titleMedium, + Row(children: [ + Icon(Icons.category, color: theme.colorScheme.primary), + const SizedBox(width: 10), + Expanded( + child: Text( + S.of(context).featureCategoriesTitle, + style: theme.textTheme.titleMedium, + ), ), + ]), + const SizedBox(height: 6), + Padding( + padding: const EdgeInsets.only(left: 34.0), + child: Text(S.of(context).featureCategoriesDesc), ), - ]), - const SizedBox(height: 6), - Padding( - padding: const EdgeInsets.only(left: 34.0), - child: Text(S.of(context).featureArchiveDesc), - ), - const SizedBox(height: 16), + const SizedBox(height: 16), - // Material You theme - Android only - if (!Platform.isIOS) ...[ Row(children: [ - const Icon(Icons.palette_outlined, color: HaboColors.primary), + Icon(Icons.inventory_2_outlined, + color: theme.colorScheme.primary), const SizedBox(width: 10), Expanded( child: Text( - S.of(context).featureMaterialYouTitle, + S.of(context).featureArchiveTitle, style: theme.textTheme.titleMedium, ), ), @@ -149,126 +133,151 @@ class WhatsNew extends StatelessWidget { const SizedBox(height: 6), Padding( padding: const EdgeInsets.only(left: 34.0), - child: Text(S.of(context).featureMaterialYouDesc), + child: Text(S.of(context).featureArchiveDesc), ), const SizedBox(height: 16), - ], - Row(children: [ - const Icon(Icons.volume_up_outlined, color: HaboColors.primary), - const SizedBox(width: 10), - Expanded( - child: Text( - S.of(context).featureSoundTitle, - style: theme.textTheme.titleMedium, + // Material You theme - Android only + if (!Platform.isIOS) ...[ + Row(children: [ + Icon(Icons.palette_outlined, + color: theme.colorScheme.primary), + const SizedBox(width: 10), + Expanded( + child: Text( + S.of(context).featureMaterialYouTitle, + style: theme.textTheme.titleMedium, + ), + ), + ]), + const SizedBox(height: 6), + Padding( + padding: const EdgeInsets.only(left: 34.0), + child: Text(S.of(context).featureMaterialYouDesc), ), - ), - ]), - const SizedBox(height: 6), - Padding( - padding: const EdgeInsets.only(left: 34.0), - child: Text(S.of(context).featureSoundDesc), - ), - const SizedBox(height: 16), + const SizedBox(height: 16), + ], - Row(children: [ - const Icon(Icons.lock_outline, color: HaboColors.primary), - const SizedBox(width: 10), - Expanded( - child: Text( - S.of(context).featureLockTitle, - style: theme.textTheme.titleMedium, + Row(children: [ + Icon(Icons.volume_up_outlined, + color: theme.colorScheme.primary), + const SizedBox(width: 10), + Expanded( + child: Text( + S.of(context).featureSoundTitle, + style: theme.textTheme.titleMedium, + ), ), + ]), + const SizedBox(height: 6), + Padding( + padding: const EdgeInsets.only(left: 34.0), + child: Text(S.of(context).featureSoundDesc), ), - ]), - const SizedBox(height: 6), - Padding( - padding: const EdgeInsets.only(left: 34.0), - child: Text(S.of(context).featureLockDesc), - ), - const SizedBox(height: 24), + const SizedBox(height: 16), - // Habo Sync Coming Soon - Container( - padding: const EdgeInsets.all(16.0), - decoration: BoxDecoration( - color: theme.colorScheme.surfaceContainerHighest, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: HaboColors.primary.withValues(alpha: 0.3), - width: 1, + Row(children: [ + Icon(Icons.lock_outline, color: theme.colorScheme.primary), + const SizedBox(width: 10), + Expanded( + child: Text( + S.of(context).featureLockTitle, + style: theme.textTheme.titleMedium, + ), ), + ]), + const SizedBox(height: 6), + Padding( + padding: const EdgeInsets.only(left: 34.0), + child: Text(S.of(context).featureLockDesc), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Icon(Icons.cloud_sync_outlined, color: HaboColors.primary), - const SizedBox(width: 10), - Expanded( - child: Text( - "Habo Sync", - style: theme.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.bold, - ), - ), - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: HaboColors.primary.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(12), - ), - child: Text( - S.of(context).haboSyncComingSoon, - style: theme.textTheme.bodySmall?.copyWith( - color: HaboColors.primary, - fontWeight: FontWeight.w600, - ), - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - S.of(context).haboSyncDescription, - style: theme.textTheme.bodyMedium, + const SizedBox(height: 24), + + // Habo Sync Coming Soon + Container( + padding: const EdgeInsets.all(16.0), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerHighest, + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.primary.withValues(alpha: 0.3), + width: 1, ), - const SizedBox(height: 12), - GestureDetector( - onTap: _launchHaboSync, - child: Row( + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( children: [ - Text( - S.of(context).haboSyncLearnMore, - style: theme.textTheme.bodyMedium?.copyWith( - color: HaboColors.primary, - decoration: TextDecoration.underline, - decorationColor: HaboColors.primary, + Icon(Icons.cloud_sync_outlined, + color: theme.colorScheme.primary), + const SizedBox(width: 10), + Expanded( + child: Text( + "Habo Sync", + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + ), ), ), - const SizedBox(width: 4), - const Icon( - Icons.open_in_new, - size: 16, - color: HaboColors.primary, + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: theme.colorScheme.primary + .withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + S.of(context).haboSyncComingSoon, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.primary, + fontWeight: FontWeight.w600, + ), + ), ), ], ), - ), - ], + const SizedBox(height: 8), + Text( + S.of(context).haboSyncDescription, + style: theme.textTheme.bodyMedium, + ), + const SizedBox(height: 12), + GestureDetector( + onTap: _launchHaboSync, + child: Row( + children: [ + Text( + S.of(context).haboSyncLearnMore, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.primary, + decoration: TextDecoration.underline, + decorationColor: theme.colorScheme.primary, + ), + ), + const SizedBox(width: 4), + Icon( + Icons.open_in_new, + size: 16, + color: theme.colorScheme.primary, + ), + ], + ), + ), + ], + ), ), - ), - ], + ], + ), ), ), - ), ), ]; return IntroductionScreen( pages: pages, - done: Text(S.of(context).done, style: const TextStyle(fontWeight: FontWeight.w600)), + done: Text(S.of(context).done, + style: const TextStyle(fontWeight: FontWeight.w600)), onDone: () { _markSeen(context); Navigator.of(context).maybePop(); @@ -280,7 +289,7 @@ class WhatsNew extends StatelessWidget { _markSeen(context); Navigator.of(context).maybePop(); }, - dotsDecorator: const DotsDecorator(activeColor: HaboColors.primary), + dotsDecorator: DotsDecorator(activeColor: theme.colorScheme.primary), ); } } diff --git a/lib/widgets/category_filter_row.dart b/lib/widgets/category_filter_row.dart index 55d14838..74af75ff 100644 --- a/lib/widgets/category_filter_row.dart +++ b/lib/widgets/category_filter_row.dart @@ -36,8 +36,10 @@ class CategoryFilterRow extends StatelessWidget { child: ListView.builder( key: ValueKey('cat-row-$themeSig'), scrollDirection: Axis.horizontal, - padding: const EdgeInsets.only(left: 16, right: 24), // Extra right padding - itemCount: habitsManager.allCategories.length + 1, // +1 for "All" chip + padding: const EdgeInsets.only( + left: 16, right: 24), // Extra right padding + itemCount: + habitsManager.allCategories.length + 1, // +1 for "All" chip itemBuilder: (context, index) { if (index == 0) { // "All" chip to show all habits @@ -46,9 +48,14 @@ class CategoryFilterRow extends StatelessWidget { padding: const EdgeInsets.only(right: 8), child: FilterChip( key: ValueKey('all-chip-$themeSig'), - label: const Text( + label: Text( 'All', - style: TextStyle(fontWeight: FontWeight.w600, color: Colors.grey), + style: theme.textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w600, + color: isSelected + ? theme.colorScheme.primary + : theme.colorScheme.onPrimary.withAlpha(150), + ), ), selected: isSelected, onSelected: (selected) { @@ -56,15 +63,16 @@ class CategoryFilterRow extends StatelessWidget { onCategorySelected(null); } }, - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - selectedColor: Theme.of(context).colorScheme.primaryContainer, - side: BorderSide( + side: BorderSide( color: isSelected - ? Theme.of(context).colorScheme.outline.withValues(alpha: 0.3) + ? Theme.of(context) + .colorScheme + .outline + .withValues(alpha: 0.3) : Colors.transparent, width: 1, ), - showCheckmark: false, + showCheckmark: false, ), ); } @@ -78,15 +86,19 @@ class CategoryFilterRow extends StatelessWidget { key: ValueKey('cat-${category.id}-$themeSig'), label: Text( category.title, - style: TextStyle( + style: theme.textTheme.bodyMedium?.copyWith( fontWeight: FontWeight.w600, - color: Colors.grey, + color: isSelected + ? theme.colorScheme.primary + : theme.colorScheme.onPrimary.withAlpha(150), ), ), avatar: Icon( category.icon, size: 18, - color: Colors.grey, + color: isSelected + ? theme.colorScheme.primary + : theme.colorScheme.onPrimary.withAlpha(150), ), selected: isSelected, onSelected: (selected) { @@ -96,14 +108,12 @@ class CategoryFilterRow extends StatelessWidget { onCategorySelected(null); } }, - backgroundColor: theme.scaffoldBackgroundColor, - selectedColor: theme.colorScheme.primaryContainer, side: BorderSide( - color: isSelected - ? theme.colorScheme.outline.withValues(alpha: 0.3) - : Colors.transparent, - width: 1, - ), + color: isSelected + ? theme.colorScheme.outline.withValues(alpha: 0.3) + : Colors.transparent, + width: 1, + ), showCheckmark: false, // pressElevation: 4, ), diff --git a/lib/widgets/progress_input_modal.dart b/lib/widgets/progress_input_modal.dart index 894d4a1a..d217ce0c 100644 --- a/lib/widgets/progress_input_modal.dart +++ b/lib/widgets/progress_input_modal.dart @@ -36,8 +36,8 @@ class _ProgressInputModalState extends State { super.initState(); _currentValue = widget.currentProgress; _textController = TextEditingController( - text: _currentValue.toStringAsFixed(_currentValue == _currentValue.roundToDouble() ? 0 : 1) - ); + text: _currentValue.toStringAsFixed( + _currentValue == _currentValue.roundToDouble() ? 0 : 1)); } @override @@ -48,8 +48,10 @@ class _ProgressInputModalState extends State { void _updateValue(double value) { setState(() { - _currentValue = value.clamp(0.0, widget.targetValue * 2); // Allow up to 200% completion - _textController.text = _currentValue.toStringAsFixed(_currentValue == _currentValue.roundToDouble() ? 0 : 1); + _currentValue = value.clamp( + 0.0, widget.targetValue * 2); // Allow up to 200% completion + _textController.text = _currentValue.toStringAsFixed( + _currentValue == _currentValue.roundToDouble() ? 0 : 1); }); } @@ -62,7 +64,8 @@ class _ProgressInputModalState extends State { } } - double get _progressPercentage => (_currentValue / widget.targetValue).clamp(0.0, 1.0); + double get _progressPercentage => + (_currentValue / widget.targetValue).clamp(0.0, 1.0); bool get _isCompleted => _currentValue >= widget.targetValue; bool get _isExceeded => _currentValue > widget.targetValue; @@ -83,8 +86,8 @@ class _ProgressInputModalState extends State { child: Text( widget.habitTitle, style: Theme.of(context).textTheme.headlineSmall?.copyWith( - fontWeight: FontWeight.bold, - ), + fontWeight: FontWeight.bold, + ), overflow: TextOverflow.ellipsis, maxLines: 1, softWrap: false, @@ -118,40 +121,59 @@ class _ProgressInputModalState extends State { animateFromLastPercent: true, percent: _progressPercentage, backgroundColor: Colors.transparent, - progressColor: _isExceeded ? Provider.of(context, listen: false).checkColor : - _isCompleted ? Provider.of(context, listen: false).checkColor : - Provider.of(context, listen: false).progressColor, + progressColor: _isExceeded + ? Provider.of(context, + listen: false) + .checkColor + : _isCompleted + ? Provider.of(context, + listen: false) + .checkColor + : Provider.of(context, + listen: false) + .progressColor, circularStrokeCap: CircularStrokeCap.round, ), ), // Progress text AnimatedSwitcher( - duration: Duration(milliseconds: 300), - transitionBuilder: (Widget child, Animation animation) { - return FadeTransition( - opacity: animation, - child: ScaleTransition( - scale: animation, - child: child, - ), - ); - }, - child: _isCompleted ? - Icon( - Icons.check, - color: Provider.of(context, listen: false).checkColor, - size: 50, - ) : - Text( - '${(_progressPercentage * 100).round()}%', - style: Theme.of(context).textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.bold, - color: _isCompleted - ? Provider.of(context, listen: false).checkColor - : Provider.of(context, listen: false).progressColor, - ), - ) - ), + duration: Duration(milliseconds: 300), + transitionBuilder: + (Widget child, Animation animation) { + return FadeTransition( + opacity: animation, + child: ScaleTransition( + scale: animation, + child: child, + ), + ); + }, + child: _isCompleted + ? Icon( + Icons.check, + color: Provider.of(context, + listen: false) + .checkColor, + size: 50, + ) + : Text( + '${(_progressPercentage * 100).round()}%', + style: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith( + fontWeight: FontWeight.bold, + color: _isCompleted + ? Provider.of( + context, + listen: false) + .checkColor + : Provider.of( + context, + listen: false) + .progressColor, + ), + )), ], ), ), @@ -168,7 +190,6 @@ class _ProgressInputModalState extends State { ), IconButton( icon: const Icon(Icons.edit_outlined), - color: Colors.grey, onPressed: () { setState(() { _useEdit = !_useEdit; @@ -180,17 +201,19 @@ class _ProgressInputModalState extends State { const SizedBox(height: 10), if (_useEdit) ...[ - Center( - child: TextField( - controller: _textController, - keyboardType: const TextInputType.numberWithOptions(decimal: true), - decoration: InputDecoration( - labelText: S.of(context).enterAmount, - suffixText: widget.unit, - border: const OutlineInputBorder(),), - onChanged: _onTextChanged, + Center( + child: TextField( + controller: _textController, + keyboardType: + const TextInputType.numberWithOptions(decimal: true), + decoration: InputDecoration( + labelText: S.of(context).enterAmount, + suffixText: widget.unit, + border: const OutlineInputBorder(), + ), + onChanged: _onTextChanged, + ), ), - ), ], // Input controls const SizedBox(height: 20), @@ -198,12 +221,16 @@ class _ProgressInputModalState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - _buildQuickButton('-${widget.partialValue.toStringAsFixed(widget.partialValue == widget.partialValue.roundToDouble() ? 0 : 1)}', - () => _updateValue(_currentValue - widget.partialValue), context), - _buildQuickButton('+${widget.partialValue.toStringAsFixed(widget.partialValue == widget.partialValue.roundToDouble() ? 0 : 1)}', - () => _updateValue(_currentValue + widget.partialValue), context), - _buildQuickButton(S.of(context).complete, - () => _updateValue(widget.targetValue), context), + _buildQuickButton( + '-${widget.partialValue.toStringAsFixed(widget.partialValue == widget.partialValue.roundToDouble() ? 0 : 1)}', + () => _updateValue(_currentValue - widget.partialValue), + context), + _buildQuickButton( + '+${widget.partialValue.toStringAsFixed(widget.partialValue == widget.partialValue.roundToDouble() ? 0 : 1)}', + () => _updateValue(_currentValue + widget.partialValue), + context), + _buildQuickButton(S.of(context).complete, + () => _updateValue(widget.targetValue), context), ], ), const SizedBox(height: 24), @@ -216,7 +243,8 @@ class _ProgressInputModalState extends State { onPressed: () => Navigator.of(context).pop(), style: TextButton.styleFrom( backgroundColor: Colors.transparent, - foregroundColor: Theme.of(context).textTheme.bodyMedium?.color, + foregroundColor: + Theme.of(context).textTheme.bodyMedium?.color, ), child: Text(S.of(context).cancel), ), @@ -227,13 +255,21 @@ class _ProgressInputModalState extends State { Navigator.of(context).pop(); }, style: ElevatedButton.styleFrom( - backgroundColor: _isCompleted - ? Provider.of(context, listen: false).checkColor - : Provider.of(context, listen: false).progressColor, + backgroundColor: _isCompleted + ? Provider.of(context, listen: false) + .checkColor + : Provider.of(context, listen: false) + .progressColor, ), child: Text( - _isCompleted ? S.of(context).complete : S.of(context).saveProgress, - style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold), + _isCompleted + ? S.of(context).complete + : S.of(context).saveProgress, + style: TextStyle( + color: + Provider.of(context, listen: false) + .iconColor, + fontWeight: FontWeight.bold), ), ), ], @@ -244,26 +280,27 @@ class _ProgressInputModalState extends State { ); } - Widget _buildQuickButton(String label, VoidCallback onPressed, BuildContext context) { - return ElevatedButton( - onPressed: onPressed, - style: ElevatedButton.styleFrom( - elevation: 2, - shadowColor: Theme.of(context).shadowColor, - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - backgroundColor: Theme.of(context).colorScheme.primaryContainer, - foregroundColor: Theme.of(context).textTheme.bodyMedium?.color, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), + Widget _buildQuickButton( + String label, VoidCallback onPressed, BuildContext context) { + return ElevatedButton( + onPressed: onPressed, + style: ElevatedButton.styleFrom( + elevation: 2, + shadowColor: Theme.of(context).shadowColor, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + backgroundColor: Theme.of(context).colorScheme.primaryContainer, + foregroundColor: Theme.of(context).textTheme.bodyMedium?.color, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), ), - ), - child: Text( - label, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, + child: Text( + label, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ), ), - ), - ); -} + ); + } } diff --git a/macos/Podfile.lock b/macos/Podfile.lock index f9247327..5a30416c 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -82,7 +82,7 @@ SPEC CHECKSUMS: dynamic_color: b820c000cc68df65e7ba7ff177cb98404ce56651 file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a flutter_soloud: cb69d77c6ca89760429201880cf416b72d4d0c6a - FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19 package_info_plus: f0052d280d17aa382b932f399edf32507174e870 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 7ef16fb0..5ee3d024 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -55,7 +55,7 @@ /* Begin PBXFileReference section */ 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* habo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = habo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* Habo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Habo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -112,7 +112,7 @@ 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( - 33CC10ED2044A3C60003C045 /* habo.app */, + 33CC10ED2044A3C60003C045 /* Habo.app */, ); name = Products; sourceTree = ""; @@ -159,7 +159,6 @@ 8AE137FCFDC1D9D46680EA93 /* Pods-Runner.release.xcconfig */, A3B0EF60408AB1FEA84129B3 /* Pods-Runner.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -193,7 +192,7 @@ ); name = Runner; productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* habo.app */; + productReference = 33CC10ED2044A3C60003C045 /* Habo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -405,7 +404,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -427,6 +426,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 14.6; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -484,7 +484,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -531,7 +531,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -553,6 +553,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 14.6; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -573,6 +574,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 14.6; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index f8ac3267..0f6d895a 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -15,7 +15,7 @@ @@ -31,7 +31,7 @@ @@ -55,7 +55,7 @@ @@ -72,7 +72,7 @@