habitrack/app/lib/function_widgets/compound_widgets/compound_timer_widget.dart
2024-08-26 00:34:20 +02:00

465 lines
16 KiB
Dart

//import 'dart:ffi';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:habitrack_app/function_widgets/widget_settings_menu/setting_entry.dart';
import 'package:habitrack_app/function_widgets/widget_settings_menu/widget_settings.dart';
import 'package:habitrack_app/infrastructure/widget_wall/items_controller.dart';
import 'package:habitrack_app/infrastructure/widget_wall/items_state.dart';
import 'package:habitrack_app/main.dart';
import 'package:habitrack_app/sembast/timer.dart';
import 'package:logger/logger.dart';
// ignore: must_be_immutable
class CompoundWidgetTimer extends ConsumerStatefulWidget {
CompoundWidgetTimer({required this.item, super.key});
TimerItem item;
double getProgress() {
return (item.current / item.goal) / 60;
}
@override
ConsumerState<CompoundWidgetTimer> createState() =>
_CompoundWidgetTimerState();
}
class _CompoundWidgetTimerState extends ConsumerState<CompoundWidgetTimer>
with WidgetsBindingObserver {
_CompoundWidgetTimerState();
String button1text = '';
Timer _timer = Timer(Duration.zero, () => ());
DateTime calcDue() {
final now = DateTime.now();
const secondsToAdd = 10;
const duration = Duration(seconds: secondsToAdd);
final futureTime = now.add(duration);
Logger().i(futureTime);
return DateTime.now();
}
void handleButton1() {
//start timer from 0
const oneSec = Duration(seconds: 1);
if (widget.item.state == 'initial') {
widget.item = widget.item.copyWith(state: 'running');
ref.watch(homeControllerProvider).edit(widget.item);
_timer = Timer.periodic(
oneSec,
(Timer funcTimer) {
if (widget.item.current == (widget.item.goal * 60)) {
setState(() {
final now = DateTime.now();
widget.item = widget.item.copyWith(
state: 'completed',
completedOn: now.toString(),
);
ref.watch(homeControllerProvider).edit(widget.item);
funcTimer.cancel();
});
} else {
setState(() {
widget.item =
widget.item.copyWith(current: widget.item.current + 1);
ref.watch(homeControllerProvider).edit(widget.item);
});
}
},
);
}
// continue timer
else if (widget.item.state == 'paused') {
widget.item = widget.item.copyWith(state: 'running');
ref.watch(homeControllerProvider).edit(widget.item);
_timer = Timer.periodic(
const Duration(seconds: 1),
(Timer funcTimer) {
if (widget.item.current == (widget.item.goal * 60)) {
setState(() {
final now = DateTime.now();
widget.item = widget.item.copyWith(
state: 'completed',
completedOn: now.toString(),
);
ref.watch(homeControllerProvider).edit(widget.item);
funcTimer.cancel();
});
} else {
setState(() {
widget.item =
widget.item.copyWith(current: widget.item.current + 1);
ref.watch(homeControllerProvider).edit(widget.item);
});
}
},
);
} else if (widget.item.state == 'running') {
widget.item = widget.item.copyWith(state: 'paused');
ref.watch(homeControllerProvider).edit(widget.item);
_timer.cancel();
} else if (widget.item.state == 'completed') {}
}
void stopTimer() {
setState(() {
if (_timer.isActive) {
_timer.cancel();
}
widget.item = widget.item.copyWith(
current: 0,
state: 'initial',
);
ref.watch(homeControllerProvider).edit(widget.item);
});
}
String _formatCurrent() {
final hours = (widget.item.current / 3600).floor();
final minutes = ((widget.item.current - (hours * 3600)) / 60).floor();
return '$hours hours : $minutes minutes';
}
String _formattedTime() {
final minutesTotal = widget.item.goal;
final hours = (minutesTotal / 60).floor();
final minutes = minutesTotal - (hours * 60);
return '$hours hours : $minutes minutes';
}
void _toggleExpansion() {
setState(() {
widget.item = widget.item.copyWith(isExpanded: !widget.item.isExpanded);
ref.watch(homeControllerProvider).edit(widget.item);
});
}
String _getButton1Text(BuildContext context) {
if (widget.item.state == 'initial') {
return AppLocalizations.of(context)!.timerWidget_buttonStart;
} else if (widget.item.state == 'running') {
return AppLocalizations.of(context)!.timerWidget_buttonPause;
} else if (widget.item.state == 'paused') {
return AppLocalizations.of(context)!.timerWidget_buttonContinue;
}
return 'Done';
}
@override
Widget build(BuildContext context) {
ref
..watch(homeControllerProvider)
..watch(itemsProvider);
return Container(
margin: const EdgeInsets.only(left: 10, top: 10, right: 10, bottom: 10),
padding: const EdgeInsets.only(left: 10, top: 15, right: 10, bottom: 15),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
borderRadius: const BorderRadius.all(Radius.circular(7)),
boxShadow: [
BoxShadow(
color: const Color(0x00000000).withOpacity(0.25),
spreadRadius: 2,
blurRadius: 5,
// changes position of shadow
),
],
),
width: double.infinity,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (!widget.item.isExpanded) ...[
Icon(
Icons.timer,
size: 20,
color: Theme.of(context).colorScheme.onPrimary,
),
Expanded(
flex: 2,
child: Container(
margin: const EdgeInsets.only(left: 10, right: 10),
height: 30,
child: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(5),
), // Rounded corners
child: LinearProgressIndicator(
value:
widget.getProgress(), // Progress value (0.0 - 1.0)
backgroundColor:
Colors.grey.withOpacity(0.5), // Background color
valueColor: const AlwaysStoppedAnimation<Color>(
Color(0xffA4E8FD),
), // Progress color
),
),
),
),
Expanded(
child: Text(
widget.item.name,
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimary,
// alignment: TextAlign.left,
),
),
),
],
if (widget.item.isExpanded) ...[
Expanded(
child: Text(
widget.item.name,
textScaler: const TextScaler.linear(2),
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimary,
// alignment: TextAlign.left,
),
),
),
Expanded(
flex: 0,
child: IconButton(
icon: Icon(
Icons.settings,
color: Theme.of(context).colorScheme.onPrimary,
),
onPressed: () => _showSettingsMenu(ref),
),
),
],
Expanded(
flex: 0,
child: IconButton(
icon: Icon(
widget.item.isExpanded
? Icons.arrow_drop_up_outlined
: Icons.arrow_drop_down_circle_outlined,
color: Theme.of(context).colorScheme.onPrimary,
),
onPressed: _toggleExpansion,
),
),
],
),
if (widget.item.isExpanded) ...[
// Additional child elements when expanded
SizedBox(
height: 300,
width: MediaQuery.of(context).size.width,
child: Column(
children: [
Stack(
children: <Widget>[
Container(
alignment: Alignment.center,
// color: Colors.blueAccent,
width: MediaQuery.of(context).size.width,
height: 250,
child: SizedBox(
height: 150,
// color: Colors.greenAccent,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
// ignore: lines_longer_than_80_chars
'${AppLocalizations.of(context)!.timerWidget_current}: ${_formatCurrent()} \n ${AppLocalizations.of(context)!.timerWidget_goal}: ${_formattedTime()}',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
color: Theme.of(context)
.colorScheme
.onPrimary,
),
),
],
),
),
),
Positioned(
top: 10,
left: MediaQuery.of(context).size.width * 0.15,
width: MediaQuery.of(context).size.width * 0.60,
height: 220,
child: CircularProgressIndicator(
color: Theme.of(context).colorScheme.onPrimary,
strokeWidth: 7,
value: widget.getProgress(),
semanticsLabel: 'Circular progress indicator',
),
),
],
),
Expanded(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: handleButton1,
child: Text(
_getButton1Text(context),
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
color: Theme.of(context)
.colorScheme
.onPrimary,
),
),
),
TextButton(
onPressed: stopTimer,
child: Text(
AppLocalizations.of(context)!
.timerWidget_buttonReset,
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
color: Theme.of(context)
.colorScheme
.onPrimary,
),
),
),
],
),
],
),
),
],
),
),
// Add more widgets here as needed
],
],
),
);
}
Future<void> _showSettingsMenu(WidgetRef ref) async {
logger.i('Opening settings');
final settingEntries = WidgetSettingsData(
entries: {
'name': SettingEntryText(
name: AppLocalizations.of(context)!.widgetSettings_name,
defaultValue: widget.item.name,
),
'duration': SettingEntryDuration(
name: AppLocalizations.of(context)!.timerWidgetSettings_duration,
defaultValue: widget.item.goal,
),
},
);
if (widget.item.state == 'running') {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
AppLocalizations.of(context)!.timerWidget_pausedForEdit,
),
),
);
} else {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
content: WidgetSettings(
entries: settingEntries,
),
actions: [
OutlinedButton(
style: OutlinedButton.styleFrom(
backgroundColor: Colors.red,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
onPressed: () async {
ref.watch(itemsProvider);
final items = ref.watch(homeControllerProvider);
widget.item = widget.item.copyWith(isVisible: false);
setState(() {
items.edit(widget.item);
});
logger.i('Attempting delete');
// ignore: use_build_context_synchronously
Navigator.of(context).pop();
},
child: Text(
AppLocalizations.of(context)!.widgetSettings_deleteButton,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
fontWeight: FontWeight.bold,
),
),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
backgroundColor: Theme.of(context).colorScheme.onPrimary,
),
onPressed: () {
_timer.cancel();
ref.watch(homeControllerProvider);
logger.i('Attempting edit of name and/or duration');
final name = settingEntries.getValue('name') as String;
logger.i('New name: $name');
final duration = settingEntries.getValue('duration') as int;
widget.item =
widget.item.copyWith(goal: duration, name: name);
setState(() {
ref.watch(homeControllerProvider).edit(widget.item);
});
logger.i('NAME AND DURATION SUCCESSFULLY UPDATED');
Navigator.of(context).pop();
},
child: Text(
AppLocalizations.of(context)!.widgetSettings_saveButton,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
),
),
),
],
);
},
);
}
}
}