From fec696c48071c2436ef540ab8450e7cd25f68c89 Mon Sep 17 00:00:00 2001 From: RaHannes <128587611+RaHannes@users.noreply.github.com> Date: Tue, 4 Jul 2023 21:36:01 +0200 Subject: [PATCH] Profile and settings --- trackeroo/lib/app.dart | 67 +++--- trackeroo/lib/app_scaffold.dart | 90 ++++---- trackeroo/lib/frontend/utils/boxes.dart | 3 + .../lib/frontend/utils/category_chip.dart | 8 +- .../frontend/views/edit_settings_view.dart | 203 ++++++++++++++++++ .../lib/frontend/views/settings_views.dart | 155 +++++++++++++ trackeroo/lib/logic/models/local_String.dart | 37 ++++ trackeroo/lib/logic/models/profile.dart | 25 +++ trackeroo/lib/logic/models/profile.g.dart | 50 +++++ trackeroo/lib/logic/services/locator.dart | 139 ++++++++---- .../logic/services/profile_controller.dart | 20 ++ trackeroo/lib/main.dart | 3 +- trackeroo/pubspec.lock | 120 +++++++++++ trackeroo/pubspec.yaml | 2 + 14 files changed, 809 insertions(+), 113 deletions(-) create mode 100644 trackeroo/lib/frontend/utils/boxes.dart create mode 100644 trackeroo/lib/frontend/views/edit_settings_view.dart create mode 100644 trackeroo/lib/frontend/views/settings_views.dart create mode 100644 trackeroo/lib/logic/models/local_String.dart create mode 100644 trackeroo/lib/logic/models/profile.dart create mode 100644 trackeroo/lib/logic/models/profile.g.dart create mode 100644 trackeroo/lib/logic/services/profile_controller.dart diff --git a/trackeroo/lib/app.dart b/trackeroo/lib/app.dart index 1588070..c6b022c 100644 --- a/trackeroo/lib/app.dart +++ b/trackeroo/lib/app.dart @@ -4,11 +4,14 @@ import 'package:trackeroo/app_scaffold.dart'; import 'package:trackeroo/frontend/views/onboarding_view.dart'; import 'package:trackeroo/logic/services/app_state_controller.dart'; import 'package:trackeroo/logic/services/locator.dart'; +import 'package:get/get.dart'; +import 'package:trackeroo/logic/models/local_String.dart'; class MyApp extends StatelessWidget { MyApp({super.key}); - final AppStateController appStateController = locator.get<AppStateController>(); + final AppStateController appStateController = + locator.get<AppStateController>(); // This widget is the root of your application. @override @@ -18,37 +21,45 @@ class MyApp extends StatelessWidget { value: SystemUiOverlayStyle( systemNavigationBarColor: Colors.transparent, systemNavigationBarDividerColor: Colors.transparent, - systemNavigationBarIconBrightness: Theme.of(context).brightness == Brightness.dark ? Brightness.light : Brightness.dark, + systemNavigationBarIconBrightness: + Theme.of(context).brightness == Brightness.dark + ? Brightness.light + : Brightness.dark, systemNavigationBarContrastEnforced: true, statusBarColor: Colors.transparent, - statusBarIconBrightness: Theme.of(context).brightness == Brightness.dark ? Brightness.light : Brightness.dark, + statusBarIconBrightness: Theme.of(context).brightness == Brightness.dark + ? Brightness.light + : Brightness.dark, ), - child: Builder( - builder: (context) { - final lightColorScheme = ColorScheme.fromSeed(seedColor: const Color(0xFF0077B6)); - final darkColorScheme = ColorScheme.fromSeed( - seedColor: const Color(0xFF0077B6), + child: Builder(builder: (context) { + final lightColorScheme = + ColorScheme.fromSeed(seedColor: const Color(0xFF0077B6)); + final darkColorScheme = ColorScheme.fromSeed( + seedColor: const Color(0xFF0077B6), + brightness: Brightness.dark, + ); + return GetMaterialApp( + translations: LocalString(), + locale: Locale('en', 'US'), + debugShowCheckedModeBanner: false, + title: 'Flutter Demo', + theme: ThemeData( + colorScheme: lightColorScheme, + brightness: Brightness.light, + useMaterial3: true, + // textTheme: GoogleFonts.rubikTextTheme(ThemeData.light().textTheme) + ), + darkTheme: ThemeData( + colorScheme: darkColorScheme, brightness: Brightness.dark, - ); - return MaterialApp( - debugShowCheckedModeBanner: false, - title: 'Flutter Demo', - theme: ThemeData( - colorScheme: lightColorScheme, - brightness: Brightness.light, - useMaterial3: true, - // textTheme: GoogleFonts.rubikTextTheme(ThemeData.light().textTheme) - ), - darkTheme: ThemeData( - colorScheme: darkColorScheme, - brightness: Brightness.dark, - useMaterial3: true, - // textTheme: GoogleFonts.rubikTextTheme(ThemeData.dark().textTheme) - ), - home: appStateController.appState.isFirstOpening ? const OnboardingView() : const AppScaffold(), - ); - } - ), + useMaterial3: true, + // textTheme: GoogleFonts.rubikTextTheme(ThemeData.dark().textTheme) + ), + home: appStateController.appState.isFirstOpening + ? const OnboardingView() + : const AppScaffold(), + ); + }), ); } } diff --git a/trackeroo/lib/app_scaffold.dart b/trackeroo/lib/app_scaffold.dart index fe248ea..6c111b2 100644 --- a/trackeroo/lib/app_scaffold.dart +++ b/trackeroo/lib/app_scaffold.dart @@ -6,6 +6,7 @@ import 'package:trackeroo/frontend/views/details_view.dart'; import 'package:trackeroo/frontend/views/categories_view.dart'; import 'package:trackeroo/logic/services/locator.dart'; import 'package:trackeroo/logic/services/transactions_controller.dart'; +import 'package:trackeroo/frontend/views/settings_views.dart'; class AppScaffold extends StatefulWidget { const AppScaffold({Key? key}) : super(key: key); @@ -28,33 +29,32 @@ class _AppScaffoldState extends State<AppScaffold> { return Scaffold( appBar: AppBar( title: const Text('Trackeroo', - style: TextStyle( - fontSize: 24.0, - fontWeight: FontWeight.bold - ) - ), + style: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold)), elevation: 0.0, scrolledUnderElevation: 0.0, actions: [ IconButton.filledTonal( - onPressed: () => {}, - padding: const EdgeInsets.all(12.0), - icon: const Icon(Icons.person) - ), + onPressed: () => { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const SettingsView())) + }, + padding: const EdgeInsets.all(12.0), + icon: const Icon(Icons.person)), const SizedBox(width: 16.0) ], ), body: screens[index], bottomNavigationBar: NavigationBarTheme( data: NavigationBarThemeData( - backgroundColor: Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.3), + backgroundColor: + Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.3), indicatorColor: Theme.of(context).colorScheme.secondaryContainer, - labelTextStyle: MaterialStateProperty.all( - const TextStyle( - fontSize: 15.0, - fontWeight: FontWeight.w500, - ) - ), + labelTextStyle: MaterialStateProperty.all(const TextStyle( + fontSize: 15.0, + fontWeight: FontWeight.w500, + )), ), child: NavigationBar( height: 70, @@ -62,42 +62,44 @@ class _AppScaffoldState extends State<AppScaffold> { onDestinationSelected: (index) => setState(() => this.index = index), destinations: const [ NavigationDestination( - icon: Icon(Icons.home_outlined), - selectedIcon: Icon(Icons.home_rounded), - label: 'Home' - ), + icon: Icon(Icons.home_outlined), + selectedIcon: Icon(Icons.home_rounded), + label: 'Home'), NavigationDestination( - icon: Icon(Icons.bar_chart), - selectedIcon: Icon(Icons.bar_chart), - label: 'Details' - ), + icon: Icon(Icons.bar_chart), + selectedIcon: Icon(Icons.bar_chart), + label: 'Details'), NavigationDestination( - icon: Icon(Icons.category_outlined), - selectedIcon: Icon(Icons.category_rounded), - label: 'Category' - ) + icon: Icon(Icons.category_outlined), + selectedIcon: Icon(Icons.category_rounded), + label: 'Category') ], ), ), - floatingActionButton: locator.get<TransactionsController>().transactionsList.isNotEmpty ? FloatingActionButton( - onPressed: () => fabOnPressed(), - child: const Icon(Icons.add_rounded), - ) : FloatingActionButton.extended( - onPressed: () => fabOnPressed(), - label: Row( - children: [ - const Icon(Icons.add_rounded), - const SizedBox(width: 10.0), - Text(index == 2 ? 'add Category' : 'add Transaction') - ], - ) - ), + floatingActionButton: + locator.get<TransactionsController>().transactionsList.isNotEmpty + ? FloatingActionButton( + onPressed: () => fabOnPressed(), + child: const Icon(Icons.add_rounded), + ) + : FloatingActionButton.extended( + onPressed: () => fabOnPressed(), + label: Row( + children: [ + const Icon(Icons.add_rounded), + const SizedBox(width: 10.0), + Text(index == 2 ? 'add Category' : 'add Transaction') + ], + )), ); } + void fabOnPressed() { Navigator.push( - context, - MaterialPageRoute(builder: (context) => index == 2 ? const EditCategoryView() : const EditTransactionView()) - ); + context, + MaterialPageRoute( + builder: (context) => index == 2 + ? const EditCategoryView() + : const EditTransactionView())); } } diff --git a/trackeroo/lib/frontend/utils/boxes.dart b/trackeroo/lib/frontend/utils/boxes.dart new file mode 100644 index 0000000..d004dca --- /dev/null +++ b/trackeroo/lib/frontend/utils/boxes.dart @@ -0,0 +1,3 @@ +import 'package:hive/hive.dart'; + +late Box boxProfile; diff --git a/trackeroo/lib/frontend/utils/category_chip.dart b/trackeroo/lib/frontend/utils/category_chip.dart index 8e2e0bd..53b65d3 100644 --- a/trackeroo/lib/frontend/utils/category_chip.dart +++ b/trackeroo/lib/frontend/utils/category_chip.dart @@ -19,10 +19,10 @@ class CategoryChip extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Icon( - IconData(category.iconCodePoint, fontFamily: category.iconFontFamily), - size: 16.0, - color: Color(category.colorValue) - ), + IconData(category.iconCodePoint, + fontFamily: category.iconFontFamily), + size: 16.0, + color: Color(category.colorValue)), const SizedBox(width: 5.0), Text(category.title) ], diff --git a/trackeroo/lib/frontend/views/edit_settings_view.dart b/trackeroo/lib/frontend/views/edit_settings_view.dart new file mode 100644 index 0000000..c74b58f --- /dev/null +++ b/trackeroo/lib/frontend/views/edit_settings_view.dart @@ -0,0 +1,203 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:trackeroo/frontend/views/settings_views.dart'; +import 'package:trackeroo/logic/services/locator.dart'; +import '../../logic/models/profile.dart'; +import 'package:trackeroo/logic/services/profile_controller.dart'; +import 'package:image_picker/image_picker.dart'; +import 'dart:io'; +import 'package:flutter/services.dart'; + +class EditSettingsView extends StatefulWidget { + const EditSettingsView({super.key}); + + @override + State<EditSettingsView> createState() => _EditSettingsView(); +} + +class _EditSettingsView extends State<EditSettingsView> { + TextEditingController nameController = TextEditingController(); + TextEditingController numberController = TextEditingController(); + TextEditingController emailController = TextEditingController(); + String imageController = ''; + + Future<bool> _updateProfile() async { + if (nameController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('name cant be empty')), + ); + return false; + } + + if (numberController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Mobile Number cant be empty ')), + ); + return false; + } + + if (emailController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('E-Mail cant be empty ')), + ); + return false; + } + + if (imageController.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Choose a Picture')), + ); + return false; + } + + Profile profile = Profile( + name: nameController.text, + number: int.parse(numberController.text), + email: emailController.text, + imagePath: imageController, + ); + locator.get<ProfileController>().saveProfile(profile); + return true; + } + + File? _imageFile; + final ImagePicker _picker = ImagePicker(); + + Widget imageProfile() { + return Center( + child: Stack( + children: <Widget>[ + CircleAvatar( + radius: 80.0, + backgroundImage: _imageFile == null + ? const NetworkImage( + 'https://images.bild.de/64928bbc72f9093ee562d003/2265ccc3e85215843e55f38b5a7cdaf5,8321f2dd?w=992') + : FileImage(File(_imageFile!.path)) as ImageProvider<Object>?, + ), + Positioned( + bottom: 20.0, + right: 20.0, + child: InkWell( + onTap: () { + showModalBottomSheet( + context: context, + builder: ((builder) => bottomSheet()), + ); + }, + child: const Icon( + Icons.camera_alt, + color: Colors.teal, + size: 28, + )), + ) + ], + ), + ); + } + + void takePhoto(ImageSource source) async { + try { + final pickedFile = await _picker.pickImage( + source: source, + ); + if (pickedFile == null) return; + final pickedTemp = File(pickedFile.path); + setState(() { + this._imageFile = pickedTemp; + this.imageController = pickedTemp.path; + }); + } on PlatformException catch (e) { + print('Error$e'.tr); + } + } + + Widget bottomSheet() { + return Container( + height: 100, + width: MediaQuery.of(context).size.width, + margin: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 20, + ), + child: Column(children: <Widget>[ + Text( + 'ChoosePB'.tr, + style: const TextStyle( + fontSize: 20.0, + ), + ), + const SizedBox( + height: 20, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: <Widget>[ + TextButton.icon( + icon: const Icon(Icons.camera), + onPressed: () { + takePhoto(ImageSource.camera); + }, + label: Text('camera'.tr), + ), + TextButton.icon( + icon: const Icon(Icons.image), + onPressed: () { + takePhoto(ImageSource.gallery); + }, + label: Text('Gallery'.tr), + ) + ], + ) + ]), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('EP'.tr), + elevation: 0.0, + scrolledUnderElevation: 0.0, + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + imageProfile(), + const SizedBox( + height: 20, + ), + TextField( + controller: nameController, + decoration: InputDecoration( + border: const OutlineInputBorder(), + hintText: 'name'.tr, + )), + TextField( + controller: numberController, + keyboardType: TextInputType.number, + decoration: InputDecoration( + border: const OutlineInputBorder(), + hintText: 'Number'.tr, + ), + ), + TextField( + controller: emailController, + decoration: InputDecoration( + border: const OutlineInputBorder(), + hintText: 'email'.tr, + ), + ), + ElevatedButton( + onPressed: () async => + {if (await _updateProfile()) Navigator.pop(context)}, + child: Text('Save'.tr), + ) + ], + ), + ), + ); + } +} diff --git a/trackeroo/lib/frontend/views/settings_views.dart b/trackeroo/lib/frontend/views/settings_views.dart new file mode 100644 index 0000000..bb849e6 --- /dev/null +++ b/trackeroo/lib/frontend/views/settings_views.dart @@ -0,0 +1,155 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:trackeroo/frontend/views/edit_settings_view.dart'; +import 'package:trackeroo/logic/services/locator.dart'; +import 'package:trackeroo/logic/services/profile_controller.dart'; + +class SettingsView extends StatefulWidget { + const SettingsView({super.key}); + + @override + State<SettingsView> createState() => _SettingsView(); +} + +class _SettingsView extends State<SettingsView> { + final List locale = [ + {'name': 'Englisch', 'locale': const Locale('en', 'US')}, + {'name': 'Deutsch', 'locale': const Locale('de', 'DE')} + ]; + ProfileController profileController = locator.get<ProfileController>(); + + updatelanguage(Locale locale) { + Get.back(); + Get.updateLocale(locale); + } + + getImage(String path) { + String filePath = path.replaceFirst('file://', ''); + return filePath; + } + + biulddialog(BuildContext context) { + showDialog( + context: context, + builder: (builder) { + return AlertDialog( + title: Text('Lang'.tr), + content: SizedBox( + width: double.maxFinite, + child: ListView.separated( + shrinkWrap: true, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: GestureDetector( + onTap: () { + print(locale[index]['name']); + updatelanguage(locale[index]['locale']); + }, + child: Text(locale[index]['name'])), + ); + }, + separatorBuilder: (context, index) { + return const Divider( + color: Colors.blue, + ); + }, + itemCount: locale.length), + ), + ); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Profile'.tr), + elevation: 0.0, + scrolledUnderElevation: 0.0, + ), + body: ValueListenableBuilder( + valueListenable: profileController.profilBox.listenable(), + builder: (context, box, child) { + ProfileController profileController = + locator.get<ProfileController>(); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 48), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + CircleAvatar( + radius: 55, + backgroundColor: Colors.grey, + child: profileController.profile.imagePath.isNotEmpty + ? CircleAvatar( + radius: 53, + backgroundImage: FileImage(File(getImage( + profileController.profile.imagePath))), + ) + : const Icon(Icons.person), + ), + const SizedBox(height: 16), + Text( + 'name'.tr, + style: const TextStyle( + fontSize: 16, fontWeight: FontWeight.bold), + ), + Text( + locator.get<ProfileController>().profile.name, + style: const TextStyle(fontSize: 16), + ), + const SizedBox(height: 16), + Text( + 'Number'.tr, + style: const TextStyle( + fontSize: 16, fontWeight: FontWeight.bold), + ), + Text( + locator + .get<ProfileController>() + .profile + .number + .toString(), + style: const TextStyle(fontSize: 16), + ), + const SizedBox(height: 16), + Text( + 'email'.tr, + style: const TextStyle( + fontSize: 16, fontWeight: FontWeight.bold), + ), + Text( + locator.get<ProfileController>().profile.email, + style: const TextStyle(fontSize: 16), + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const EditSettingsView()), + ); + }, + child: Text('EP'.tr), + ), + Text('hello'.tr), + ElevatedButton( + onPressed: () { + biulddialog(context); + }, + child: Text('Lang'.tr), + ) + ], + ), + ), + ); + }), + ); + } +} diff --git a/trackeroo/lib/logic/models/local_String.dart b/trackeroo/lib/logic/models/local_String.dart new file mode 100644 index 0000000..76db96d --- /dev/null +++ b/trackeroo/lib/logic/models/local_String.dart @@ -0,0 +1,37 @@ +import 'package:get/get.dart'; + +class LocalString extends Translations { + @override + Map<String, Map<String, String>> get keys => { + 'en_US': { + 'hello': 'HELLO WORLS', + 'message': 'Welcome to shit', + 'Error': 'Failed to pick image:', + 'ChoosePB': 'Choose Profile Picture', + 'camera': 'Camera', + 'Gallery': 'Gallery', + 'EP': 'Edit Profile', + 'name': 'Name', + 'Number': 'Mobile number', + 'email': 'E-Mail', + 'Save': 'Save', + 'Lang': 'Select a language', + 'Profile': 'Profile', + }, + 'de_DE': { + 'hello': 'SERVUS', + 'message': 'das ist die Nachricht', + 'Error': 'Bild auswählen Fehlgeschlagen:', + 'ChoosePB': 'Wähle ein Profielbild Aus', + 'camera': 'Kamera', + 'Gallery': 'Alben', + 'EP': 'Profiel Bearbeiten', + 'name': 'Name', + 'Number': 'Handynummer', + 'email': 'E-Mail', + 'Save': 'Speichern', + 'Lang': 'Sprache einstellen', + 'Profile': 'Profil', + } + }; +} diff --git a/trackeroo/lib/logic/models/profile.dart b/trackeroo/lib/logic/models/profile.dart new file mode 100644 index 0000000..b69c5a2 --- /dev/null +++ b/trackeroo/lib/logic/models/profile.dart @@ -0,0 +1,25 @@ +import 'package:hive/hive.dart'; + +part 'profile.g.dart'; + +@HiveType(typeId: 1) +class Profile { + @HiveField(0) + String name; + + @HiveField(1) + int number; + + @HiveField(2) + String email; + + @HiveField(3) + String imagePath; + + Profile({ + required this.name, + required this.number, + required this.email, + required this.imagePath, + }); +} diff --git a/trackeroo/lib/logic/models/profile.g.dart b/trackeroo/lib/logic/models/profile.g.dart new file mode 100644 index 0000000..bcad61b --- /dev/null +++ b/trackeroo/lib/logic/models/profile.g.dart @@ -0,0 +1,50 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'profile.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class ProfileAdapter extends TypeAdapter<Profile> { + @override + final int typeId = 2; + + @override + Profile read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = <int, dynamic>{ + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return Profile( + name: fields[0] as String, + number: fields[1] as int, + email: fields[2] as String, + imagePath: fields[3] as String, + ); + } + + @override + void write(BinaryWriter writer, Profile obj) { + writer + ..writeByte(4) + ..writeByte(0) + ..write(obj.name) + ..writeByte(1) + ..write(obj.number) + ..writeByte(2) + ..write(obj.email) + ..writeByte(3) + ..write(obj.imagePath); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ProfileAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/trackeroo/lib/logic/services/locator.dart b/trackeroo/lib/logic/services/locator.dart index 17bde82..9537b62 100644 --- a/trackeroo/lib/logic/services/locator.dart +++ b/trackeroo/lib/logic/services/locator.dart @@ -12,6 +12,9 @@ import 'package:trackeroo/logic/models/transaction.dart'; import 'package:trackeroo/logic/services/app_state_controller.dart'; import 'package:trackeroo/logic/services/categories_controller.dart'; import 'package:trackeroo/logic/services/transactions_controller.dart'; +import 'package:trackeroo/logic/services/profile_controller.dart'; + +import '../models/profile.dart'; final locator = GetIt.instance; @@ -20,46 +23,96 @@ Future<void> setupLocatorService() async { var appStateBox = await Hive.openBox('app_state_box'); Map<dynamic, dynamic> appStateMap = appStateBox.toMap(); AppState appState = AppState( - isFirstOpening: appStateMap['is_first_opening'] ?? true, - detailsTransactionsFilter: appStateMap['details_transactions_filter'] ?? [] - ); - AppStateController appStateController = AppStateController(appStateBox: appStateBox, appState: appState); + isFirstOpening: appStateMap['is_first_opening'] ?? true, + detailsTransactionsFilter: + appStateMap['details_transactions_filter'] ?? []); + AppStateController appStateController = + AppStateController(appStateBox: appStateBox, appState: appState); locator.registerLazySingleton<AppStateController>(() => appStateController); // load categories from box and safe to list, make list available in get_it Box<Category> categoriesBox = await Hive.openBox<Category>('categories_box'); - if(appState.isFirstOpening) { + if (appState.isFirstOpening) { // create default categories categoriesBox.putAll({ - 'food_and_groceries': Category(id: 'food_and_groceries', title: 'Food & Groceries', iconCodePoint: selectableIcons[13].codePoint, colorValue: selectableColors['Sorta Sage']!.color.value), - 'transport_and_car': Category(id: 'transport_and_car', title: 'Transport & Car', iconCodePoint: selectableIcons[27].codePoint, colorValue: selectableColors['Pale Yellow']!.color.value), - 'healthcare_and_drug_stores': Category(id: 'healthcare_and_drug_stores', title: 'Healthcare & Drug Stores', iconCodePoint: selectableIcons[14].codePoint, colorValue: selectableColors['Terra Cotta']!.color.value), - 'shopping': Category(id: 'shopping', title: 'Shopping', iconCodePoint: selectableIcons[26].codePoint, colorValue: selectableColors['Ocean']!.color.value), - 'bars_and_restaurants': Category(id: 'bars_and_restaurants', title: 'Bars & Restaurants', iconCodePoint: selectableIcons[2].codePoint, colorValue: selectableColors['Coral']!.color.value), - 'family_and_friends': Category(id: 'family_and_friends', title: 'Family & Friends', iconCodePoint: selectableIcons[11].codePoint, colorValue: selectableColors['Caribean']!.color.value), - 'leisure_and_entertainment': Category(id: 'leisure_and_entertainment', title: 'Leisure & Entertainment', iconCodePoint: selectableIcons[18].codePoint, colorValue: selectableColors['Mint']!.color.value), - 'media_and_electronics': Category(id: 'media_and_electronics', title: 'Media & Electronics', iconCodePoint: selectableIcons[21].codePoint, colorValue: selectableColors['Dark Olive']!.color.value), - 'education': Category(id: 'education', title: 'Education', iconCodePoint: selectableIcons[6].codePoint, colorValue: selectableColors['Eucalyptus']!.color.value), - 'household_and_utilities': Category(id: 'household_and_utilities', title: 'Household & Utilities', iconCodePoint: selectableIcons[16].codePoint, colorValue: selectableColors['Salmon']!.color.value), - 'travel_and_holidays': Category(id: 'travel_and_holidays', title: 'Travel & Holidays', iconCodePoint: selectableIcons[34].codePoint, colorValue: selectableColors['Sorta Sage']!.color.value), - 'atm': Category(id: 'atm', title: 'ATM', iconCodePoint: selectableIcons[1].codePoint, colorValue: selectableColors['Warm Stone']!.color.value) + 'food_and_groceries': Category( + id: 'food_and_groceries', + title: 'Food & Groceries', + iconCodePoint: selectableIcons[13].codePoint, + colorValue: selectableColors['Sorta Sage']!.color.value), + 'transport_and_car': Category( + id: 'transport_and_car', + title: 'Transport & Car', + iconCodePoint: selectableIcons[27].codePoint, + colorValue: selectableColors['Pale Yellow']!.color.value), + 'healthcare_and_drug_stores': Category( + id: 'healthcare_and_drug_stores', + title: 'Healthcare & Drug Stores', + iconCodePoint: selectableIcons[14].codePoint, + colorValue: selectableColors['Terra Cotta']!.color.value), + 'shopping': Category( + id: 'shopping', + title: 'Shopping', + iconCodePoint: selectableIcons[26].codePoint, + colorValue: selectableColors['Ocean']!.color.value), + 'bars_and_restaurants': Category( + id: 'bars_and_restaurants', + title: 'Bars & Restaurants', + iconCodePoint: selectableIcons[2].codePoint, + colorValue: selectableColors['Coral']!.color.value), + 'family_and_friends': Category( + id: 'family_and_friends', + title: 'Family & Friends', + iconCodePoint: selectableIcons[11].codePoint, + colorValue: selectableColors['Caribean']!.color.value), + 'leisure_and_entertainment': Category( + id: 'leisure_and_entertainment', + title: 'Leisure & Entertainment', + iconCodePoint: selectableIcons[18].codePoint, + colorValue: selectableColors['Mint']!.color.value), + 'media_and_electronics': Category( + id: 'media_and_electronics', + title: 'Media & Electronics', + iconCodePoint: selectableIcons[21].codePoint, + colorValue: selectableColors['Dark Olive']!.color.value), + 'education': Category( + id: 'education', + title: 'Education', + iconCodePoint: selectableIcons[6].codePoint, + colorValue: selectableColors['Eucalyptus']!.color.value), + 'household_and_utilities': Category( + id: 'household_and_utilities', + title: 'Household & Utilities', + iconCodePoint: selectableIcons[16].codePoint, + colorValue: selectableColors['Salmon']!.color.value), + 'travel_and_holidays': Category( + id: 'travel_and_holidays', + title: 'Travel & Holidays', + iconCodePoint: selectableIcons[34].codePoint, + colorValue: selectableColors['Sorta Sage']!.color.value), + 'atm': Category( + id: 'atm', + title: 'ATM', + iconCodePoint: selectableIcons[1].codePoint, + colorValue: selectableColors['Warm Stone']!.color.value) }); } Map<dynamic, Category> categoriesMap = categoriesBox.toMap(); - CategoriesController categoriesController = CategoriesController( - catBox: categoriesBox, - categories: categoriesMap - ); - locator.registerLazySingleton<CategoriesController>(() => categoriesController); + CategoriesController categoriesController = + CategoriesController(catBox: categoriesBox, categories: categoriesMap); + locator + .registerLazySingleton<CategoriesController>(() => categoriesController); - Box<Transaction> transactionsBox = await Hive.openBox<Transaction>('transactions_box'); + Box<Transaction> transactionsBox = + await Hive.openBox<Transaction>('transactions_box'); // TODO: remove for prod, only here for dev/test purposes - if(appState.isFirstOpening) { + if (appState.isFirstOpening) { List<Transaction> transactionsFromJson = []; - final String response = await rootBundle.loadString('assets/data/transaction_data.json'); + final String response = + await rootBundle.loadString('assets/data/transaction_data.json'); final jsonList = await json.decode(response); - for(var json in jsonList) { + for (var json in jsonList) { transactionsFromJson.add(Transaction.fromJson(json)); } transactionsBox.addAll(transactionsFromJson); @@ -68,24 +121,38 @@ Future<void> setupLocatorService() async { double balance = 0; double income = 0; double expenses = 0; - for(Transaction tr in transactionsBox.values.toList()) { + for (Transaction tr in transactionsBox.values.toList()) { balance += tr.amount; - if(tr.amount.isNegative) { + if (tr.amount.isNegative) { expenses += tr.amount; } else { income += tr.amount; } } TransactionsController transactionsController = TransactionsController( - transactionsBox: transactionsBox, - transactionsList: transactionsBox.values.toList(), - balance: balance, - income: income, - expenses: expenses - ); + transactionsBox: transactionsBox, + transactionsList: transactionsBox.values.toList(), + balance: balance, + income: income, + expenses: expenses); + + Box<Profile> profileBox = await Hive.openBox('profileBox'); + Profile empty = Profile( + name: 'Max Musterman', + number: 0123456789, + email: 'MaxMusterman@gmail.com', + imagePath: ''); + if (appState.isFirstOpening) { + profileBox.put('profile', empty); + } + + ProfileController profileController = ProfileController( + profilBox: profileBox, profile: profileBox.get('profile') ?? empty); + + locator.registerLazySingleton<ProfileController>(() => profileController); // TODO: remove for prod, only here for dev/test purposes - - locator.registerLazySingleton<TransactionsController>(() => transactionsController); + locator.registerLazySingleton<TransactionsController>( + () => transactionsController); } diff --git a/trackeroo/lib/logic/services/profile_controller.dart b/trackeroo/lib/logic/services/profile_controller.dart new file mode 100644 index 0000000..b8048b0 --- /dev/null +++ b/trackeroo/lib/logic/services/profile_controller.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:hive/hive.dart'; +import 'package:trackeroo/logic/models/profile.dart'; + +class ProfileController extends ChangeNotifier { + ProfileController({required this.profilBox, required this.profile}); + + Box profilBox; + Profile profile; + + Future<void> saveProfile(Profile profile) async { + try { + this.profile = profile; + profilBox.put('profile', profile); + } catch (e) { + return; + } + return; + } +} diff --git a/trackeroo/lib/main.dart b/trackeroo/lib/main.dart index a9f3209..93706f2 100644 --- a/trackeroo/lib/main.dart +++ b/trackeroo/lib/main.dart @@ -4,7 +4,7 @@ import 'package:hive_flutter/hive_flutter.dart'; import 'package:trackeroo/logic/models/category.dart'; import 'package:trackeroo/logic/models/transaction.dart'; import 'package:trackeroo/logic/services/locator.dart'; - +import 'package:trackeroo/logic/models/profile.dart'; import 'package:trackeroo/app.dart'; void main() async { @@ -12,6 +12,7 @@ void main() async { await Hive.initFlutter(); Hive.registerAdapter(TransactionAdapter()); Hive.registerAdapter(CategoryAdapter()); + Hive.registerAdapter(ProfileAdapter()); await setupLocatorService(); runApp(MyApp()); } diff --git a/trackeroo/pubspec.lock b/trackeroo/pubspec.lock index f3723e6..e5efed2 100644 --- a/trackeroo/pubspec.lock +++ b/trackeroo/pubspec.lock @@ -161,6 +161,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + url: "https://pub.dev" + source: hosted + version: "0.3.3+4" crypto: dependency: transitive description: @@ -209,6 +217,38 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.4" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "770eb1ab057b5ae4326d1c24cc57710758b9a46026349d021d6311bd27580046" + url: "https://pub.dev" + source: hosted + version: "0.9.2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "7a6f1ae6107265664f3f7f89a66074882c4d506aef1441c9af313c1f7e6f41ce" + url: "https://pub.dev" + source: hosted + version: "0.9.3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "412705a646a0ae90f33f37acfae6a0f7cbc02222d6cd34e479421c3e74d3853c" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "1372760c6b389842b77156203308940558a2817360154084368608413835fc26" + url: "https://pub.dev" + source: hosted + version: "0.9.3" fixnum: dependency: transitive description: @@ -246,6 +286,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360" + url: "https://pub.dev" + source: hosted + version: "2.0.15" flutter_test: dependency: "direct dev" description: flutter @@ -264,6 +312,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.0" + get: + dependency: "direct main" + description: + name: get + sha256: "2ba20a47c8f1f233bed775ba2dd0d3ac97b4cf32fc17731b3dfc672b06b0e92a" + url: "https://pub.dev" + source: hosted + version: "4.6.5" get_it: dependency: "direct main" description: @@ -352,6 +408,70 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.17" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: b9603755b35253ccfad4be0762bb74d5e8bf9ff75edebf0ac3beec24fac1c5b5 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: d2bab152deb2547ea6f53d82ebca9b7e77386bb706e5789e815d37e08ea475bb + url: "https://pub.dev" + source: hosted + version: "0.8.7+3" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: b3e2f21feb28b24dd73a35d7ad6e83f568337c70afab5eabac876e23803f264b + url: "https://pub.dev" + source: hosted + version: "0.8.8" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "02cbc21fe1706b97942b575966e5fbbeaac535e76deef70d3a242e4afb857831" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: cee2aa86c56780c13af2c77b5f2f72973464db204569e1ba2dd744459a065af4 + url: "https://pub.dev" + source: hosted + version: "0.2.1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "7c7b96bb9413a9c28229e717e6fd1e3edd1cc5569c1778fcca060ecf729b65ee" + url: "https://pub.dev" + source: hosted + version: "2.8.0" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: c3066601ea42113922232c7b7b3330a2d86f029f685bba99d82c30e799914952 + url: "https://pub.dev" + source: hosted + version: "0.2.1" io: dependency: transitive description: diff --git a/trackeroo/pubspec.yaml b/trackeroo/pubspec.yaml index 5c1ec75..5edd83f 100644 --- a/trackeroo/pubspec.yaml +++ b/trackeroo/pubspec.yaml @@ -39,6 +39,8 @@ dependencies: flutter_colorpicker: ^1.0.3 rive: ^0.11.3 icons_launcher: ^2.1.2 + get: + image_picker: dev_dependencies: flutter_test: -- GitLab