Initial (redacted) commit.

This commit is contained in:
mustard 2024-08-26 00:34:20 +02:00
commit 655f8a036a
368 changed files with 20949 additions and 0 deletions

View file

@ -0,0 +1,42 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class ScaffoldWithBottomNavigationBar extends StatelessWidget {
const ScaffoldWithBottomNavigationBar({
required this.navigationShell,
Key? key,
}) : super(key: key ?? const ValueKey<String>('ScaffoldWithNavBar'));
final StatefulNavigationShell navigationShell;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(child: navigationShell),
bottomNavigationBar: BottomNavigationBar(
fixedColor: Theme.of(context).colorScheme.onPrimary,
backgroundColor: Theme.of(context).colorScheme.secondary,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.list),
label: 'Widget Wall',
),
BottomNavigationBarItem(
icon: Icon(Icons.dashboard),
label: 'Dashboard',
),
],
currentIndex: navigationShell.currentIndex,
onTap: (int index) => _onTap(context, index),
),
);
}
void _onTap(BuildContext context, int index) {
navigationShell.goBranch(
index,
initialLocation: index == navigationShell.currentIndex,
);
}
}

View file

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:habitrack_app/infrastructure/bottom_navigation.dart';
import 'package:habitrack_app/pages/dashboard_page.dart';
import 'package:habitrack_app/pages/widget_page.dart';
// navigators, root and each destination of bottom navigation bar
final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorWidgetWallKey =
GlobalKey<NavigatorState>(debugLabel: 'widgetWall');
final _shellNavigatorDashboardKey =
GlobalKey<NavigatorState>(debugLabel: 'dashboard');
const String _widgetWallPath = '/widgetWall';
const String _dashboardPath = '/dashboard';
final goRouter = GoRouter(
initialLocation: _widgetWallPath,
navigatorKey: _rootNavigatorKey,
debugLogDiagnostics: true,
routes: [
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
return ScaffoldWithBottomNavigationBar(
navigationShell: navigationShell,
);
},
branches: [
StatefulShellBranch(
navigatorKey: _shellNavigatorWidgetWallKey,
routes: [
GoRoute(
path: _widgetWallPath,
pageBuilder: (context, state) => const NoTransitionPage(
child: WidgetPage(),
),
),
],
),
StatefulShellBranch(
navigatorKey: _shellNavigatorDashboardKey,
routes: [
GoRoute(
path: _dashboardPath,
pageBuilder: (context, state) => const NoTransitionPage(
child: DashboardPage(),
),
),
],
),
],
),
],
);

View file

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
import 'package:habitrack_app/infrastructure/widget_wall/add_widget_menu.dart';
class AddWidgetButton extends StatelessWidget {
const AddWidgetButton({super.key});
@override
Widget build(BuildContext context) {
return OutlinedButton(
style: OutlinedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
),
onPressed: () => {
Navigator.push(
context,
MaterialPageRoute<dynamic>(
builder: (context) => const AddWidgetMenu(),
),
),
},
child: Icon(
Icons.add,
color: Theme.of(context).colorScheme.onPrimary,
),
);
}
}

View file

@ -0,0 +1,150 @@
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/infrastructure/widget_wall/items_controller.dart';
import 'package:habitrack_app/main.dart';
import 'package:habitrack_app/sembast/hydration.dart';
import 'package:habitrack_app/sembast/tasks_list.dart';
import 'package:habitrack_app/sembast/timer.dart';
//Add Widget to List- Button Class ######################################
class _AddWidgetToList extends ConsumerWidget {
const _AddWidgetToList({
required this.toAdd,
required this.buttonText,
required this.iconData,
});
final dynamic toAdd;
final String buttonText;
final IconData iconData;
void _buttonFunc(BuildContext context, WidgetRef ref) {
//ref.read(widgetListNotifierProvider.notifier).addWidget(toAdd());
//ref.read(homeControllerProvider).add()
ref.watch(homeControllerProvider).add(toAdd);
Navigator.pop(context);
logger.i('Button Func Called');
}
@override
Widget build(BuildContext context, WidgetRef ref) {
return Container(
alignment: Alignment.center,
margin: const EdgeInsets.symmetric(vertical: 4),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
boxShadow: [
BoxShadow(
color: const Color(0x00000000).withOpacity(0.25),
spreadRadius: 1,
blurRadius: 2,
),
],
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
width: 300,
child: TextButton(
onPressed: () => {_buttonFunc(context, ref)},
child: Row(
children: [
Icon(
iconData,
color: Theme.of(context).colorScheme.onPrimary,
),
Text(
buttonText,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
),
),
],
),
),
);
}
}
// AddWidgetMenu ##########################################################
class AddWidgetMenu extends StatelessWidget {
const AddWidgetMenu({super.key});
@override
Widget build(BuildContext context) {
//AddWidgetToList - Button-Instances #######################################
final addWaterWidget = _AddWidgetToList(
toAdd: Hydration(
createdOn: DateTime.now().toString(),
completedOn: '',
isVisible: true,
widgetType: 'Hydration',
name: AppLocalizations.of(context)!.waterWidget_defaultName,
button1Amount: 100,
button2Amount: 250,
goal: 2500,
current: 0,
isExpanded: false,
),
buttonText: AppLocalizations.of(context)!.addWidget_water,
iconData: Icons.local_drink,
);
final addCompoundTimerWidget = _AddWidgetToList(
toAdd: TimerItem(
widgetType: 'Timer',
name: AppLocalizations.of(context)!.timerWidget_defaultName,
current: 0,
goal: 90,
isExpanded: false,
createdOn: DateTime.now().toString(),
completedOn: '',
isVisible: true,
state: 'initial',
),
buttonText: AppLocalizations.of(context)!.addWidget_timer,
iconData: Icons.timer,
);
final addTaskWidget = _AddWidgetToList(
toAdd: TasksItem(
isVisible: true,
widgetType: 'TODO',
name: AppLocalizations.of(context)!.tasksWidget_defaultName,
isExpanded: false,
taskList: [],
completedTaskList: [],
),
buttonText: AppLocalizations.of(context)!.addWidget_tasks,
iconData: Icons.task,
);
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(
color: Theme.of(context).colorScheme.onPrimary,
),
title: Text(
AppLocalizations.of(context)!.addWidgetHeader,
textScaler: const TextScaler.linear(1.5),
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
),
),
backgroundColor: Theme.of(context).colorScheme.secondary,
foregroundColor: Theme.of(context).colorScheme.primary,
),
body: Container(
color: Theme.of(context).colorScheme.primaryContainer,
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
addWaterWidget,
addTaskWidget,
addCompoundTimerWidget,
],
),
),
);
}
}

View file

@ -0,0 +1,109 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart';
class DataPoint {
DataPoint({required this.date, required this.progress});
DateTime date;
double progress;
}
class GraphWidget extends ConsumerStatefulWidget {
GraphWidget({super.key});
@override
ConsumerState<ConsumerStatefulWidget> createState() => _GraphWidgetState();
final entries = <DataPoint>[
DataPoint(date: DateTime(2024, 7, 4), progress: 1),
DataPoint(date: DateTime(2024, 7, 5), progress: 0.5),
DataPoint(date: DateTime(2024, 7, 6), progress: 1.25),
DataPoint(date: DateTime(2024, 7, 7), progress: 0.75),
];
}
class _GraphWidgetState extends ConsumerState<GraphWidget> {
@override
Widget build(BuildContext context) {
final firstDate = widget.entries[0].date;
final flSpots = <FlSpot>[];
for (final dataPoint in widget.entries) {
final xValue = _daysBetween(firstDate, dataPoint.date).toDouble();
final lcbd = FlSpot(xValue, dataPoint.progress);
flSpots.add(lcbd);
}
final df = DateFormat('dd. MMMM');
return Column(
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.85,
height: MediaQuery.of(context).size.height * 0.5,
child: LineChart(
LineChartData(
minY: 0,
maxY: 1.5,
lineBarsData: [
LineChartBarData(spots: flSpots, isCurved: true),
],
gridData: const FlGridData(show: false),
extraLinesData: ExtraLinesData(
horizontalLines: [
HorizontalLine(
y: 1,
color: Colors.red,
),
],
),
titlesData: FlTitlesData(
rightTitles: const AxisTitles(
sideTitles: SideTitles(
reservedSize: 30,
interval: 20,
),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(
interval: 20,
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 30,
getTitlesWidget: (value, meta) => Text(value.toString()),
interval: 0.25,
),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
getTitlesWidget: (value, meta) => Text(
df.format(
DateTime(
firstDate.year,
firstDate.month,
firstDate.day,
).add(Duration(days: value.round())),
),
),
showTitles: true,
interval: 1,
),
),
),
),
),
),
const Text('You worked for X hours this past week'),
const Text('Out of a total of Y hours planned'),
],
);
}
int _daysBetween(DateTime from, DateTime to) {
final d1 = DateTime(from.year, from.month, from.day);
final d2 = DateTime(to.year, to.month, to.day);
return (d2.difference(d1).inHours / 24).round();
}
}

View file

@ -0,0 +1,27 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:habitrack_app/sembast/item_repository.dart';
import 'package:habitrack_app/sembast/sembast_item_repository.dart';
final homeControllerProvider = Provider(
(ref) => HomeController(
itemRepository: ref.watch(itemRepositoryProvider),
),
);
class HomeController {
HomeController({required this.itemRepository});
final ItemRepository itemRepository;
Future<void> delete(int id) async {
await itemRepository.deleteItem(id);
}
Future<void> edit(dynamic item) async {
await itemRepository.updateItem(item);
}
Future<void> add(dynamic newItem) async {
await itemRepository.insertItem(newItem);
}
}

View file

@ -0,0 +1,6 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:habitrack_app/sembast/sembast_item_repository.dart';
final itemsProvider = StreamProvider(
(ref) => ref.watch(itemRepositoryProvider).getAllItemsStream(),
);

View file

@ -0,0 +1,111 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:habitrack_app/function_widgets/compound_widgets/compound_timer_widget.dart';
import 'package:habitrack_app/function_widgets/compound_widgets/compound_widget_tasks.dart';
import 'package:habitrack_app/function_widgets/compound_widgets/compound_widget_water.dart';
import 'package:habitrack_app/infrastructure/widget_wall/add_widget_button.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/hydration.dart';
import 'package:habitrack_app/sembast/tasks_list.dart';
import 'package:habitrack_app/sembast/timer.dart';
/// Displays detailed information about a SampleItem.
class WidgetWall extends ConsumerStatefulWidget {
const WidgetWall({super.key});
@override
ConsumerState<WidgetWall> createState() => _WidgetWallState();
}
class _WidgetWallState extends ConsumerState<WidgetWall> {
Future<List<Widget>> buildList() async {
ref.watch(homeControllerProvider);
//var itemCount = 0;
final items = ref.watch(itemsProvider);
// ignore: unused_local_variable
final val = items.value;
return <Widget>[];
}
@override
Widget build(BuildContext context) {
// this.buildList();
final controller = ref.watch(itemsProvider);
switch (controller) {
case AsyncError(:final error):
return Text('Error: $error');
case AsyncData(:final value):
final allItems = value;
final items = <dynamic>[];
for (var i = 0; i < allItems.length; i++) {
// ignore: avoid_dynamic_calls
if (allItems.elementAt(i).isVisible == true) {
logger.i('INSERTING VISIBLE ITEM');
items.add(allItems.elementAt(i));
}
}
final itemWidgets = <Widget>[];
final itemCount = items.length;
for (var i = 0; i < itemCount; i++) {
final item = items.elementAt(i);
if (item is Hydration && item.isVisible) {
final itemwidget = CompoundWidgetWater(item: item);
itemWidgets.insert(i, itemwidget);
} else if (item is TimerItem && item.isVisible) {
if (item.isVisible == true) {
logger.i('VISIBLE');
final itemwidget = CompoundWidgetTimer(item: item);
itemWidgets.insert(i, itemwidget);
} else {
logger.i('IS NOT VISIBLE');
}
} else if (item is TasksItem && item.isVisible) {
final itemwidget = CompoundWidgetTasks(item: item);
itemWidgets.insert(i, itemwidget);
}
}
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(
color: Theme.of(context).colorScheme.onPrimary,
),
backgroundColor: Theme.of(context).colorScheme.secondary,
foregroundColor: Theme.of(context).colorScheme.primary,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
textScaler: const TextScaler.linear(2),
'Habitrack ',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onSecondary,
// fontStyle: FontStyle.italic,
),
),
const Align(
alignment: Alignment.topRight,
child: AddWidgetButton(),
),
],
),
),
body: ColoredBox(
color: Theme.of(context).colorScheme.primaryContainer,
child: ListView(
padding: const EdgeInsets.all(8),
children: itemWidgets,
),
),
);
default:
return const CircularProgressIndicator();
}
}
}