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