@@ -3,7 +3,6 @@ import 'package:package_info_plus/package_info_plus.dart';
33import 'package:rssaid/common/common.dart' ;
44import 'package:rssaid/shared_prefs.dart' ;
55import 'package:rssaid/views/rules.dart' ;
6- import 'package:shared_preferences/shared_preferences.dart' ;
76import 'package:flutter_gen/gen_l10n/app_localizations.dart' ;
87
98import 'components/access_control.dart' ;
@@ -17,6 +16,8 @@ class _SettingPageState extends State<SettingPage> {
1716 final SharedPrefs prefs = SharedPrefs ();
1817
1918 String _domain = "https://rsshub.app" ;
19+ late List <String > _domains;
20+
2021 PackageInfo packageInfo = PackageInfo (
2122 appName: 'RSSAid' ,
2223 packageName: 'Unknown' ,
@@ -32,11 +33,11 @@ class _SettingPageState extends State<SettingPage> {
3233 }
3334
3435 Future <void > init () async {
35- if (prefs.domain.isNotEmpty ) {
36- setState (() {
37- _domain = prefs.domain ;
38- });
39- }
36+ setState (( ) {
37+ _domain = prefs.domain;
38+ _domains = prefs.domains ;
39+ });
40+
4041 final info = await PackageInfo .fromPlatform ();
4142 setState (() {
4243 packageInfo = info;
@@ -50,80 +51,203 @@ class _SettingPageState extends State<SettingPage> {
5051 prefs.domain = domain;
5152 }
5253
54+ void setDomains (List <String > domains) async {
55+ setState (() {
56+ _domains = domains;
57+ });
58+ prefs.domains = domains;
59+ }
60+
5361 @override
5462 Widget build (BuildContext context) {
5563 return Scaffold (
56- resizeToAvoidBottomInset: false ,
57- appBar: AppBar (
58- centerTitle: true ,
59- title: Text (AppLocalizations .of (context)! .settings,
60- style: Theme .of (context).textTheme.titleLarge),
61- leading: IconButton (
62- icon: Icon (Icons .arrow_back_ios),
63- onPressed: () {
64- Navigator .pop (context);
65- })),
66- body: SingleChildScrollView (child: Column (
67- mainAxisSize: MainAxisSize .min,
68- mainAxisAlignment: MainAxisAlignment .spaceBetween,
69- crossAxisAlignment: CrossAxisAlignment .start,
70- children: [
71- Padding (padding: EdgeInsets .only (left: 24 , right: 24 , bottom: 8 ),
72- child: Text (AppLocalizations .of (context)! .common, style: Theme .of (context).textTheme.titleMedium,),
64+ resizeToAvoidBottomInset: false ,
65+ appBar: AppBar (
66+ centerTitle: true ,
67+ title: Text (AppLocalizations .of (context)! .settings,
68+ style: Theme .of (context).textTheme.titleLarge),
69+ leading: IconButton (
70+ icon: Icon (Icons .arrow_back_ios),
71+ onPressed: () {
72+ Navigator .pop (context);
73+ })),
74+ body: SingleChildScrollView (
75+ child: Column (
76+ mainAxisSize: MainAxisSize .min,
77+ mainAxisAlignment: MainAxisAlignment .spaceBetween,
78+ crossAxisAlignment: CrossAxisAlignment .start,
79+ children: [
80+ Padding (
81+ padding: EdgeInsets .only (left: 24 , right: 24 , bottom: 8 ),
82+ child: Text (
83+ AppLocalizations .of (context)! .common,
84+ style: Theme .of (context).textTheme.titleMedium,
7385 ),
74- CommonRows (_domain, setDomain),
75- Padding (padding: EdgeInsets .only (left: 24 , right: 24 , bottom: 8 ),
76- child: Text (AppLocalizations .of (context)! .about, style: Theme .of (context).textTheme.titleMedium,),
86+ ),
87+ CommonRows (
88+ domain: _domain,
89+ domains: _domains,
90+ onDomainSet: (newDomain) {
91+ setState (() {
92+ _domain = newDomain;
93+ prefs.domain = newDomain;
94+ });
95+ },
96+ onDomainsSet: (newDomains) {
97+ setState (() {
98+ _domains = newDomains;
99+ prefs.domains = newDomains;
100+ });
101+ },
102+ ),
103+ Padding (
104+ padding: EdgeInsets .only (left: 24 , right: 24 , bottom: 8 ),
105+ child: Text (
106+ AppLocalizations .of (context)! .about,
107+ style: Theme .of (context).textTheme.titleMedium,
77108 ),
78- AboutRows (version: packageInfo.version,)
79- ],
80- ),),
81- );
109+ ),
110+ AboutRows (
111+ version: packageInfo.version,
112+ )
113+ ],
114+ ),
115+ ),
116+ );
82117 }
83118}
84119
85120// ignore: must_be_immutable
86- class CommonRows extends StatelessWidget {
87- String ? _domain;
88- Function ? _domainSetCallback;
89- TextEditingController _domainController = new TextEditingController ();
90-
91- CommonRows (String domain, Function domainSetFunc) {
92- this ._domain = domain;
93- this ._domainController.text = domain;
94- this ._domainSetCallback = domainSetFunc;
121+ class CommonRows extends StatefulWidget {
122+ final String domain;
123+ final List <String > domains;
124+ final Function (String ) onDomainSet;
125+ final Function (List <String >) onDomainsSet;
126+
127+ const CommonRows ({
128+ Key ? key,
129+ required this .domain,
130+ required this .domains,
131+ required this .onDomainSet,
132+ required this .onDomainsSet,
133+ }) : super (key: key);
134+
135+ @override
136+ _CommonRowsState createState () => _CommonRowsState ();
137+ }
138+
139+ class _CommonRowsState extends State <CommonRows > {
140+ late TextEditingController _domainController;
141+ late List <String > _localDomains;
142+ late String _localDomain;
143+
144+ @override
145+ void initState () {
146+ super .initState ();
147+ _domainController = TextEditingController ();
148+ _localDomains = List .from (widget.domains);
149+ _localDomain = widget.domain;
95150 }
96151
97152 @override
98- Widget build (BuildContext context) {
99- return ListView (
100- shrinkWrap: true ,
101- children: [
102- _buildHowUseSoftware (context),
103- _buildRssHubDomain (context),
104- AccessControlWidget (),
105- _buildRules (context)
106- ],
107- );
153+ void dispose () {
154+ _domainController.dispose ();
155+ super .dispose ();
108156 }
109157
110- Widget _buildRssHubDomain (BuildContext context) {
111- return Card (
112- margin: EdgeInsets .only (left: 24 , right: 24 , bottom: 8 ),
113- clipBehavior: Clip .hardEdge,
114- shape: RoundedRectangleBorder (
115- borderRadius: BorderRadius .circular (15.0 ),
116- ),
117- elevation: 1 ,
118- child: ListTile (
119- leading: Icon (Icons .domain),
120- title: Text (
121- "RSSHub URL" ,
122- ),
123- onTap: () {
124- _showDialog (context);
125- },
126- ),
158+
159+ void _showDomainDialog (BuildContext context) {
160+ showDialog (
161+ context: context,
162+ builder: (context) {
163+ return AlertDialog (
164+ content: StatefulBuilder (
165+ builder: (BuildContext context, StateSetter setState) {
166+ return Column (
167+ mainAxisSize: MainAxisSize .min,
168+ children: [
169+ TextField (
170+ controller: _domainController,
171+ decoration: InputDecoration (
172+ labelText: 'Add New Domain' ,
173+ suffixIcon: IconButton (
174+ icon: Icon (Icons .add),
175+ onPressed: () {
176+ if (_domainController.text.isNotEmpty &&
177+ ! _localDomains
178+ .contains (_domainController.text.trim ())) {
179+ setState (() {
180+ _localDomains.add (_domainController.text.trim ());
181+ widget.onDomainsSet (_localDomains);
182+ });
183+ _domainController.clear ();
184+ }
185+ },
186+ ),
187+ ),
188+ onSubmitted: (String domain) {
189+ if (domain.isNotEmpty && ! _localDomains.contains (domain.trim ())) {
190+ setState (() {
191+ _localDomains.add (domain.trim ());
192+ widget.onDomainsSet (_localDomains);
193+ });
194+ _domainController.clear ();
195+ }
196+ },
197+ ),
198+ ListView .builder (
199+ shrinkWrap: true ,
200+ itemCount: _localDomains.length,
201+ itemBuilder: (context, index) {
202+ final domain = _localDomains[index];
203+ return Row (
204+ children: [
205+ Checkbox (
206+ value: domain == _localDomain,
207+ onChanged: (bool ? selected) {
208+ if (selected == true ) {
209+ setState (() {
210+ widget.onDomainSet (domain);
211+ _localDomain = domain;
212+ });
213+ }
214+ },
215+ ),
216+ Expanded (child: Text (domain)),
217+ if (_localDomains.length > 1 )
218+ IconButton (
219+ icon: Icon (Icons .delete, color: Colors .red),
220+ onPressed: () {
221+ if (_localDomains.length > 1 ) {
222+ setState (() {
223+ _localDomains.remove (domain);
224+ widget.onDomainsSet (_localDomains);
225+
226+ // If the current domain is removed, select the first available domain
227+ if (domain == widget.domain) {
228+ widget.onDomainSet (_localDomains.first);
229+ }
230+ });
231+ }
232+ },
233+ ),
234+ ],
235+ );
236+ },
237+ )
238+ ],
239+ );
240+ }),
241+ actions: [
242+ ElevatedButton (
243+ child: Text ('Ok' ),
244+ onPressed: () {
245+ Navigator .pop (context);
246+ },
247+ ),
248+ ],
249+ );
250+ },
127251 );
128252 }
129253
@@ -169,39 +293,29 @@ class CommonRows extends StatelessWidget {
169293 );
170294 }
171295
172- _showDialog (BuildContext context) async {
173- await showDialog (
174- context: context,
175- builder: (context) {
176- return StatefulBuilder (
177- builder: (context, setState) {
178- return new AlertDialog (
179- // contentPadding: const EdgeInsets.all(16.0),
180- content: Container (
181- child: TextField (
182- controller: _domainController,
183- decoration: new InputDecoration (labelText: 'Host' ),
184- ),
185- ),
186- actions: < Widget > [
187- TextButton (
188- child: Text (AppLocalizations .of (context)! .cancel),
189- onPressed: () {
190- Navigator .pop (context);
191- }),
192- ElevatedButton (
193- child: Text (AppLocalizations .of (context)! .sure),
194- onPressed: () {
195- if (_domainController.text != _domain) {
196- _domainSetCallback !(_domainController.text);
197- }
198- Navigator .pop (context);
199- })
200- ],
201- );
202- },
203- );
204- });
296+ Widget _buildRssHubDomain (BuildContext context) {
297+ return Card (
298+ margin: EdgeInsets .only (left: 24 , right: 24 , bottom: 8 ),
299+ child: ListTile (
300+ leading: Icon (Icons .domain),
301+ title: Text ("RSSHub URL" ),
302+ subtitle: Text (widget.domain),
303+ onTap: () => _showDomainDialog (context),
304+ ),
305+ );
306+ }
307+
308+ @override
309+ Widget build (BuildContext context) {
310+ return ListView (
311+ shrinkWrap: true ,
312+ children: [
313+ _buildHowUseSoftware (context),
314+ _buildRssHubDomain (context),
315+ AccessControlWidget (),
316+ _buildRules (context)
317+ ],
318+ );
205319 }
206320}
207321
0 commit comments