Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/constants.dart
Original file line number Diff line number Diff line change
@@ -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 }

Expand Down
1 change: 1 addition & 0 deletions lib/generated/l10n.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

169 changes: 93 additions & 76 deletions lib/habits/edit_habit_screen.dart

Large diffs are not rendered by default.

94 changes: 54 additions & 40 deletions lib/habits/habit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
};
}
Expand Down Expand Up @@ -112,9 +115,10 @@ class Habit extends StatefulWidget {
SplayTreeMap<DateTime, List> result = SplayTreeMap<DateTime, List>();

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;
Expand Down Expand Up @@ -184,9 +188,10 @@ class HabitState extends State<Habit> {
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<SettingsManager>(context, listen: false).checkColor,
behavior: SnackBarBehavior.floating,
),
);
Expand All @@ -207,7 +212,7 @@ class HabitState extends State<Habit> {
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<SettingsManager>(context, listen: false).failColor,
Expand Down Expand Up @@ -389,24 +394,26 @@ class HabitState extends State<Habit> {

Color _getEventColor(List events) {
final eventType = events[0] as DayType;

switch (eventType) {
case DayType.check:
return Provider.of<SettingsManager>(context, listen: false).checkColor;
return Provider.of<SettingsManager>(context).checkColor;
case DayType.fail:
return Provider.of<SettingsManager>(context, listen: false).failColor;
return Provider.of<SettingsManager>(context).failColor;
case DayType.skip:
return Provider.of<SettingsManager>(context, listen: false).skipColor;
return Provider.of<SettingsManager>(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<SettingsManager>(context, listen: false).checkColor;
return Provider.of<SettingsManager>(context, listen: false)
.checkColor;
}
}
return Provider.of<SettingsManager>(context, listen: false).progressColor;
return Provider.of<SettingsManager>(context, listen: false)
.progressColor;
case DayType.clear:
default:
return Colors.transparent;
Expand All @@ -415,32 +422,32 @@ class HabitState extends State<Habit> {

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<SettingsManager>(context).iconColor,
);
case DayType.fail:
return const Icon(
return Icon(
Icons.close,
color: Colors.white,
color: Provider.of<SettingsManager>(context).iconColor,
);
case DayType.skip:
return const Icon(
return Icon(
Icons.last_page,
color: Colors.white,
color: Provider.of<SettingsManager>(context).iconColor,
);
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 icon
return const Icon(
return Icon(
Icons.check,
color: Colors.white,
color: Provider.of<SettingsManager>(context).iconColor,
);
}
}
Expand All @@ -455,8 +462,9 @@ class HabitState extends State<Habit> {
// 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(
Expand All @@ -466,16 +474,19 @@ class HabitState extends State<Habit> {
child: CircularProgressIndicator(
value: percentage,
strokeWidth: 3,
backgroundColor: Colors.white.withValues(alpha: 0.3),
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
backgroundColor: Provider.of<SettingsManager>(context)
.progressColor
.withValues(alpha: 0.3),
valueColor: AlwaysStoppedAnimation<Color>(
Provider.of<SettingsManager>(context).iconColor),
),
),
),
Center(
child: Text(
'${(percentage * 100).round()}%',
style: const TextStyle(
color: Colors.white,
style: TextStyle(
color: Provider.of<SettingsManager>(context).iconColor,
fontSize: 8,
fontWeight: FontWeight.bold,
),
Expand Down Expand Up @@ -516,11 +527,12 @@ class HabitState extends State<Habit> {
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!);
}

Expand All @@ -537,9 +549,10 @@ class HabitState extends State<Habit> {
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;
Expand All @@ -550,8 +563,9 @@ class HabitState extends State<Habit> {
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;
}

Expand Down
17 changes: 11 additions & 6 deletions lib/habits/habit_header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -32,7 +33,7 @@ class HabitHeader extends StatelessWidget {
child: Text(
Provider.of<HabitsManager>(context)
.getNameOfHabit(widget.habitData.id!),
style: const TextStyle(fontSize: 20),
style: Theme.of(context).textTheme.titleLarge,
overflow: TextOverflow.ellipsis,
),
),
Expand All @@ -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);
Expand All @@ -61,10 +61,13 @@ class HabitHeader extends StatelessWidget {
border: Border.all(
color: (_orangeStreak)
? HaboColors.orange
: HaboColors.primary,
: Provider.of<SettingsManager>(context, listen: false)
.checkColor,
),
color:
(_orangeStreak) ? HaboColors.orange : HaboColors.primary,
color: (_orangeStreak)
? HaboColors.orange
: Provider.of<SettingsManager>(context, listen: false)
.checkColor,
borderRadius: const BorderRadius.all(Radius.circular(20)),
boxShadow: [
BoxShadow(
Expand All @@ -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<SettingsManager>(context).iconColor),
),
),
),
Expand Down
3 changes: 1 addition & 2 deletions lib/habits/habits_screen.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -192,7 +191,7 @@ class _HabitsScreenState extends State<HabitsScreen> {
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()
Expand Down
44 changes: 23 additions & 21 deletions lib/habits/one_day_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ class OneDayButton extends StatelessWidget {
key: const Key('Plus'),
icon: Icon(
Icons.add,
color: Provider.of<SettingsManager>(context, listen: false).progressColor,
color: Provider.of<SettingsManager>(context, listen: false)
.progressColor,
semanticLabel: 'Add Progress',
),
),
Expand Down Expand Up @@ -120,21 +121,21 @@ class OneDayButton extends StatelessWidget {
child: Container(
alignment: Alignment.center,
child: DropdownButton<InButton>(
iconSize: 0,
elevation: 3,
alignment: Alignment.center,
borderRadius: BorderRadius.circular(10.0),
underline: Container(),
items: icons.map(
(InButton value) {
return DropdownMenuItem<InButton>(
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<InButton>(
key: value.key,
value: value,
child: Center(child: value),
);
},
).toList(),
value: icons[index],
onTap: () {
parent.setSelectedDay(date);
},
Expand All @@ -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<SettingsManager>(context, listen: false)
.playCheckSound();
// Complete the habit with full target value
Expand Down Expand Up @@ -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<HabitsManager>(context, listen: false).addEvent(
Expand Down Expand Up @@ -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) {
Expand All @@ -276,7 +278,7 @@ class OneDayButton extends StatelessWidget {
Provider.of<HabitsManager>(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);
Expand All @@ -286,7 +288,7 @@ class OneDayButton extends StatelessWidget {
Provider.of<SettingsManager>(context, listen: false)
.playClickSound();
}

callback();
},
);
Expand Down
Loading