Initial (redacted) commit.
This commit is contained in:
commit
655f8a036a
368 changed files with 20949 additions and 0 deletions
375
app/lib/function_widgets/widget_settings_menu/setting_entry.dart
Normal file
375
app/lib/function_widgets/widget_settings_menu/setting_entry.dart
Normal file
|
@ -0,0 +1,375 @@
|
|||
import 'package:duration_picker/duration_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:habitrack_app/main.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
abstract class SettingEntry extends StatefulWidget {
|
||||
const SettingEntry({required this.name, super.key});
|
||||
|
||||
final String name;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _SettingEntryState();
|
||||
|
||||
dynamic getValue() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
void setValue(dynamic newValue) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
class _SettingEntryState extends State<SettingEntry> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Text('Abstract, not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
// ###############################TEXT#########################################
|
||||
class SettingEntryText extends SettingEntry {
|
||||
SettingEntryText({
|
||||
required super.name,
|
||||
this.defaultValue = 'Some Text',
|
||||
super.key,
|
||||
}) {
|
||||
setValue(defaultValue);
|
||||
}
|
||||
|
||||
final TextEditingController valueController = TextEditingController();
|
||||
final String defaultValue;
|
||||
|
||||
@override
|
||||
State<SettingEntryText> createState() => _SettingEntryTextState();
|
||||
|
||||
@override
|
||||
String getValue() {
|
||||
logger.i('GETTING VALUE ${valueController.text}');
|
||||
return valueController.text;
|
||||
}
|
||||
|
||||
@override
|
||||
void setValue(dynamic newValue) {
|
||||
if (newValue is! String) {
|
||||
throw Exception('Value of SettingEntryText can only be a String!');
|
||||
}
|
||||
valueController.text = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
class _SettingEntryTextState extends State<SettingEntryText> {
|
||||
void monitorTextChange() {
|
||||
final text = widget.valueController.text;
|
||||
logger.i('TEXT: $text');
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// Start listening to changes.
|
||||
widget.valueController.addListener(monitorTextChange);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Clean up the controller when the widget is removed from the widget tree.
|
||||
// This also removes the _printLatestValue listener.
|
||||
widget.valueController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
alignment: AlignmentDirectional.bottomStart,
|
||||
margin: const EdgeInsets.only(top: 7.5, bottom: 7.5),
|
||||
|
||||
// color: Colors.black,
|
||||
child: Text(
|
||||
widget.name,
|
||||
textAlign: TextAlign.left,
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextField(
|
||||
keyboardType: TextInputType.text,
|
||||
controller: widget.valueController,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ###############################NUMERIC#######################################
|
||||
class SettingEntryNumeric extends SettingEntry {
|
||||
SettingEntryNumeric({required super.name, int defaultValue = 0, super.key}) {
|
||||
setValue(defaultValue);
|
||||
}
|
||||
|
||||
final TextEditingController valueController = TextEditingController();
|
||||
|
||||
@override
|
||||
State<SettingEntryNumeric> createState() => _SettingEntryNumericState();
|
||||
|
||||
@override
|
||||
int getValue() {
|
||||
return int.parse(valueController.text);
|
||||
}
|
||||
|
||||
@override
|
||||
void setValue(dynamic newValue) {
|
||||
if (newValue is! int) {
|
||||
throw Exception('Value of SettingEntryNumeric can only be an integer!');
|
||||
}
|
||||
valueController.text = newValue.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class _SettingEntryNumericState extends State<SettingEntryNumeric> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Text(widget.name),
|
||||
TextField(
|
||||
keyboardType: TextInputType.number,
|
||||
controller: widget.valueController,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ###############################SLIDER########################################
|
||||
class SettingEntrySlider extends SettingEntry {
|
||||
SettingEntrySlider({
|
||||
required this.topValue,
|
||||
required this.divisions,
|
||||
required super.name,
|
||||
double defaultValue = 0.0,
|
||||
super.key,
|
||||
}) {
|
||||
setValue(defaultValue);
|
||||
}
|
||||
|
||||
final double topValue;
|
||||
final int divisions;
|
||||
final value = DoubleSaver();
|
||||
|
||||
@override
|
||||
State<SettingEntrySlider> createState() => _SettingEntrySliderState();
|
||||
|
||||
@override
|
||||
double getValue() {
|
||||
return value.v;
|
||||
}
|
||||
|
||||
@override
|
||||
void setValue(dynamic newValue) {
|
||||
if (newValue is! double) {
|
||||
throw Exception('Value of SettingEntrySlider can only be a Double!');
|
||||
}
|
||||
value.v = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
class DoubleSaver {
|
||||
double v = 0;
|
||||
}
|
||||
|
||||
class _SettingEntrySliderState extends State<SettingEntrySlider> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
//Expanded(flex: 2, child: Text(widget.name)),
|
||||
Text(widget.name),
|
||||
Text(' ${widget.getValue()}'),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
const Text('0 '),
|
||||
Expanded(
|
||||
child: Slider(
|
||||
value: widget.getValue(),
|
||||
divisions: widget.divisions,
|
||||
max: widget.topValue,
|
||||
onChanged: sliderChange,
|
||||
),
|
||||
),
|
||||
Text(' ${widget.topValue}'),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void sliderChange(double newValue) {
|
||||
setState(() {
|
||||
widget.setValue(newValue);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// #############################DURATION#######################################
|
||||
|
||||
class IntSaver {
|
||||
IntSaver({this.v = 30});
|
||||
int v;
|
||||
}
|
||||
|
||||
class SettingEntryDuration extends SettingEntry {
|
||||
SettingEntryDuration({
|
||||
required super.name,
|
||||
required this.defaultValue,
|
||||
super.key,
|
||||
}) {
|
||||
val = IntSaver(v: defaultValue);
|
||||
}
|
||||
final int defaultValue;
|
||||
late final IntSaver val;
|
||||
|
||||
@override
|
||||
State<SettingEntryDuration> createState() => _SettingEntryDurationState();
|
||||
|
||||
@override
|
||||
int getValue() {
|
||||
return val.v;
|
||||
}
|
||||
|
||||
@override
|
||||
void setValue(dynamic newValue) {
|
||||
if (newValue is! int) {
|
||||
throw Exception('Value of SettingEntryDuration can only be a Double!');
|
||||
}
|
||||
val.v = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
class _SettingEntryDurationState extends State<SettingEntryDuration> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textCurrent =
|
||||
AppLocalizations.of(context)!.widgetSettings_durationPickerCurrent;
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
alignment: AlignmentDirectional.bottomStart,
|
||||
margin: const EdgeInsets.only(top: 7.5, bottom: 7.5),
|
||||
child: Text(
|
||||
'$textCurrent ${widget.getValue()}m',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
onPressed: () async {
|
||||
var resultingDuration = await showDurationPicker(
|
||||
context: context,
|
||||
initialTime: Duration(minutes: widget.val.v),
|
||||
);
|
||||
resultingDuration ??= Duration(minutes: widget.defaultValue);
|
||||
// ignore: use_build_context_synchronously
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Chose duration: ${resultingDuration.inMinutes}'),
|
||||
),
|
||||
);
|
||||
widget.setValue(resultingDuration.inMinutes);
|
||||
setState(() {});
|
||||
},
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.widgetSettings_durationPickerButton,
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ###############################DATE#########################################
|
||||
class DateSaver {
|
||||
DateTime v = DateTime.now();
|
||||
}
|
||||
|
||||
class SettingEntryDate extends SettingEntry {
|
||||
SettingEntryDate({required super.name, DateTime? defaultValue, super.key}) {
|
||||
this.defaultValue = defaultValue ?? DateTime.now();
|
||||
setValue(defaultValue);
|
||||
}
|
||||
|
||||
final date = DateSaver();
|
||||
|
||||
late final DateTime defaultValue;
|
||||
|
||||
@override
|
||||
State<SettingEntryDate> createState() => _SettingEntryDateState();
|
||||
|
||||
@override
|
||||
DateTime getValue() {
|
||||
return date.v;
|
||||
}
|
||||
|
||||
@override
|
||||
void setValue(dynamic newValue) {
|
||||
if (newValue is! DateTime) {
|
||||
throw Exception('Value of SettingEntryNumeric can only be a DateTime!');
|
||||
}
|
||||
date.v = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
class _SettingEntryDateState extends State<SettingEntryDate> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final dateFormat = DateFormat('dd. MMMM');
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
'${widget.name}: ${dateFormat.format(widget.date.v)} ',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: datePicker,
|
||||
child: const Text('Choose a date'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> datePicker() async {
|
||||
final pickedDate = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: widget.date.v, //get today's date
|
||||
firstDate: DateTime.now(),
|
||||
//DateTime.now() - not to allow to choose before today.
|
||||
lastDate: DateTime(2101),
|
||||
);
|
||||
final cleanDate = pickedDate ?? widget.date.v;
|
||||
widget.setValue(cleanDate);
|
||||
setState(() {});
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue