mirror of
https://github.com/Dvorinka/1356.git
synced 2026-06-04 20:12:56 +00:00
Added core data models, repositories, and utilities
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppScaffold extends StatelessWidget {
|
||||
final String? title;
|
||||
final Widget body;
|
||||
final List<Widget>? actions;
|
||||
final Widget? floatingActionButton;
|
||||
final bool showBackButton;
|
||||
final VoidCallback? onBackPressed;
|
||||
final Widget? bottomNavigationBar;
|
||||
|
||||
const AppScaffold({
|
||||
super.key,
|
||||
this.title,
|
||||
required this.body,
|
||||
this.actions,
|
||||
this.floatingActionButton,
|
||||
this.showBackButton = false,
|
||||
this.onBackPressed,
|
||||
this.bottomNavigationBar,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: title != null
|
||||
? AppBar(
|
||||
title: Text(title!),
|
||||
centerTitle: true,
|
||||
automaticallyImplyLeading: showBackButton,
|
||||
leading: showBackButton
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: onBackPressed ?? () => Navigator.pop(context),
|
||||
)
|
||||
: null,
|
||||
actions: actions,
|
||||
)
|
||||
: null,
|
||||
body: SafeArea(child: body),
|
||||
floatingActionButton: floatingActionButton,
|
||||
bottomNavigationBar: bottomNavigationBar,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class BottomNavScaffold extends StatefulWidget {
|
||||
final Widget child;
|
||||
|
||||
const BottomNavScaffold({
|
||||
super.key,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BottomNavScaffold> createState() => _BottomNavScaffoldState();
|
||||
}
|
||||
|
||||
class _BottomNavScaffoldState extends State<BottomNavScaffold> {
|
||||
int _currentIndex = 0;
|
||||
|
||||
final List<NavigationDestination> _destinations = const [
|
||||
NavigationDestination(
|
||||
icon: Icon(Icons.home_outlined),
|
||||
selectedIcon: Icon(Icons.home),
|
||||
label: 'Home',
|
||||
),
|
||||
NavigationDestination(
|
||||
icon: Icon(Icons.flag_outlined),
|
||||
selectedIcon: Icon(Icons.flag),
|
||||
label: 'Goals',
|
||||
),
|
||||
NavigationDestination(
|
||||
icon: Icon(Icons.people_outline),
|
||||
selectedIcon: Icon(Icons.people),
|
||||
label: 'Social',
|
||||
),
|
||||
NavigationDestination(
|
||||
icon: Icon(Icons.person_outline),
|
||||
selectedIcon: Icon(Icons.person),
|
||||
label: 'Profile',
|
||||
),
|
||||
];
|
||||
|
||||
void _onDestinationSelected(int index) {
|
||||
setState(() {
|
||||
_currentIndex = index;
|
||||
});
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
context.go('/home');
|
||||
break;
|
||||
case 1:
|
||||
context.go('/goals');
|
||||
break;
|
||||
case 2:
|
||||
context.go('/social');
|
||||
break;
|
||||
case 3:
|
||||
context.go('/profile');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: widget.child,
|
||||
bottomNavigationBar: NavigationBar(
|
||||
selectedIndex: _currentIndex,
|
||||
onDestinationSelected: _onDestinationSelected,
|
||||
destinations: _destinations,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class EmptyState extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final String? subtitle;
|
||||
final String? actionLabel;
|
||||
final VoidCallback? onAction;
|
||||
|
||||
const EmptyState({
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
this.actionLabel,
|
||||
this.onAction,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(32.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: 80,
|
||||
color: Theme.of(context).colorScheme.primary.withOpacity(0.5),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
if (subtitle != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
subtitle!,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
if (actionLabel != null && onAction != null) ...[
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
onPressed: onAction,
|
||||
child: Text(actionLabel!),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LoadingIndicator extends StatelessWidget {
|
||||
final String? message;
|
||||
|
||||
const LoadingIndicator({
|
||||
super.key,
|
||||
this.message,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const CircularProgressIndicator(),
|
||||
if (message != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
message!,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user