From f6a8cd61f7df69221c9042d0677117dba206eb63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=99=D7=95=D7=A1=D7=A3?= Date: Sat, 21 Sep 2024 23:59:59 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D7=94=D7=95=D7=A1=D7=A4=D7=AA=20=D7=90?= =?UTF-8?q?=D7=A4=D7=A9=D7=A8=D7=95=D7=AA=20=D7=9C=D7=A0=D7=A2=D7=99=D7=9C?= =?UTF-8?q?=D7=AA=20=D7=94=D7=94=D7=92=D7=93=D7=A8=D7=95=D7=AA=20=D7=91?= =?UTF-8?q?=D7=90=D7=9E=D7=A6=D7=A2=D7=95=D7=AA=20=D7=A7=D7=95=D7=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/screens/settings_screen.dart | 294 ++++++++++++++++++++++++------- 1 file changed, 233 insertions(+), 61 deletions(-) diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index a99cf135..0361684c 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -5,6 +5,178 @@ import 'dart:io'; import 'package:otzaria/models/app_model.dart'; import 'package:provider/provider.dart'; import 'package:package_info_plus/package_info_plus.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +class SettingsScreen extends StatefulWidget { + @override + _SettingsScreenState createState() => _SettingsScreenState(); +} + +class _SettingsScreenState extends State { + final storage = const FlutterSecureStorage(); + String? lockCode; + bool isLocked = false; + + @override + void initState() { + super.initState(); + loadLockCode(); + } + + Future loadLockCode() async { + lockCode = await storage.read(key: 'settings_lock_code'); + if (lockCode != null) { + setState(() { + isLocked = true; + }); + } + } + + Future saveLockCode(String code) async { + await storage.write(key: 'settings_lock_code', value: code); + setState(() { + lockCode = code; + isLocked = true; + }); + } + + Future _showUnlockDialog() async { + String inputCode = ''; + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('הזן קוד נעילה'), + content: TextField( + onChanged: (value) { + inputCode = value; + }, + decoration: InputDecoration(hintText: "הכנס קוד"), + obscureText: true, + ), + actions: [ + TextButton( + child: Text('ביטול'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: Text('אישור'), + onPressed: () { + if (inputCode == lockCode) { + setState(() { + isLocked = false; + }); + Navigator.of(context).pop(); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('קוד לא נכון')), + ); + } + }, + ), + ], + ); + }, + ); + } + + Future _showSetLockDialog() async { + String newCode = ''; + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('הגדר קוד נעילה'), + content: TextField( + onChanged: (value) { + newCode = value; + }, + decoration: InputDecoration(hintText: "הכנס קוד חדש"), + obscureText: true, + ), + actions: [ + TextButton( + child: Text('ביטול'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: Text('שמור'), + onPressed: () { + if (newCode.isNotEmpty) { + saveLockCode(newCode); + Navigator.of(context).pop(); + } + }, + ), + ], + ); + }, + ); + } + + Future _clearLockCode() async { + await storage.delete(key: 'settings_lock_code'); + setState(() { + lockCode = null; + isLocked = false; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('הגדרות'), + ), + body: isLocked + ? Center( + child: ElevatedButton( + onPressed: _showUnlockDialog, + child: Text('הזן קוד נעילה כדי לפתוח'), + ), + ) + : ListView( + padding: EdgeInsets.all(16), + children: [ + ListTile( + title: Text('אפשרות א'), + subtitle: Text('הגדרה ראשונה'), + trailing: Switch( + value: true, + onChanged: (bool value) { + // שינוי ההגדרות + }, + ), + ), + ListTile( + title: Text('אפשרות ב'), + subtitle: Text('הגדרה שנייה'), + trailing: Switch( + value: false, + onChanged: (bool value) { + // שינוי ההגדרות + }, + ), + ), + Divider(), + ListTile( + title: Text('הגדר קוד נעילה'), + onTap: _showSetLockDialog, + ), + ListTile( + title: Text('מחק קוד נעילה'), + onTap: _clearLockCode, + ), + ], + ), + ); + } +} class MySettingsScreen extends StatefulWidget { const MySettingsScreen({ @@ -58,66 +230,66 @@ class _MySettingsScreenState extends State { }; return Scaffold( - body: Consumer( - builder: (context, appModel, child) { - return Center( - child: SettingsScreen( - title: 'הגדרות', - children: [ - SettingsGroup( - titleAlignment: Alignment.centerRight, - title: 'הגדרות עיצוב', - titleTextStyle: const TextStyle(fontSize: 25), - children: [ - SwitchSettingsTile( - settingKey: 'key-dark-mode', - title: 'מצב כהה', - enabledLabel: 'מופעל', - disabledLabel: 'לא מופעל', - leading: const Icon(Icons.nightlight_round_outlined), - onChange: (value) { - appModel.isDarkMode.value = value; - }, - ), - ColorPickerSettingsTile( - title: 'צבע בסיס', - leading: const Icon(Icons.color_lens), - settingKey: 'key-swatch-color', - onChange: (p0) { - appModel.seedColor.value = p0; - }), - const SliderSettingsTile( - title: 'גודל גופן התחלתי בספרים', - settingKey: 'key-font-size', - defaultValue: 30, - min: 15, - max: 60, - step: 1, - leading: Icon(Icons.format_size), - decimalPrecision: 0, - ), - DropDownSettingsTile( - title: 'גופן', - settingKey: 'key-font-family', - values: const { - 'TaameyDavidCLM': 'דוד', - 'FrankRuhlCLM': 'פרנק-רוהל', - 'TaameyAshkenaz': 'טעמי אשכנז', - 'KeterYG': 'כתר', - 'Shofar': 'שופר', - 'NotoSerifHebrew': 'נוטו', - 'Tinos': 'טינוס', - 'NotoRashiHebrew': 'רש"י', - 'Candara': 'קנדרה', - 'roboto': 'רובוטו', - 'Calibri': 'קליברי', - 'Arial': 'אריאל', - }, - selected: 'FrankRuhlCLM', - leading: const Icon(Icons.font_download_outlined), - onChange: (value) {}, - ), - SliderSettingsTile( + body: Consumer(builder: (context, appModel, child) { + return Center( + child: SettingsScreen( + title: 'הגדרות', + children: [ + SettingsGroup( + titleAlignment: Alignment.centerRight, + title: 'הגדרות עיצוב', + titleTextStyle: const TextStyle(fontSize: 25), + children: [ + SwitchSettingsTile( + settingKey: 'key-dark-mode', + title: 'מצב כהה', + enabledLabel: 'מופעל', + disabledLabel: 'לא מופעל', + leading: const Icon(Icons.nightlight_round_outlined), + onChange: (value) { + appModel.isDarkMode.value = value; + }, + ), + ColorPickerSettingsTile( + title: 'צבע בסיס', + leading: const Icon(Icons.color_lens), + settingKey: 'key-swatch-color', + onChange: (p0) { + appModel.seedColor.value = p0; + }, + ), + const SliderSettingsTile( + title: 'גודל גופן התחלתי בספרים', + settingKey: 'key-font-size', + defaultValue: 30, + min: 15, + max: 60, + step: 1, + leading: Icon(Icons.format_size), + decimalPrecision: 0, + ), + DropDownSettingsTile( + title: 'גופן', + settingKey: 'key-font-family', + values: const { + 'TaameyDavidCLM': 'דוד', + 'FrankRuhlCLM': 'פרנק-רוהל', + 'TaameyAshkenaz': 'טעמי אשכנז', + 'KeterYG': 'כתר', + 'Shofar': 'שופר', + 'NotoSerifHebrew': 'נוטו', + 'Tinos': 'טינוס', + 'NotoRashiHebrew': 'רש"י', + 'Candara': 'קנדרה', + 'roboto': 'רובוטו', + 'Calibri': 'קליברי', + 'Arial': 'אריאל', + }, + selected: 'FrankRuhlCLM', + leading: const Icon(Icons.font_download_outlined), + onChange: (value) {}, + ), + SliderSettingsTile( title: 'רוחב השוליים בצידי הטקסט', settingKey: 'key-padding-size', defaultValue: 10, @@ -135,7 +307,7 @@ class _MySettingsScreenState extends State { : const SettingsGroup( titleAlignment: Alignment.centerRight, title: "קיצורי מקשים", - titleTextStyle: TextStyle(fontSize: 25), + titleTextStyle: const TextStyle(fontSize: 25), children: [ DropDownSettingsTile( selected: 'ctrl+l', From 4a4bcbf0e095eecffeb2cc78f06fc84d7cd23282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=99=D7=95=D7=A1=D7=A3?= Date: Sun, 22 Sep 2024 00:04:11 +0300 Subject: [PATCH 2/2] Add files via upload --- settings_screen.dart | 470 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 470 insertions(+) create mode 100644 settings_screen.dart diff --git a/settings_screen.dart b/settings_screen.dart new file mode 100644 index 00000000..61177f50 --- /dev/null +++ b/settings_screen.dart @@ -0,0 +1,470 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_settings_screens/flutter_settings_screens.dart'; +import 'package:file_picker/file_picker.dart'; +import 'dart:io'; +import 'package:otzaria/models/app_model.dart'; +import 'package:provider/provider.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +class SettingsScreen extends StatefulWidget { + @override + _SettingsScreenState createState() => _SettingsScreenState(); +} + +class _SettingsScreenState extends State { + final storage = const FlutterSecureStorage(); + String? lockCode; + bool isLocked = false; + + @override + void initState() { + super.initState(); + loadLockCode(); + } + + Future loadLockCode() async { + lockCode = await storage.read(key: 'settings_lock_code'); + if (lockCode != null) { + setState(() { + isLocked = true; + }); + } + } + + Future saveLockCode(String code) async { + await storage.write(key: 'settings_lock_code', value: code); + setState(() { + lockCode = code; + isLocked = true; + }); + } + + Future _showUnlockDialog() async { + String inputCode = ''; + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('הזן קוד נעילה'), + content: TextField( + onChanged: (value) { + inputCode = value; + }, + decoration: InputDecoration(hintText: "הכנס קוד"), + obscureText: true, + ), + actions: [ + TextButton( + child: Text('ביטול'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: Text('אישור'), + onPressed: () { + if (inputCode == lockCode) { + setState(() { + isLocked = false; + }); + Navigator.of(context).pop(); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('קוד לא נכון')), + ); + } + }, + ), + ], + ); + }, + ); + } + + Future _showSetLockDialog() async { + String newCode = ''; + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('הגדר קוד נעילה'), + content: TextField( + onChanged: (value) { + newCode = value; + }, + decoration: InputDecoration(hintText: "הכנס קוד חדש"), + obscureText: true, + ), + actions: [ + TextButton( + child: Text('ביטול'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: Text('שמור'), + onPressed: () { + if (newCode.isNotEmpty) { + saveLockCode(newCode); + Navigator.of(context).pop(); + } + }, + ), + ], + ); + }, + ); + } + + Future _clearLockCode() async { + await storage.delete(key: 'settings_lock_code'); + setState(() { + lockCode = null; + isLocked = false; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('הגדרות'), + ), + body: isLocked + ? Center( + child: ElevatedButton( + onPressed: _showUnlockDialog, + child: Text('הזן קוד נעילה כדי לפתוח'), + ), + ) + : ListView( + padding: EdgeInsets.all(16), + children: [ + ListTile( + title: Text('אפשרות א'), + subtitle: Text('הגדרה ראשונה'), + trailing: Switch( + value: true, + onChanged: (bool value) { + // שינוי ההגדרות + }, + ), + ), + ListTile( + title: Text('אפשרות ב'), + subtitle: Text('הגדרה שנייה'), + trailing: Switch( + value: false, + onChanged: (bool value) { + // שינוי ההגדרות + }, + ), + ), + Divider(), + ListTile( + title: Text('הגדר קוד נעילה'), + onTap: _showSetLockDialog, + ), + ListTile( + title: Text('מחק קוד נעילה'), + onTap: _clearLockCode, + ), + ], + ), + ); + } +} + +class MySettingsScreen extends StatefulWidget { + const MySettingsScreen({ + Key? key, + }) : super(key: key); + + @override + State createState() => _MySettingsScreenState(); +} + +class _MySettingsScreenState extends State { + @override + Widget build(BuildContext context) { + const Map shortcuctsList = { + 'ctrl+a': 'CTRL + A', + 'ctrl+b': "CTRL + B", + 'ctrl+c': "CTRL + C", + 'ctrl+d': "CTRL + D", + 'ctrl+e': "CTRL + E", + 'ctrl+f': "CTRL + F", + 'ctrl+g': "CTRL + G", + 'ctrl+h': "CTRL + H", + 'ctrl+i': "CTRL + I", + 'ctrl+j': "CTRL + J", + 'ctrl+k': "CTRL + K", + 'ctrl+l': "CTRL + L", + 'ctrl+m': "CTRL + M", + 'ctrl+n': "CTRL + N", + 'ctrl+o': "CTRL + O", + 'ctrl+p': "CTRL + P", + 'ctrl+q': "CTRL + Q", + 'ctrl+r': "CTRL + R", + 'ctrl+s': "CTRL + S", + 'ctrl+t': "CTRL + T", + 'ctrl+u': "CTRL + U", + 'ctrl+v': "CTRL + V", + 'ctrl+w': "CTRL + W", + 'ctrl+x': "CTRL + X", + 'ctrl+y': "CTRL + Y", + 'ctrl+z': "CTRL + Z", + 'ctrl+0': "CTRL + 0", + 'ctrl+1': "CTRL + 1", + 'ctrl+2': "CTRL + 2", + 'ctrl+3': "CTRL + 3", + 'ctrl+4': "CTRL + 4", + 'ctrl+5': "CTRL + 5", + 'ctrl+6': "CTRL + 6", + 'ctrl+7': "CTRL + 7", + 'ctrl+8': "CTRL + 8", + 'ctrl+9': "CTRL + 9", + }; + + return Scaffold( + body: Consumer(builder: (context, appModel, child) { + return Center( + child: SettingsScreen( + title: 'הגדרות', + children: [ + SettingsGroup( + titleAlignment: Alignment.centerRight, + title: 'הגדרות עיצוב', + titleTextStyle: const TextStyle(fontSize: 25), + children: [ + SwitchSettingsTile( + settingKey: 'key-dark-mode', + title: 'מצב כהה', + enabledLabel: 'מופעל', + disabledLabel: 'לא מופעל', + leading: const Icon(Icons.nightlight_round_outlined), + onChange: (value) { + appModel.isDarkMode.value = value; + }, + ), + ColorPickerSettingsTile( + title: 'צבע בסיס', + leading: const Icon(Icons.color_lens), + settingKey: 'key-swatch-color', + onChange: (p0) { + appModel.seedColor.value = p0; + }, + ), + const SliderSettingsTile( + title: 'גודל גופן התחלתי בספרים', + settingKey: 'key-font-size', + defaultValue: 30, + min: 15, + max: 60, + step: 1, + leading: Icon(Icons.format_size), + decimalPrecision: 0, + ), + DropDownSettingsTile( + title: 'גופן', + settingKey: 'key-font-family', + values: const { + 'TaameyDavidCLM': 'דוד', + 'FrankRuhlCLM': 'פרנק-רוהל', + 'TaameyAshkenaz': 'טעמי אשכנז', + 'KeterYG': 'כתר', + 'Shofar': 'שופר', + 'NotoSerifHebrew': 'נוטו', + 'Tinos': 'טינוס', + 'NotoRashiHebrew': 'רש"י', + 'Candara': 'קנדרה', + 'roboto': 'רובוטו', + 'Calibri': 'קליברי', + 'Arial': 'אריאל', + }, + selected: 'FrankRuhlCLM', + leading: const Icon(Icons.font_download_outlined), + onChange: (value) {}, + ), + SliderSettingsTile( + title: 'רוחב השוליים בצידי הטקסט', + settingKey: 'key-padding-size', + defaultValue: 10, + min: 0, + max: 500, + step: 2, + leading: const Icon(Icons.horizontal_distribute), + decimalPrecision: 0, + onChange: (p0) => appModel.paddingSize.value = p0, + ), + ], + ), + Platform.isAndroid + ? const SizedBox.shrink() + : const SettingsGroup( + titleAlignment: Alignment.centerRight, + title: "קיצורי מקשים", + titleTextStyle: const TextStyle(fontSize: 25), + children: [ + DropDownSettingsTile( + selected: 'ctrl+l', + settingKey: 'key-shortcut-open-library-browser', + title: 'ספרייה', + values: shortcuctsList, + leading: Icon(Icons.library_books), + ), + DropDownSettingsTile( + selected: 'ctrl+o', + settingKey: 'key-shortcut-open-find-ref', + title: 'איתור', + values: shortcuctsList, + leading: Icon(Icons.auto_stories_rounded), + ), + DropDownSettingsTile( + selected: 'ctrl+r', + settingKey: 'key-shortcut-open-reading-screen', + title: 'עיון', + leading: Icon(Icons.menu_book_rounded), + values: shortcuctsList, + ), + DropDownSettingsTile( + selected: 'ctrl+q', + settingKey: 'key-shortcut-open-new-search', + title: 'חלון חיפוש חדש', + leading: Icon(Icons.search), + values: shortcuctsList, + ), + DropDownSettingsTile( + selected: 'ctrl+w', + settingKey: 'key-shortcut-close-tab', + title: 'סגור ספר נוכחי', + leading: Icon(Icons.cancel), + values: shortcuctsList, + ), + DropDownSettingsTile( + selected: 'ctrl+x', + settingKey: 'key-shortcut-close-all-tabs', + title: 'סגור כל הספרים', + leading: Icon(Icons.close), + values: shortcuctsList, + ), + ]), + SettingsGroup( + title: 'הגדרות ממשק', + titleAlignment: Alignment.centerRight, + titleTextStyle: const TextStyle(fontSize: 25), + children: [ + // Platform.isAndroid + // ? const SizedBox.shrink() + // : const SwitchSettingsTile( + // settingKey: 'key-close-left-pane-on-scroll', + // title: 'סגירת תפריט הצד בעת גלילה', + // enabledLabel: + // 'עם תחילת הגלילה, ייסגר תפריט הצד אוטומטית', + // disabledLabel: 'תפריט הצד לא ייסגר אוטומטית', + // leading: Icon(Icons.arrow_back), + // ), + const SwitchSettingsTile( + settingKey: 'key-splited-view', + title: 'ברירת המחדל להצגת המפרשים', + enabledLabel: 'המפרשים יוצגו לצד הטקסט', + disabledLabel: 'המפרשים יוצגו מתחת הטקסט', + leading: Icon(Icons.vertical_split), + defaultValue: false, + ), + SwitchSettingsTile( + settingKey: 'key-use-fast-search', + title: 'חיפוש מהיר באמצעות אינדקס', + enabledLabel: + 'החיפוש יהיה מהיר יותר, נדרש ליצור אינדקס', + disabledLabel: 'החיפוש יהיה איטי יותר, לא נדרש אינדקס', + leading: Icon(Icons.search), + defaultValue: true, + onChange: (value) => context + .read() + .useFastSearch + .value = value, + ), + SwitchSettingsTile( + settingKey: 'key-show-external-books', + title: 'איתור ספרים באתרים חיצוניים', + enabledLabel: 'יוצגו גם ספרים מאתרים חיצוניים', + disabledLabel: 'יוצגו רק ספרים מספריית אוצריא', + leading: const Icon(Icons.open_in_new), + defaultValue: false, + onChange: (value) { + Provider.of(context, listen: false) + .showExternalBooks + .value = value; + Provider.of(context, listen: false) + .showHebrewBooks + .value = value; + Provider.of(context, listen: false) + .showOtzarHachochma + .value = value; + Settings.setValue('key-show-hebrew-books', value); + Settings.setValue('key-show-otzar-hachochma', value); + }, + ), + ]), + SettingsGroup( + title: 'כללי', + titleAlignment: Alignment.centerRight, + titleTextStyle: const TextStyle(fontSize: 25), + children: [ + SimpleSettingsTile( + title: 'מיקום הספרייה', + subtitle: Settings.getValue('key-library-path') ?? + 'לא קיים', + leading: const Icon(Icons.folder), + onTap: () async { + String? path = + await FilePicker.platform.getDirectoryPath(); + if (path != null) { + Settings.setValue('key-library-path', path); + setState( + () {}, + ); + } + }, + ), + const SwitchSettingsTile( + settingKey: 'key-dev-channel', + title: 'עדכון לגרסאות מפתחים', + enabledLabel: + 'קבלת עדכונים על גרסאות בדיקה, ייתכנו באגים וחוסר יציבות', + disabledLabel: 'קבלת עדכונים על גרסאות יציבות בלבד', + leading: Icon(Icons.bug_report), + ), + FutureBuilder( + future: PackageInfo.fromPlatform(), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return SimpleSettingsTile( + title: 'גרסה נוכחית', + subtitle: 'המתן..', + leading: Icon(Icons.info_rounded), + ); + } + return Align( + alignment: Alignment.centerRight, + child: SimpleSettingsTile( + title: 'גרסה נוכחית', + subtitle: snapshot.data!.version, + leading: Icon(Icons.info_rounded), + ), + ); + }) + ], + ) + ], + ), + ); + }, + ), + ); + } +}