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

968 lines
32 KiB
Dart

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/tasks_list.dart';
import 'package:intl/intl.dart';
const seperator = '_SEPARATOR_';
// ignore: must_be_immutable
class IndividualTodoWidget extends ConsumerStatefulWidget {
IndividualTodoWidget({
required this.todo,
required this.due,
required this.completed,
required this.item,
required this.isVisible,
required this.createdOn,
required this.completedOn,
super.key,
});
late String todo;
late bool completed;
late DateTime due;
late DateTime createdOn;
late DateTime completedOn;
late TasksItem item;
late bool isVisible;
@override
ConsumerState<IndividualTodoWidget> createState() =>
_IndividualTodoWidgetState();
String stringRepr() {
return [
todo,
due.toString().substring(0, 10),
createdOn,
completedOn,
completed,
isVisible,
].join(seperator);
}
void deleteItem(WidgetRef ref) {
final searchTerm = stringRepr();
if (completed == true) {
final completedTaskList = <String>[...item.completedTaskList];
//search in completed tasks list
for (var i = 0; i < completedTaskList.length; i++) {
if (searchTerm == completedTaskList.elementAt(i)) {
var newItem = searchTerm;
final toConvert = newItem.split(seperator);
final todo = toConvert.elementAtOrNull(0)!;
final due = DateTime.parse(toConvert.elementAtOrNull(1)!);
final createdOn = DateTime.parse(toConvert.elementAtOrNull(2)!);
final completedOn = DateTime.parse(toConvert.elementAtOrNull(3)!);
final completed =
toConvert.elementAtOrNull(4)!.toLowerCase() == 'true';
final dateFormat = DateFormat('yyyy-MM-dd');
final formattedDate = dateFormat.format(due);
newItem = [
todo,
formattedDate.substring(0, 10),
createdOn,
completedOn,
completed,
false,
].join(seperator);
completedTaskList[i] = newItem;
final controller = ref.watch(homeControllerProvider);
item = item.copyWith(completedTaskList: completedTaskList);
controller.edit(item);
}
}
} else {
final taskList = <String>[...item.taskList];
for (var i = 0; i < taskList.length; i++) {
if (searchTerm == taskList.elementAt(i)) {
var newItem = searchTerm;
final toConvert = newItem.split(seperator);
final todo = toConvert.elementAtOrNull(0)!;
final due = DateTime.parse(toConvert.elementAtOrNull(1)!);
final createdOn = DateTime.parse(toConvert.elementAtOrNull(2)!);
final completedOn = DateTime.parse(toConvert.elementAtOrNull(3)!);
final completed =
toConvert.elementAtOrNull(4)!.toLowerCase() == 'true';
final dateFormat = DateFormat('yyyy-MM-dd');
final formattedDate = dateFormat.format(due);
newItem = [
todo,
formattedDate,
createdOn,
completedOn,
completed,
false,
].join(seperator);
taskList[i] = newItem;
final controller = ref.watch(homeControllerProvider);
item = item.copyWith(taskList: taskList);
controller.edit(item);
} else {}
}
}
}
bool overdue() {
final now = DateTime.now();
if (DateTime(now.year, now.month, now.day).isAfter(due)) {
return true;
}
return false;
}
}
class _IndividualTodoWidgetState extends ConsumerState<IndividualTodoWidget> {
_IndividualTodoWidgetState();
void _toggleChecked(bool? param) {
if (widget.overdue() && !widget.completed) {
} else {
final searchTerm = widget.stringRepr();
final completedTaskList = <String>[...widget.item.completedTaskList];
final taskList = <String>[...widget.item.taskList];
if (widget.completed == true) {
//search in completed tasks list
for (var i = 0; i < completedTaskList.length; i++) {
if (searchTerm == completedTaskList.elementAt(i)) {
widget.completed = !widget.completed;
final replacementStr = widget.stringRepr();
completedTaskList.removeAt(i);
taskList.add(replacementStr);
final controller = ref.watch(homeControllerProvider);
widget.item = widget.item.copyWith(
taskList: taskList,
completedTaskList: completedTaskList,
);
setState(() {
controller.edit(widget.item);
});
}
}
} else {
for (var i = 0; i < taskList.length; i++) {
if (searchTerm == taskList.elementAt(i)) {
widget.completed = !widget.completed;
// ignore: cascade_invocations
widget.completedOn = DateTime.now();
final replacementStr = widget.stringRepr();
taskList.removeAt(i);
completedTaskList.add(replacementStr);
final controller = ref.watch(homeControllerProvider);
widget.item = widget.item.copyWith(
taskList: taskList,
completedTaskList: completedTaskList,
);
setState(
() {
controller.edit(widget.item);
},
);
} else {}
}
}
setState(() {});
}
}
void _editItem(String oldItem, String itemToAdd) {
final completedTaskList = <String>[...widget.item.completedTaskList];
final taskList = <String>[...widget.item.taskList];
if (widget.completed == true) {
//search in completed tasks list
for (var i = 0; i < completedTaskList.length; i++) {
if (oldItem == completedTaskList.elementAt(i)) {
completedTaskList.replaceRange(i, i + 1, [itemToAdd]);
final controller = ref.watch(homeControllerProvider);
widget.item =
widget.item.copyWith(completedTaskList: completedTaskList);
setState(() {
controller.edit(widget.item);
});
}
}
} else {
for (var i = 0; i < taskList.length; i++) {
if (oldItem == taskList.elementAt(i)) {
taskList.replaceRange(i, i + 1, [itemToAdd]);
final controller = ref.watch(homeControllerProvider);
widget.item = widget.item.copyWith(taskList: taskList);
setState(
() {
controller.edit(widget.item);
},
);
} else {}
}
}
}
Future<void> _editPopup(String oldItem) async {
final todoFieldEditController = TextEditingController(text: widget.todo);
DateTime? date = widget.due;
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
title: Text(
AppLocalizations.of(context)!.tasksWidget_editTask,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimaryContainer,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
scrollable: true,
content: Column(
children: <Widget>[
TextField(
controller: todoFieldEditController,
decoration: InputDecoration(hintText: widget.todo),
autofillHints: null,
),
TextButton(
child: Text(
AppLocalizations.of(context)!.taskSettings_duePicker,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimaryContainer,
),
),
onPressed: () async {
final pickedDate = await showDatePicker(
context: context,
initialDate: widget.due,
firstDate: DateTime(2024, 0, 0),
lastDate: DateTime(2101),
);
date = pickedDate;
},
),
],
),
actions: <Widget>[
OutlinedButton(
style: OutlinedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
AppLocalizations.of(context)!.widgetSettings_cancelButton,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
onPressed: () {
date ??= widget.due;
if (todoFieldEditController.text.isEmpty) {
todoFieldEditController.text = widget.todo;
}
Navigator.of(context).pop();
final dateFormat = DateFormat('yyyy-MM-dd');
final formattedDate = dateFormat.format(date!);
final newItem = [
todoFieldEditController.text,
formattedDate,
widget.createdOn,
widget.completedOn,
widget.completed,
widget.isVisible,
].join(seperator);
_editItem(oldItem, newItem);
todoFieldEditController.clear();
},
child: Text(
AppLocalizations.of(context)!.widgetSettings_saveButton,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
final df = DateFormat('dd.MM.yyyy');
var dateText =
// ignore: lines_longer_than_80_chars
'${AppLocalizations.of(context)!.taskSettings_due}: ${df.format(widget.due)}';
var backgroundColor = Theme.of(context).colorScheme.secondary;
if (widget.overdue() && !widget.completed) {
dateText = AppLocalizations.of(context)!.tasksWidget_overdue;
backgroundColor = Theme.of(context).colorScheme.tertiary;
}
return Container(
margin: const EdgeInsets.symmetric(vertical: 2),
padding: const EdgeInsets.all(3),
width: 300,
decoration: BoxDecoration(
border: Border.all(
width: 1.5,
),
color: backgroundColor,
borderRadius: const BorderRadius.all(Radius.circular(7)),
boxShadow: [
BoxShadow(
color: const Color(0x00000000).withOpacity(0.25),
spreadRadius: 1,
blurRadius: 2,
),
],
),
child: Row(
children: [
Expanded(
flex: 0,
child: Checkbox(
activeColor: Colors.green,
fillColor: WidgetStateProperty.resolveWith(
(states) {
if (states.contains(WidgetState.selected)) {
return null;
}
return Theme.of(context).colorScheme.onSecondary;
},
),
value: widget.completed,
onChanged: _toggleChecked,
),
),
Expanded(
flex: 2,
child: Column(
children: [
Text(
widget.todo,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onSecondary,
),
),
Text(
dateText,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onSecondary,
),
),
],
),
),
Expanded(
flex: 0,
child: IconButton(
onPressed: () => _editPopup(widget.stringRepr()),
icon: Icon(
Icons.edit,
color: Theme.of(context).colorScheme.onSecondary,
),
),
),
Expanded(
flex: 0,
child: IconButton(
onPressed: () => setState(() {
widget.deleteItem(ref);
}),
icon: Icon(
Icons.delete,
color: Theme.of(context).colorScheme.onSecondary,
),
),
),
],
),
);
}
}
// ignore: must_be_immutable
class CompoundWidgetTasks extends ConsumerStatefulWidget {
CompoundWidgetTasks({required this.item, super.key});
TasksItem item;
double getProgress() {
if (item.completedTaskList.isNotEmpty) {
return item.completedTaskList.length /
(item.taskList.length + item.completedTaskList.length);
}
return 0;
}
@override
ConsumerState<CompoundWidgetTasks> createState() =>
_CompoundWidgetTasksState();
}
class _CompoundWidgetTasksState extends ConsumerState<CompoundWidgetTasks> {
final TextEditingController _todoFieldController = TextEditingController();
void _toggleExpansion() {
setState(() {
widget.item = widget.item.copyWith(isExpanded: !widget.item.isExpanded);
ref.watch(homeControllerProvider).edit(widget.item);
});
}
IndividualTodoWidget _todoFromString(String input) {
final toConvert = input.split(seperator);
final todo = toConvert.elementAtOrNull(0)!;
final due = DateTime.parse(toConvert.elementAtOrNull(1)!);
final createdOn = DateTime.parse(toConvert.elementAtOrNull(2)!);
final completedOn = DateTime.parse(toConvert.elementAtOrNull(3)!);
final completed = toConvert.elementAtOrNull(4)!.toLowerCase() == 'true';
final isVisible = toConvert.elementAt(5).toLowerCase() == 'true';
final newItem = IndividualTodoWidget(
todo: todo,
due: due,
completed: completed,
completedOn: completedOn,
item: widget.item,
isVisible: isVisible,
createdOn: createdOn,
);
return newItem;
}
List<Widget> _buildTodoList() {
final items = <IndividualTodoWidget>[];
final taskList = <String>[...widget.item.taskList];
final completedTaskList = <String>[...widget.item.completedTaskList];
taskList.sort(
(a, b) =>
DateTime.parse(a.split(seperator).elementAtOrNull(1)!).compareTo(
DateTime.parse(b.split(seperator).elementAtOrNull(1)!),
),
);
completedTaskList.sort(
(a, b) =>
DateTime.parse(a.split(seperator).elementAtOrNull(1)!).compareTo(
DateTime.parse(b.split(seperator).elementAtOrNull(1)!),
),
);
for (var i = 0; i < taskList.length; i++) {
final todoAsString = taskList.elementAt(i);
final newItem = _todoFromString(todoAsString);
if (newItem.isVisible) {
items.add(newItem);
}
}
for (var i = 0; i < completedTaskList.length; i++) {
final todoAsString = completedTaskList.elementAt(i);
final newItem = _todoFromString(todoAsString);
if (newItem.isVisible) {
items.add(newItem);
}
}
return items;
}
void _addItem(String toAdd) {
logger.i('ITEM TO ADD: $toAdd');
final controller = ref.watch(homeControllerProvider);
final toCopy = <String>[...widget.item.taskList];
// ignore: cascade_invocations
toCopy.add(toAdd);
widget.item = widget.item.copyWith(taskList: toCopy);
setState(() {
controller.edit(widget.item);
});
}
@override
Widget build(BuildContext context) {
ref.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),
//height: 100,
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.task,
size: 20,
color: Theme.of(context).colorScheme.onPrimary,
),
Expanded(
flex: 2,
child: Container(
margin: const EdgeInsets.only(left: 10, right: 10),
// Width of the progress bar
height: 30, // Height of the progress bar
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(
// fontSize: 12,
// fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
],
if (widget.item.isExpanded) ...[
Expanded(
child: Text(
widget.item.name,
textScaler: const TextScaler.linear(2),
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
Expanded(
flex: 0,
child: IconButton(
icon: Icon(
Icons.settings,
color: Theme.of(context).colorScheme.onPrimary,
),
onPressed: () => _showSettingsMenu(ref, context),
),
),
],
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,
),
//child: Icon(Icons.arrow_drop_down_circle_outlined),
),
],
),
if (widget.item.isExpanded) ...[
// Additional child elements when expanded
SizedBox(
width: MediaQuery.of(context).size.width,
child: Column(
children: [
Column(
children: [
OutlinedButton(
onPressed: _addPopup,
child: Row(
children: [
Icon(
Icons.add_task_outlined,
color: Theme.of(context).colorScheme.onPrimary,
),
Text(
// ignore: lines_longer_than_80_chars
' ${AppLocalizations.of(context)!.tasksWidget_addTaskButtonLabel}',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
color:
Theme.of(context).colorScheme.onPrimary,
),
),
],
),
),
ListView(
padding: const EdgeInsets.symmetric(vertical: 5),
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
children: _buildTodoList(),
),
if (anyTasksCompleted()) ...[
OutlinedButton(
onPressed: _deleteCompletedTasks,
child: Text(
AppLocalizations.of(context)!
.tasksWidget_deleteDone,
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
color:
Theme.of(context).colorScheme.onPrimary,
),
),
),
],
/* if (anyTasksOverdue()) ...[
OutlinedButton(
onPressed: _rescheduleOverdueTasks,
child: Text(
AppLocalizations.of(context)!
.tasksWidget_rescheduleOverdue,
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
color:
Theme.of(context).colorScheme.onPrimary,
),
),
),
],*/
],
),
],
),
),
],
],
),
);
}
bool anyTasksCompleted() {
for (final item in widget.item.completedTaskList) {
final toConvert = item.split(seperator);
final isVisible = toConvert.elementAt(5).toLowerCase() == 'true';
if (isVisible) {
return true;
}
}
return false;
}
void _deleteCompletedTasks() {
final controller = ref.watch(homeControllerProvider);
final newCompletedTaskList = <String>[]; // widget.item.completedTaskList;
for (final itemString in widget.item.completedTaskList) {
final oldItem = _todoFromString(itemString);
final dateFormat = DateFormat('yyyy-MM-dd');
final newItem = [
oldItem.todo,
dateFormat.format(oldItem.due),
oldItem.createdOn,
oldItem.completedOn,
oldItem.completed,
false,
].join(seperator);
newCompletedTaskList.add(newItem);
}
widget.item = widget.item.copyWith(completedTaskList: newCompletedTaskList);
controller.edit(widget.item);
}
bool anyTasksOverdue() {
final taskList = <String>[...widget.item.taskList];
for (final taskString in taskList) {
if (_todoFromString(taskString).overdue()) {
return true;
}
}
return false;
}
// Used for the Reschedule Task Button
// ignore: unused_element
void _rescheduleOverdueTasks() {
final taskList = <String>[...widget.item.taskList];
for (var i = 0; i < taskList.length; i++) {
final taskString = taskList[i];
if (_todoFromString(taskString).overdue()) {
final oldItem = _todoFromString(taskString);
final now = DateTime.now();
final newItem = IndividualTodoWidget(
todo: oldItem.todo,
due: DateTime(now.year, now.month, now.day),
createdOn: DateTime.now(),
completedOn: DateTime.now(),
completed: oldItem.completed,
item: widget.item,
isVisible: true,
);
taskList.replaceRange(i, i + 1, [newItem.stringRepr()]);
final controller = ref.watch(homeControllerProvider);
widget.item = widget.item.copyWith(taskList: taskList);
setState(
() {
controller.edit(widget.item);
},
);
}
}
}
Future<void> _addPopup() async {
DateTime? date = DateTime.now();
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
title: Text(
AppLocalizations.of(context)!.tasksWidget_addTaskButtonLabel,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimaryContainer,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
scrollable: true,
content: Column(
children: <Widget>[
TextField(
controller: _todoFieldController,
autofillHints: null,
decoration: InputDecoration(
hintText: AppLocalizations.of(context)!.taskSettings_name,
),
),
TextButton(
child: Text(
AppLocalizations.of(context)!.taskSettings_duePicker,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimaryContainer,
),
),
onPressed: () async {
final pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(), //get today's date
firstDate: DateTime.now(),
//DateTime.now() - not to allow to choose before today
lastDate: DateTime(2101),
);
date = pickedDate;
},
),
],
),
actions: <Widget>[
OutlinedButton(
style: OutlinedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
AppLocalizations.of(context)!.widgetSettings_cancelButton,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
onPressed: () {
//DateTime due = DateTime.parse(formattedDate);
// ignore: cascade_invocations
if (_todoFieldController.text.isEmpty) {
_todoFieldController.text = 'todo';
}
if (date != null && _todoFieldController.text.isNotEmpty) {
final dateFormat = DateFormat('yyyy-MM-dd');
final formattedDate = dateFormat.format(date!);
Navigator.of(context).pop();
final itemToAdd = [
_todoFieldController.text,
formattedDate,
DateTime.now(),
DateTime.now(),
false,
true,
].join(seperator);
_addItem(itemToAdd);
_todoFieldController.clear();
}
},
child: Text(
AppLocalizations.of(context)!.widgetSettings_saveButton,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
],
);
},
);
}
Future<void> _showSettingsMenu(WidgetRef ref, BuildContext context) async {
final settingEntries = WidgetSettingsData(
entries: {
'name': SettingEntryText(
name: AppLocalizations.of(context)!.widgetSettings_name,
defaultValue: widget.item.name,
),
},
);
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: () {
ref
.watch(homeControllerProvider)
.edit(widget.item.copyWith(isVisible: false));
// await controller.delete(widget.item.id);
// 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),
),
),
onPressed: () {
final controller = ref.watch(homeControllerProvider);
final name = settingEntries.getValue('name') as String;
widget.item = widget.item.copyWith(name: name);
setState(() {
widget.item = widget.item.copyWith(name: name);
controller.edit(widget.item);
});
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,
),
),
),
],
);
},
);
}
}