Skip to content

Commit 588de30

Browse files
authored
fix #66
* feat: support multiple rsshub domains * feat: support multiple rsshub domains * feat: support multiple rsshub domains
1 parent 6204d05 commit 588de30

File tree

6 files changed

+392
-244
lines changed

6 files changed

+392
-244
lines changed

android/settings.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ pluginManagement {
1717
}
1818

1919
plugins {
20-
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
20+
id "dev.flutter.flutter-plugin-loader" version "1.0.2"
2121
id "com.android.application" version "7.3.0" apply false
22-
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
22+
id "org.jetbrains.kotlin.android" version "1.8.10" apply false
2323
}
2424

2525
include ":app"

changelogs/3.0.4.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
feat: support multiple rsshub domains #66

lib/shared_prefs.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class SharedPrefs {
2828

2929
String get domain => _sharedPrefs.getString("RSSHUB") ?? "https://rsshub.app";
3030

31+
List<String> get domains => _sharedPrefs.getStringList("DOMAIN") ?? ["https://rsshub.app"];
32+
33+
set domains(List<String> domains) => _sharedPrefs.setStringList("DOMAIN", domains);
34+
3135
/// Save history records after user delete one
3236
set historyList(List<String> history) =>
3337
_sharedPrefs.setStringList('historyListKey', history);

lib/views/settings.dart

Lines changed: 213 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import 'package:package_info_plus/package_info_plus.dart';
33
import 'package:rssaid/common/common.dart';
44
import 'package:rssaid/shared_prefs.dart';
55
import 'package:rssaid/views/rules.dart';
6-
import 'package:shared_preferences/shared_preferences.dart';
76
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
87

98
import '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

Comments
 (0)