From bf81680b564c9e31bb9bc919768fca39a610538d Mon Sep 17 00:00:00 2001
From: Kima <kimavideos97@gmail.com>
Date: Sun, 4 Feb 2024 22:54:32 +0100
Subject: [PATCH] progress in new theme sharing

---
 filcnaplo/lib/database/init.dart              |   2 +
 filcnaplo/lib/models/settings.dart            |  38 ++-
 .../lib/providers/share_provider.dart         |   4 +-
 .../settings/settings_screen.i18n.dart        |  12 +
 .../screens/settings/submenu/paint_list.dart  | 250 +++++++++++++++++-
 .../lib/screens/settings/theme_screen.dart    |  36 ++-
 6 files changed, 313 insertions(+), 29 deletions(-)

diff --git a/filcnaplo/lib/database/init.dart b/filcnaplo/lib/database/init.dart
index 1d0fe2a..d384229 100644
--- a/filcnaplo/lib/database/init.dart
+++ b/filcnaplo/lib/database/init.dart
@@ -35,6 +35,8 @@ const settingsDB = DatabaseStruct("settings", {
   "renamed_teachers_italics": int,
   "live_activity_color": String,
   "welcome_message": String, "app_icon": String,
+  // paints
+  "current_theme_id": String, "current_theme_display_name": String, "current_theme_creator": String,
 });
 // DON'T FORGET TO UPDATE DEFAULT VALUES IN `initDB` MIGRATION OR ELSE PARENTS WILL COMPLAIN ABOUT THEIR CHILDREN MISSING
 // YOU'VE BEEN WARNED!!!
diff --git a/filcnaplo/lib/models/settings.dart b/filcnaplo/lib/models/settings.dart
index 31201eb..d488b00 100644
--- a/filcnaplo/lib/models/settings.dart
+++ b/filcnaplo/lib/models/settings.dart
@@ -79,6 +79,10 @@ class SettingsProvider extends ChangeNotifier {
   Color _liveActivityColor;
   String _welcomeMessage;
   String _appIcon;
+  // current theme
+  String _currentThemeId;
+  String _currentThemeDisplayName;
+  String _currentThemeCreator;
 
   SettingsProvider({
     DatabaseProvider? database,
@@ -127,6 +131,9 @@ class SettingsProvider extends ChangeNotifier {
     required Color liveActivityColor,
     required String welcomeMessage,
     required String appIcon,
+    required String currentThemeId,
+    required String currentThemeDisplayName,
+    required String currentThemeCreator,
   })  : _database = database,
         _language = language,
         _startPage = startPage,
@@ -172,7 +179,10 @@ class SettingsProvider extends ChangeNotifier {
         _renamedTeachersItalics = renameTeachersItalics,
         _liveActivityColor = liveActivityColor,
         _welcomeMessage = welcomeMessage,
-        _appIcon = appIcon;
+        _appIcon = appIcon,
+        _currentThemeId = currentThemeId,
+        _currentThemeDisplayName = currentThemeDisplayName,
+        _currentThemeCreator = currentThemeCreator;
 
   factory SettingsProvider.fromMap(Map map,
       {required DatabaseProvider database}) {
@@ -238,6 +248,9 @@ class SettingsProvider extends ChangeNotifier {
       liveActivityColor: Color(map["live_activity_color"]),
       welcomeMessage: map["welcome_message"],
       appIcon: map["app_icon"],
+      currentThemeId: map['current_theme_id'],
+      currentThemeDisplayName: map['current_theme_display_name'],
+      currentThemeCreator: map['current_theme_creator'],
     );
   }
 
@@ -291,6 +304,9 @@ class SettingsProvider extends ChangeNotifier {
       "live_activity_color": _liveActivityColor.value,
       "welcome_message": _welcomeMessage,
       "app_icon": _appIcon,
+      "current_theme_id": _currentThemeId,
+      "current_theme_display_name": _currentThemeDisplayName,
+      "current_theme_creator": _currentThemeCreator,
     };
   }
 
@@ -348,6 +364,9 @@ class SettingsProvider extends ChangeNotifier {
       liveActivityColor: const Color(0xFF676767),
       welcomeMessage: '',
       appIcon: 'refilc_default',
+      currentThemeId: '',
+      currentThemeDisplayName: '',
+      currentThemeCreator: 'reFilc',
     );
   }
 
@@ -400,6 +419,9 @@ class SettingsProvider extends ChangeNotifier {
   Color get liveActivityColor => _liveActivityColor;
   String get welcomeMessage => _welcomeMessage;
   String get appIcon => _appIcon;
+  String get currentThemeId => _currentThemeId;
+  String get currentThemeDisplayName => _currentThemeDisplayName;
+  String get currentThemeCreator => _currentThemeCreator;
 
   Future<void> update({
     bool store = true,
@@ -448,6 +470,9 @@ class SettingsProvider extends ChangeNotifier {
     Color? liveActivityColor,
     String? welcomeMessage,
     String? appIcon,
+    String? currentThemeId,
+    String? currentThemeDisplayName,
+    String? currentThemeCreator,
   }) async {
     if (language != null && language != _language) _language = language;
     if (startPage != null && startPage != _startPage) _startPage = startPage;
@@ -578,6 +603,17 @@ class SettingsProvider extends ChangeNotifier {
     if (appIcon != null && appIcon != _appIcon) {
       _appIcon = appIcon;
     }
+    if (currentThemeId != null && currentThemeId != _currentThemeId) {
+      _currentThemeId = currentThemeId;
+    }
+    if (currentThemeDisplayName != null &&
+        currentThemeDisplayName != _currentThemeDisplayName) {
+      _currentThemeDisplayName = currentThemeDisplayName;
+    }
+    if (currentThemeCreator != null &&
+        currentThemeCreator != _currentThemeCreator) {
+      _currentThemeCreator = currentThemeCreator;
+    }
     // store or not
     if (store) await _database?.store.storeSettings(this);
     notifyListeners();
diff --git a/filcnaplo_kreta_api/lib/providers/share_provider.dart b/filcnaplo_kreta_api/lib/providers/share_provider.dart
index ba55417..9d19b8f 100644
--- a/filcnaplo_kreta_api/lib/providers/share_provider.dart
+++ b/filcnaplo_kreta_api/lib/providers/share_provider.dart
@@ -22,7 +22,8 @@ class ShareProvider extends ChangeNotifier {
   Future<SharedTheme> shareCurrentTheme(BuildContext context,
       {bool isPublic = false,
       bool shareNick = true,
-      required SharedGradeColors gradeColors}) async {
+      required SharedGradeColors gradeColors,
+      String displayName = ''}) async {
     final SettingsProvider settings =
         Provider.of<SettingsProvider>(context, listen: false);
 
@@ -30,6 +31,7 @@ class ShareProvider extends ChangeNotifier {
       'public_id': const Uuid().v4(),
       'is_public': isPublic,
       'nickname': shareNick ? _user.nickname : 'Anonymous',
+      'display_name': displayName,
       'background_color': (settings.customBackgroundColor ??
               SettingsProvider.defaultSettings().customBackgroundColor)
           ?.value,
diff --git a/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.i18n.dart b/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.i18n.dart
index 9070a43..b786906 100755
--- a/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.i18n.dart
+++ b/filcnaplo_mobile_ui/lib/screens/settings/settings_screen.i18n.dart
@@ -88,6 +88,10 @@ extension SettingsLocalization on String {
           "dl_paint": "Redeemed",
           "public_paint": "Public Paints",
           "no_pub_paint": "No Public Paints",
+          "enter_id": "Enter Paint ID",
+          "paint_id": "Paint ID...",
+          "set_as_current": "Set as current",
+          "share_subj_theme": "Share Theme",
         },
         "hu_hu": {
           "personal_details": "Személyes információk",
@@ -174,6 +178,10 @@ extension SettingsLocalization on String {
           "dl_paint": "Beszerzett",
           "public_paint": "Nyilvános témák",
           "no_pub_paint": "Nincsenek nyilvános festékek",
+          "enter_id": "Azonosító megadása",
+          "paint_id": "Téma azonosító...",
+          "set_as_current": "Beállítás jelenleginek",
+          "share_subj_theme": "Téma Megosztás",
         },
         "de_de": {
           "personal_details": "Persönliche Angaben",
@@ -260,6 +268,10 @@ extension SettingsLocalization on String {
           "dl_paint": "Eingelöst",
           "public_paint": "Öffentliche Themen",
           "no_pub_paint": "Keine öffentlichen Anstriche",
+          "enter_id": "Themen-ID eingeben",
+          "paint_id": "Themen-ID...",
+          "set_as_current": "Als aktuell einstellen",
+          "share_subj_theme": "Thema Teilen",
         },
       };
 
diff --git a/filcnaplo_mobile_ui/lib/screens/settings/submenu/paint_list.dart b/filcnaplo_mobile_ui/lib/screens/settings/submenu/paint_list.dart
index 25c9cab..9ca868c 100644
--- a/filcnaplo_mobile_ui/lib/screens/settings/submenu/paint_list.dart
+++ b/filcnaplo_mobile_ui/lib/screens/settings/submenu/paint_list.dart
@@ -5,7 +5,9 @@ import 'package:filcnaplo/models/settings.dart';
 import 'package:filcnaplo/models/shared_theme.dart';
 import 'package:filcnaplo/theme/colors/accent.dart';
 import 'package:filcnaplo/theme/colors/colors.dart';
+import 'package:filcnaplo/theme/observer.dart';
 import 'package:filcnaplo_kreta_api/providers/share_provider.dart';
+import 'package:filcnaplo_mobile_ui/common/custom_snack_bar.dart';
 import 'package:filcnaplo_mobile_ui/common/empty.dart';
 import 'package:filcnaplo_mobile_ui/common/panel/panel_button.dart';
 import 'package:filcnaplo_mobile_ui/common/splitted_panel/splitted_panel.dart';
@@ -76,6 +78,10 @@ class PaintListScreenState extends State<PaintListScreen>
 
   late List<Widget> tiles;
 
+  final _paintId = TextEditingController();
+
+  SharedTheme? newThemeByID;
+
   @override
   void initState() {
     super.initState();
@@ -194,6 +200,37 @@ class PaintListScreenState extends State<PaintListScreen>
                   const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
               child: Column(
                 children: [
+                  // enter id
+                  SplittedPanel(
+                    padding: EdgeInsets.zero,
+                    cardPadding: const EdgeInsets.all(3.0),
+                    hasBorder: true,
+                    isTransparent: true,
+                    children: [
+                      PanelButton(
+                        onPressed: () => showEnterIDDialog(),
+                        title: Text(
+                          "enter_id".i18n,
+                          style: TextStyle(
+                            color: AppColors.of(context).text.withOpacity(.95),
+                          ),
+                        ),
+                        leading: Icon(
+                          FeatherIcons.plus,
+                          size: 22.0,
+                          color: AppColors.of(context).text.withOpacity(.95),
+                        ),
+                        borderRadius: const BorderRadius.vertical(
+                          top: Radius.circular(12.0),
+                          bottom: Radius.circular(12.0),
+                        ),
+                      ),
+                    ],
+                  ),
+
+                  const SizedBox(
+                    height: 18.0,
+                  ),
                   // current paint
                   SplittedPanel(
                     title: Text('current_paint'.i18n),
@@ -202,32 +239,44 @@ class PaintListScreenState extends State<PaintListScreen>
                     children: [
                       PanelButton(
                         onPressed: () async {
-                          SharedGradeColors gradeColors = await shareProvider
-                              .shareCurrentGradeColors(context);
-                          SharedTheme theme =
-                              await shareProvider.shareCurrentTheme(
-                            context,
-                            gradeColors: gradeColors,
-                          );
+                          if (settingsProvider.currentThemeId != '') {
+                            Share.share(
+                              settingsProvider.currentThemeId,
+                              subject: 'share_subj_theme'.i18n,
+                            );
+                          } else {
+                            SharedGradeColors gradeColors = await shareProvider
+                                .shareCurrentGradeColors(context);
+                            SharedTheme theme =
+                                await shareProvider.shareCurrentTheme(
+                              context,
+                              gradeColors: gradeColors,
+                            );
 
-                          Share.share(
-                            theme.id,
-                            subject: 'share_subj_theme'.i18n,
-                          );
+                            Share.share(
+                              theme.id,
+                              subject: 'share_subj_theme'.i18n,
+                            );
+                          }
                         },
                         longPressInstead: true,
                         title: Column(
                           crossAxisAlignment: CrossAxisAlignment.start,
                           children: [
                             Text(
-                              't.displayName',
+                              settingsProvider.currentThemeDisplayName !=
+                                      'displayName'
+                                  ? settingsProvider.currentThemeDisplayName
+                                  : 'Névtelen téma',
                               style: TextStyle(
                                 color:
                                     AppColors.of(context).text.withOpacity(.95),
                               ),
                             ),
                             Text(
-                              user.nickname ?? 'Anonymous',
+                              settingsProvider.currentThemeCreator != ''
+                                  ? settingsProvider.currentThemeCreator
+                                  : 'Anonymous',
                               style: TextStyle(
                                 color:
                                     AppColors.of(context).text.withOpacity(.65),
@@ -339,4 +388,179 @@ class PaintListScreenState extends State<PaintListScreen>
       ),
     );
   }
+
+  // enter id dialog
+  void showEnterIDDialog() {
+    _paintId.text = '';
+
+    showDialog(
+      context: context,
+      builder: (context) => StatefulBuilder(builder: (context, setS) {
+        return AlertDialog(
+          shape: const RoundedRectangleBorder(
+              borderRadius: BorderRadius.all(Radius.circular(14.0))),
+          title: Text("enter_id".i18n),
+          content: Column(
+            mainAxisSize: MainAxisSize.min,
+            children: [
+              TextField(
+                controller: _paintId,
+                onEditingComplete: () async {
+                  // SharedTheme? theme = await shareProvider.getThemeById(
+                  //   context,
+                  //   id: _paintId.text.replaceAll(' ', ''),
+                  // );
+
+                  // if (theme != null) {
+                  //   // set theme variable
+                  //   newThemeByID = theme;
+
+                  //   _paintId.clear();
+                  // } else {
+                  //   ScaffoldMessenger.of(context).showSnackBar(
+                  //     CustomSnackBar(
+                  //       content: Text("theme_not_found".i18n,
+                  //           style: const TextStyle(color: Colors.white)),
+                  //       backgroundColor: AppColors.of(context).red,
+                  //       context: context,
+                  //     ),
+                  //   );
+                  // }
+                },
+                decoration: InputDecoration(
+                  border: OutlineInputBorder(
+                    borderSide:
+                        const BorderSide(color: Colors.grey, width: 1.5),
+                    borderRadius: BorderRadius.circular(12.0),
+                  ),
+                  focusedBorder: OutlineInputBorder(
+                    borderSide:
+                        const BorderSide(color: Colors.grey, width: 1.5),
+                    borderRadius: BorderRadius.circular(12.0),
+                  ),
+                  contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
+                  hintText: 'paint_id'.i18n,
+                  suffixIcon: IconButton(
+                    icon: const Icon(
+                      FeatherIcons.x,
+                      color: Colors.grey,
+                    ),
+                    onPressed: () {
+                      setState(() {
+                        _paintId.text = '';
+                      });
+                    },
+                  ),
+                ),
+              ),
+              const Padding(
+                padding: EdgeInsets.symmetric(vertical: 8.0),
+                child: Icon(FeatherIcons.arrowDown, size: 32),
+              ),
+              Container(
+                decoration: BoxDecoration(
+                    color: Theme.of(context).colorScheme.background,
+                    borderRadius:
+                        const BorderRadius.all(Radius.circular(12.0))),
+                padding: const EdgeInsets.symmetric(vertical: 10.0),
+                child: Center(
+                  child: Text(
+                    'set_as_current'.i18n,
+                    style: const TextStyle(
+                        fontWeight: FontWeight.w500, fontSize: 16.0),
+                  ),
+                ),
+              ),
+            ],
+          ),
+          actions: [
+            TextButton(
+              child: Text(
+                "cancel".i18n,
+                style: const TextStyle(fontWeight: FontWeight.w500),
+              ),
+              onPressed: () {
+                Navigator.of(context).maybePop();
+              },
+            ),
+            TextButton(
+              child: Text(
+                "done".i18n,
+                style: const TextStyle(fontWeight: FontWeight.w500),
+              ),
+              onPressed: () async {
+                // get sex
+
+                SharedTheme? theme = await shareProvider.getThemeById(
+                  context,
+                  id: _paintId.text.replaceAll(' ', ''),
+                );
+
+                if (theme != null) {
+                  // set theme variable
+                  newThemeByID = theme;
+
+                  _paintId.clear();
+                } else {
+                  ScaffoldMessenger.of(context).showSnackBar(
+                    CustomSnackBar(
+                      content: Text("theme_not_found".i18n,
+                          style: const TextStyle(color: Colors.white)),
+                      backgroundColor: AppColors.of(context).red,
+                      context: context,
+                    ),
+                  );
+                }
+
+                // slay
+
+                setPaint();
+
+                setState(() {});
+                Navigator.of(context).pop();
+              },
+            ),
+          ],
+        );
+      }),
+    ).then((val) {
+      _paintId.clear();
+    });
+  }
+
+  void setPaint() async {
+    if (newThemeByID == null) return;
+
+    // changing grade colors
+    List<Color> colors = [
+      newThemeByID!.gradeColors.oneColor,
+      newThemeByID!.gradeColors.twoColor,
+      newThemeByID!.gradeColors.threeColor,
+      newThemeByID!.gradeColors.fourColor,
+      newThemeByID!.gradeColors.fiveColor,
+    ];
+    settingsProvider.update(gradeColors: colors);
+
+    // changing shadow effect
+    settingsProvider.update(shadowEffect: newThemeByID!.shadowEffect);
+
+    // changing theme
+    settingsProvider.update(
+      customBackgroundColor: newThemeByID!.backgroundColor,
+      customHighlightColor: newThemeByID!.panelsColor,
+      customAccentColor: newThemeByID!.accentColor,
+      customIconColor: newThemeByID!.iconColor,
+      // new things
+      currentThemeId: newThemeByID!.id,
+      currentThemeDisplayName: newThemeByID!.displayName,
+      currentThemeCreator: newThemeByID!.nickname,
+      // we should store it
+      store: true,
+    );
+
+    // seems weird but it works, trust me (idk why)
+    await settingsProvider.update(theme: settingsProvider.theme, store: true);
+    Provider.of<ThemeModeObserver>(context, listen: false)
+        .changeTheme(settingsProvider.theme, updateNavbarColor: true);
+  }
 }
diff --git a/filcnaplo_mobile_ui/lib/screens/settings/theme_screen.dart b/filcnaplo_mobile_ui/lib/screens/settings/theme_screen.dart
index 7d5e5ff..23e1e9f 100644
--- a/filcnaplo_mobile_ui/lib/screens/settings/theme_screen.dart
+++ b/filcnaplo_mobile_ui/lib/screens/settings/theme_screen.dart
@@ -111,7 +111,7 @@ class _PremiumCustomAccentColorSettingState
   @override
   void initState() {
     super.initState();
-    _colorsTabController = TabController(length: 5, vsync: this);
+    _colorsTabController = TabController(length: 4, vsync: this);
     _testTabController = TabController(length: 4, vsync: this);
     settings = Provider.of<SettingsProvider>(context, listen: false);
     shareProvider = Provider.of<ShareProvider>(context, listen: false);
@@ -159,6 +159,14 @@ class _PremiumCustomAccentColorSettingState
 
   void updateCustomColor(dynamic v, bool store,
       {Color? accent, Color? background, Color? panels, Color? icon}) {
+    // reset custom theme id
+    settings.update(
+      currentThemeId: '',
+      currentThemeDisplayName: '',
+      currentThemeCreator: '',
+      store: store,
+    );
+
     if (colorMode != CustomColorMode.theme) {
       settings.update(accentColor: AccentColor.custom, store: store);
     }
@@ -681,9 +689,9 @@ class _PremiumCustomAccentColorSettingState
                                               tab: Tab(
                                                   text: "colorpicker_presets"
                                                       .i18n)),
-                                          ColorTab(
-                                              color: unknownColor,
-                                              tab: Tab(text: "enter_id".i18n)),
+                                          // ColorTab(
+                                          //     color: unknownColor,
+                                          //     tab: Tab(text: "enter_id".i18n)),
                                           /*ColorTab(
                                               color:
                                                   settings.customAccentColor ??
@@ -742,37 +750,37 @@ class _PremiumCustomAccentColorSettingState
                                                     CustomColorMode.theme;
                                               });
                                               break;
-                                            case 1:
-                                              setState(() {
-                                                colorMode =
-                                                    CustomColorMode.enterId;
-                                              });
-                                              break;
+                                            // case 1:
+                                            //   setState(() {
+                                            //     colorMode =
+                                            //         CustomColorMode.enterId;
+                                            //   });
+                                            //   break;
                                             /*case 1:
                                               setState(() {
                                                 colorMode =
                                                     CustomColorMode.saved;
                                               });
                                               break;*/
-                                            case 2:
+                                            case 1:
                                               setState(() {
                                                 colorMode =
                                                     CustomColorMode.background;
                                               });
                                               break;
-                                            case 3:
+                                            case 2:
                                               setState(() {
                                                 colorMode =
                                                     CustomColorMode.highlight;
                                               });
                                               break;
-                                            case 4:
+                                            case 3:
                                               setState(() {
                                                 colorMode =
                                                     CustomColorMode.accent;
                                               });
                                               break;
-                                            case 5:
+                                            case 4:
                                               setState(() {
                                                 colorMode =
                                                     CustomColorMode.icon;