11import 'package:flutter/material.dart' ;
2- import 'package:shared_preferences/shared_preferences.dart' ;
3- import 'package:url_launcher/url_launcher.dart' ;
2+ import 'settings/general_settings.dart' ;
3+ import 'settings/notes_settings.dart' ;
4+ import 'settings/dependencies_screen.dart' ;
45
5- class SettingsScreen extends StatefulWidget {
6+ class SettingsScreen extends StatelessWidget {
67 const SettingsScreen ({super .key});
78
8- @override
9- State <SettingsScreen > createState () => _SettingsScreenState ();
10- }
11-
12- class _SettingsScreenState extends State <SettingsScreen > {
13- late SharedPreferences _prefs;
14- bool _saveOnDevice = false ;
15- String _defaultName = "New note" ;
16-
17- @override
18- void initState () {
19- super .initState ();
20- _initPrefs ();
21- }
22-
23- void _initPrefs () async {
24- _prefs = await SharedPreferences .getInstance ();
25- setState (() {
26- _saveOnDevice = _prefs.getBool ('save_on_device' ) ?? false ;
27- _defaultName = _prefs.getString ('default_name' ) ?? "New note" ;
28- });
29- }
30-
319 @override
3210 Widget build (BuildContext context) {
3311 return Scaffold (
@@ -36,174 +14,50 @@ class _SettingsScreenState extends State<SettingsScreen> {
3614 ),
3715 body: ListView (
3816 children: [
39- _sectionHeader ('General' ),
40- ListTile (
41- leading: const Icon (Icons .palette_outlined),
42- title: const Text ('Accent colour' ),
43- subtitle: const Text ('Dynamic or custom colors' ),
44- onTap: () => _showColorPicker (),
45- ),
46- ListTile (
47- leading: const Icon (Icons .brightness_6_outlined),
48- title: const Text ('Theme' ),
49- subtitle: const Text ('AMOLED, Dark, Light' ),
50- onTap: () => _showThemePicker (),
51- ),
52- const ListTile (
53- leading: Icon (Icons .language_outlined),
54- title: Text ('Language' ),
55- subtitle: Text ('English (System default)' ),
56- ),
57-
58- const Divider (indent: 16 , endIndent: 16 ),
59- _sectionHeader ('Home screen' ),
60- ListTile (
61- leading: const Icon (Icons .swipe_outlined),
62- title: const Text ('Swipe gestures' ),
63- subtitle: const Text ('Configure list actions' ),
64- onTap: () {
65- // Ovde ćemo dodati Dismissible logiku kasnije
66- },
67- ),
68-
69- const Divider (indent: 16 , endIndent: 16 ),
70- _sectionHeader ('Notes' ),
71- ListTile (
72- leading: const Icon (Icons .edit_note_outlined),
73- title: const Text ('Default name for new notes' ),
74- subtitle: Text (_defaultName),
75- onTap: () => _showDefaultNameDialog (),
76- ),
77- SwitchListTile (
78- secondary: const Icon (Icons .sd_storage_outlined),
79- title: const Text ('Save notes on device' ),
80- subtitle: const Text ('Export automatically to local storage' ),
81- value: _saveOnDevice,
82- onChanged: (bool value) async {
83- setState (() => _saveOnDevice = value);
84- await _prefs.setBool ('save_on_device' , value);
85- },
86- ),
87-
88- const Divider (indent: 16 , endIndent: 16 ),
89- _sectionHeader ('About' ),
90- ListTile (
91- leading: const Icon (Icons .inventory_2_outlined), // Popravljeno malo 'i'
92- title: const Text ('Dependencies' ),
93- onTap: () => _showDependencies (),
94- ),
95- ListTile (
96- leading: const Icon (Icons .description_outlined),
97- title: const Text ('License' ),
98- subtitle: const Text ("Click this to open GNU's website" ),
99- onTap: () => _launchURL ('https://www.gnu.org/licenses/gpl-3.0.html' ),
100- ),
101- ],
102- ),
103- );
104- }
105-
106- Widget _sectionHeader (String title) {
107- return Padding (
108- padding: const EdgeInsets .fromLTRB (16 , 16 , 16 , 8 ),
109- child: Text (
110- title,
111- style: TextStyle (
112- color: Theme .of (context).colorScheme.primary,
113- fontWeight: FontWeight .bold,
114- fontSize: 12 ,
115- letterSpacing: 1.2 ,
116- ),
117- ),
118- );
119- }
120-
121- void _showColorPicker () {
122- showDialog (
123- context: context,
124- builder: (context) => AlertDialog (
125- title: const Text ("Accent colour" , style: TextStyle (fontWeight: FontWeight .w300)),
126- content: const Text ("Material You dynamic coloring is active." ),
127- actions: [
128- TextButton (onPressed: () => Navigator .pop (context), child: const Text ("Close" ))
129- ],
130- ),
131- );
132- }
133-
134- void _showThemePicker () {
135- showDialog (
136- context: context,
137- builder: (context) => SimpleDialog (
138- title: const Text ("Theme" , style: TextStyle (fontWeight: FontWeight .w300)),
139- children: ['System default' , 'Light' , 'Dark' , 'AMOLED' ].map ((theme) {
140- return SimpleDialogOption (
141- onPressed: () => Navigator .pop (context),
142- child: Padding (
143- padding: const EdgeInsets .symmetric (vertical: 8.0 ),
144- child: Text (theme),
145- ),
146- );
147- }).toList (),
148- ),
149- );
150- }
151-
152- void _showDefaultNameDialog () {
153- final controller = TextEditingController (text: _defaultName);
154- showDialog (
155- context: context,
156- builder: (context) => AlertDialog (
157- title: const Text ("Default Note Name" , style: TextStyle (fontWeight: FontWeight .w300)),
158- content: TextField (
159- controller: controller,
160- decoration: const InputDecoration (hintText: "Enter default name" ),
161- autofocus: true ,
162- ),
163- actions: [
164- TextButton (onPressed: () => Navigator .pop (context), child: const Text ("Cancel" )),
165- TextButton (
166- onPressed: () async {
167- if (controller.text.isNotEmpty) {
168- setState (() => _defaultName = controller.text);
169- await _prefs.setString ('default_name' , controller.text);
170- }
171- Navigator .pop (context);
172- },
173- child: const Text ("Save" ),
17+ _buildSettingsTile (
18+ context,
19+ icon: Icons .tune_outlined,
20+ title: 'General' ,
21+ subtitle: 'Accent colors • Theme • Language' ,
22+ destination: const GeneralSettings (),
23+ ),
24+ _buildSettingsTile (
25+ context,
26+ icon: Icons .edit_note_outlined,
27+ title: 'Notes settings' ,
28+ subtitle: 'Default note names • Data saving' ,
29+ destination: const NotesSettings (),
30+ ),
31+ _buildSettingsTile (
32+ context,
33+ icon: Icons .info_outline,
34+ title: 'About app' ,
35+ subtitle: 'Version • Dependencies • License' ,
36+ destination: const DependenciesScreen (),
17437 ),
17538 ],
17639 ),
17740 );
17841 }
17942
180- void _showDependencies () {
181- showAboutDialog (
182- context: context,
183- applicationName: "f.Sentence" ,
184- applicationVersion: "1.0.1" ,
185- children: const [
186- Text ("Built with Flutter and passion for FOSS.\n " ),
187- Text ("• Fleather / Parchment" ),
188- Text ("• Hive / Hive Flutter" ),
189- Text ("• Dynamic Color" ),
190- Text ("• Easy Localization" ),
191- Text ("• Shared Preferences" ),
192- Text ("• Animations" ),
193- ],
194- );
195- }
196-
197- void _launchURL (String url) async {
198- final Uri uri = Uri .parse (url);
199- try {
200- await launchUrl (uri, mode: LaunchMode .externalApplication);
201- } catch (e) {
202- if (mounted) {
203- ScaffoldMessenger .of (context).showSnackBar (
204- SnackBar (content: Text ("Could not open: $url " )),
43+ Widget _buildSettingsTile (
44+ BuildContext context, {
45+ required IconData icon,
46+ required String title,
47+ required String subtitle,
48+ required Widget destination,
49+ }) {
50+ return ListTile (
51+ leading: Icon (icon, size: 28 ),
52+ title: Text (title, style: const TextStyle (fontWeight: FontWeight .w500)),
53+ subtitle: Text (subtitle),
54+ contentPadding: const EdgeInsets .symmetric (horizontal: 20 , vertical: 8 ),
55+ onTap: () {
56+ Navigator .push (
57+ context,
58+ MaterialPageRoute (builder: (context) => destination),
20559 );
206- }
207- }
60+ },
61+ );
20862 }
20963}
0 commit comments