Compare commits

..

1 Commits

Author SHA1 Message Date
8ca0a7785f Fix alt_store workflow 2025-10-12 19:57:28 +08:00
12 changed files with 295 additions and 282 deletions

View File

@@ -31,7 +31,7 @@ jobs:
- name: Update AltStore source - name: Update AltStore source
id: update_source id: update_source
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.ACTION_GITHUB_TOKEN }}
run: | run: |
python update_alt_store.py python update_alt_store.py
git config --global user.name 'GitHub Action' git config --global user.name 'GitHub Action'

View File

@@ -23,7 +23,7 @@ linter:
rules: rules:
collection_methods_unrelated_type: false collection_methods_unrelated_type: false
use_build_context_synchronously: false use_build_context_synchronously: false
avoid_print: false # avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at # Additional information about this file can be found at

View File

@@ -84,8 +84,9 @@ android {
buildTypes { buildTypes {
release { release {
minifyEnabled true // Temporarily solution to fix crash
shrinkResources true minifyEnabled false
shrinkResources false
ndk { ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86_64" abiFilters "armeabi-v7a", "arm64-v8a", "x86_64"
} }

View File

@@ -17,50 +17,39 @@ class CategoriesPage extends StatefulWidget {
State<CategoriesPage> createState() => _CategoriesPageState(); State<CategoriesPage> createState() => _CategoriesPageState();
} }
class _CategoriesPageState extends State<CategoriesPage> class _CategoriesPageState extends State<CategoriesPage> {
with
TickerProviderStateMixin,
AutomaticKeepAliveClientMixin<CategoriesPage> {
var categories = <String>[]; var categories = <String>[];
late TabController controller;
void onSettingsChanged() { void onSettingsChanged() {
var categories = List.from( var categories =
appdata.settings["categories"], List.from(appdata.settings["categories"]).whereType<String>().toList();
).whereType<String>().toList();
var allCategories = ComicSource.all() var allCategories = ComicSource.all()
.map((e) => e.categoryData?.key) .map((e) => e.categoryData?.key)
.where((element) => element != null) .where((element) => element != null)
.map((e) => e!) .map((e) => e!)
.toList(); .toList();
categories = categories categories =
.where((element) => allCategories.contains(element)) categories.where((element) => allCategories.contains(element)).toList();
.toList();
if (!categories.isEqualTo(this.categories)) { if (!categories.isEqualTo(this.categories)) {
setState(() { setState(() {
this.categories = categories; this.categories = categories;
}); });
controller = TabController(length: categories.length, vsync: this);
} }
} }
@override @override
void initState() { void initState() {
super.initState(); super.initState();
var categories = List.from( var categories =
appdata.settings["categories"], List.from(appdata.settings["categories"]).whereType<String>().toList();
).whereType<String>().toList();
var allCategories = ComicSource.all() var allCategories = ComicSource.all()
.map((e) => e.categoryData?.key) .map((e) => e.categoryData?.key)
.where((element) => element != null) .where((element) => element != null)
.map((e) => e!) .map((e) => e!)
.toList(); .toList();
this.categories = categories this.categories =
.where((element) => allCategories.contains(element)) categories.where((element) => allCategories.contains(element)).toList();
.toList();
appdata.settings.addListener(onSettingsChanged); appdata.settings.addListener(onSettingsChanged);
controller = TabController(length: categories.length, vsync: this);
} }
void addPage() { void addPage() {
@@ -70,7 +59,6 @@ class _CategoriesPageState extends State<CategoriesPage>
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
controller.dispose();
appdata.settings.removeListener(onSettingsChanged); appdata.settings.removeListener(onSettingsChanged);
} }
@@ -97,45 +85,46 @@ class _CategoriesPageState extends State<CategoriesPage>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context);
if (categories.isEmpty) { if (categories.isEmpty) {
return buildEmpty(); return buildEmpty();
} }
return Material( return Material(
child: Column( child: DefaultTabController(
children: [ length: categories.length,
AppTabBar( key: Key(categories.toString()),
controller: controller, child: Column(
key: PageStorageKey(categories.toString()), children: [
tabs: categories.map((e) { AppTabBar(
String title = e; key: PageStorageKey(categories.toString()),
try { tabs: categories.map((e) {
title = getCategoryDataWithKey(e).title; String title = e;
} catch (e) { try {
// title = getCategoryDataWithKey(e).title;
} } catch (e) {
return Tab(text: title, key: Key(e)); //
}).toList(), }
actionButton: TabActionButton( return Tab(
icon: const Icon(Icons.add), text: title,
text: "Add".tl, key: Key(e),
onPressed: addPage, );
), }).toList(),
).paddingTop(context.padding.top), actionButton: TabActionButton(
Expanded( icon: const Icon(Icons.add),
child: TabBarView( text: "Add".tl,
controller: controller, onPressed: addPage,
children: categories.map((e) => _CategoryPage(e)).toList(), ),
), ).paddingTop(context.padding.top),
), Expanded(
], child: TabBarView(
children: categories.map((e) => _CategoryPage(e)).toList(),
),
)
],
),
), ),
); );
} }
@override
bool get wantKeepAlive => true;
} }
typedef ClickTagCallback = void Function(String, String?); typedef ClickTagCallback = void Function(String, String?);
@@ -161,42 +150,38 @@ class _CategoryPage extends StatelessWidget {
var children = <Widget>[]; var children = <Widget>[];
if (data.enableRankingPage || data.buttons.isNotEmpty) { if (data.enableRankingPage || data.buttons.isNotEmpty) {
children.add(buildTitle(data.title)); children.add(buildTitle(data.title));
children.add( children.add(Padding(
Padding( padding: const EdgeInsets.fromLTRB(10, 0, 10, 16),
padding: const EdgeInsets.fromLTRB(10, 0, 10, 16), child: Wrap(
child: Wrap( children: [
children: [ if (data.enableRankingPage)
if (data.enableRankingPage) buildTag("Ranking".tl, () {
buildTag("Ranking".tl, () { context.to(() => RankingPage(categoryKey: data.key));
context.to(() => RankingPage(categoryKey: data.key)); }),
}), for (var buttonData in data.buttons)
for (var buttonData in data.buttons) buildTag(buttonData.label.tl, buttonData.onTap)
buildTag(buttonData.label.tl, buttonData.onTap), ],
],
),
), ),
); ));
} }
for (var part in data.categories) { for (var part in data.categories) {
if (part.enableRandom) { if (part.enableRandom) {
children.add( children.add(StatefulBuilder(builder: (context, updater) {
StatefulBuilder( return Column(
builder: (context, updater) { mainAxisSize: MainAxisSize.min,
return Column( crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, children: [
crossAxisAlignment: CrossAxisAlignment.start, buildTitleWithRefresh(part.title, () => updater(() {})),
children: [ buildTags(part.categories)
buildTitleWithRefresh(part.title, () => updater(() {})), ],
buildTags(part.categories), );
], }));
);
},
),
);
} else { } else {
children.add(buildTitle(part.title)); children.add(buildTitle(part.title));
children.add(buildTags(part.categories)); children.add(
buildTags(part.categories),
);
} }
} }
return SingleChildScrollView( return SingleChildScrollView(
@@ -210,10 +195,8 @@ class _CategoryPage extends StatelessWidget {
Widget buildTitle(String title) { Widget buildTitle(String title) {
return Padding( return Padding(
padding: const EdgeInsets.fromLTRB(16, 10, 5, 10), padding: const EdgeInsets.fromLTRB(16, 10, 5, 10),
child: Text( child: Text(title.tl,
title.tl, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500)),
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
); );
} }
@@ -224,16 +207,21 @@ class _CategoryPage extends StatelessWidget {
children: [ children: [
Text( Text(
title.tl, title.tl,
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500), style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
), ),
const Spacer(), const Spacer(),
IconButton(onPressed: onRefresh, icon: const Icon(Icons.refresh)), IconButton(onPressed: onRefresh, icon: const Icon(Icons.refresh))
], ],
), ),
); );
} }
Widget buildTags(List<CategoryItem> categories) { Widget buildTags(
List<CategoryItem> categories,
) {
return Padding( return Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 16), padding: const EdgeInsets.fromLTRB(10, 0, 10, 16),
child: Wrap( child: Wrap(

View File

@@ -155,60 +155,64 @@ abstract mixin class _ComicPageActions {
builder: (context, setState) { builder: (context, setState) {
return ContentDialog( return ContentDialog(
title: "Download".tl, title: "Download".tl,
content: RadioGroup<int>( content: Column(
groupValue: selected, mainAxisSize: MainAxisSize.min,
onChanged: (v) { children: [
setState(() { RadioListTile<int>(
selected = v ?? selected; value: -1,
}); groupValue: selected,
}, title: Text("Normal".tl),
child: Column( onChanged: (v) {
mainAxisSize: MainAxisSize.min, setState(() {
children: [ selected = v!;
RadioListTile<int>( });
value: -1, },
title: Text("Normal".tl), ),
ExpansionTile(
title: Text("Archive".tl),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero,
), ),
ExpansionTile( collapsedShape: const RoundedRectangleBorder(
title: Text("Archive".tl), borderRadius: BorderRadius.zero,
shape: const RoundedRectangleBorder( ),
borderRadius: BorderRadius.zero, onExpansionChanged: (b) {
), if (!isLoading && b && archives == null) {
collapsedShape: const RoundedRectangleBorder( isLoading = true;
borderRadius: BorderRadius.zero, comicSource.archiveDownloader!
), .getArchives(comic.id)
onExpansionChanged: (b) { .then((value) {
if (!isLoading && b && archives == null) { if (value.success) {
isLoading = true; archives = value.data;
comicSource.archiveDownloader! } else {
.getArchives(comic.id) App.rootContext
.then((value) { .showMessage(message: value.errorMessage!);
if (value.success) { }
archives = value.data; setState(() {
} else { isLoading = false;
App.rootContext
.showMessage(message: value.errorMessage!);
}
setState(() {
isLoading = false;
});
}); });
} });
}, }
children: [ },
if (archives == null) children: [
const ListLoadingIndicator().toCenter() if (archives == null)
else const ListLoadingIndicator().toCenter()
for (int i = 0; i < archives!.length; i++) else
RadioListTile<int>( for (int i = 0; i < archives!.length; i++)
value: i, RadioListTile<int>(
title: Text(archives![i].title), value: i,
subtitle: Text(archives![i].description), groupValue: selected,
) onChanged: (v) {
], setState(() {
) selected = v!;
], });
), },
title: Text(archives![i].title),
subtitle: Text(archives![i].description),
)
],
)
],
), ),
actions: [ actions: [
Button.filled( Button.filled(

View File

@@ -514,53 +514,51 @@ class _ImportComicsWidgetState extends State<_ImportComicsWidget> {
child: CircularProgressIndicator(), child: CircularProgressIndicator(),
), ),
) )
: RadioGroup<int>( : Column(
groupValue: type, key: key,
onChanged: (value) { crossAxisAlignment: CrossAxisAlignment.start,
setState(() { children: [
type = value ?? type; const SizedBox(width: 600),
}); ...List.generate(importMethods.length, (index) {
}, return RadioListTile(
child: Column( title: Text(importMethods[index]),
key: key, value: index,
crossAxisAlignment: CrossAxisAlignment.start, groupValue: type,
children: [ onChanged: (value) {
const SizedBox(width: 600), setState(() {
...List.generate(importMethods.length, (index) { type = value as int;
return RadioListTile<int>( });
title: Text(importMethods[index]), },
value: index, );
); }),
}), if (type != 4)
if (type != 4) ListTile(
ListTile( title: Text("Add to favorites".tl),
title: Text("Add to favorites".tl), trailing: Select(
trailing: Select( current: selectedFolder,
current: selectedFolder, values: folders,
values: folders, minWidth: 112,
minWidth: 112, onTap: (v) {
onTap: (v) { setState(() {
setState(() { selectedFolder = folders[v];
selectedFolder = folders[v]; });
}); },
}, ),
), ).paddingHorizontal(8),
).paddingHorizontal(8), if (!App.isIOS && !App.isMacOS && type != 2 && type != 3)
if (!App.isIOS && !App.isMacOS && type != 2 && type != 3) CheckboxListTile(
CheckboxListTile( enabled: true,
enabled: true, title: Text("Copy to app local path".tl),
title: Text("Copy to app local path".tl), value: copyToLocalFolder,
value: copyToLocalFolder, onChanged: (v) {
onChanged: (v) { setState(() {
setState(() { copyToLocalFolder = !copyToLocalFolder;
copyToLocalFolder = !copyToLocalFolder; });
}); }).paddingHorizontal(8),
}).paddingHorizontal(8), const SizedBox(height: 8),
const SizedBox(height: 8), Text(info).paddingHorizontal(24),
Text(info).paddingHorizontal(24), ],
], ),
),
),
actions: [ actions: [
Button.text( Button.text(
child: Row( child: Row(

View File

@@ -404,23 +404,21 @@ class _ImageFavoritesDialogState extends State<_ImageFavoritesDialog> {
children: [ children: [
tabBar, tabBar,
TabViewBody(children: [ TabViewBody(children: [
RadioGroup<ImageFavoriteSortType>( Column(
groupValue: sortType, children: ImageFavoriteSortType.values
onChanged: (v) { .map(
setState(() { (e) => RadioListTile<ImageFavoriteSortType>(
sortType = v ?? sortType; title: Text(e.value.tl),
}); value: e,
}, groupValue: sortType,
child: Column( onChanged: (v) {
children: ImageFavoriteSortType.values setState(() {
.map( sortType = v!;
(e) => RadioListTile<ImageFavoriteSortType>( });
title: Text(e.value.tl), },
value: e, ),
), )
) .toList(),
.toList(),
),
), ),
Column( Column(
children: [ children: [

View File

@@ -70,29 +70,39 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
return StatefulBuilder(builder: (context, setState) { return StatefulBuilder(builder: (context, setState) {
return ContentDialog( return ContentDialog(
title: "Sort".tl, title: "Sort".tl,
content: RadioGroup<LocalSortType>( content: Column(
groupValue: sortType, children: [
onChanged: (v) { RadioListTile<LocalSortType>(
setState(() { title: Text("Name".tl),
sortType = v ?? sortType; value: LocalSortType.name,
}); groupValue: sortType,
}, onChanged: (v) {
child: Column( setState(() {
children: [ sortType = v!;
RadioListTile<LocalSortType>( });
title: Text("Name".tl), },
value: LocalSortType.name, ),
), RadioListTile<LocalSortType>(
RadioListTile<LocalSortType>( title: Text("Date".tl),
title: Text("Date".tl), value: LocalSortType.timeAsc,
value: LocalSortType.timeAsc, groupValue: sortType,
), onChanged: (v) {
RadioListTile<LocalSortType>( setState(() {
title: Text("Date Desc".tl), sortType = v!;
value: LocalSortType.timeDesc, });
), },
], ),
), RadioListTile<LocalSortType>(
title: Text("Date Desc".tl),
value: LocalSortType.timeDesc,
groupValue: sortType,
onChanged: (v) {
setState(() {
sortType = v!;
});
},
),
],
), ),
actions: [ actions: [
FilledButton( FilledButton(

View File

@@ -428,26 +428,30 @@ class _WebdavSettingState extends State<_WebdavSetting> {
), ),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
RadioGroup<bool>( Row(
groupValue: upload, children: [
onChanged: (value) { Text("Operation".tl),
setState(() { Radio<bool>(
upload = value ?? upload; groupValue: upload,
}); value: true,
}, onChanged: (value) {
child: Row( setState(() {
children: [ upload = value!;
Text("Operation".tl), });
Radio<bool>( },
value: true, ),
), Text("Upload".tl),
Text("Upload".tl), Radio<bool>(
Radio<bool>( groupValue: upload,
value: false, value: false,
), onChanged: (value) {
Text("Download".tl), setState(() {
], upload = value!;
), });
},
),
Text("Download".tl),
],
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
AnimatedSize( AnimatedSize(

View File

@@ -111,34 +111,44 @@ class _ProxySettingViewState extends State<_ProxySettingView> {
return PopUpWidgetScaffold( return PopUpWidgetScaffold(
title: "Proxy".tl, title: "Proxy".tl,
body: SingleChildScrollView( body: SingleChildScrollView(
child: RadioGroup<String>( child: Column(
groupValue: type, children: [
onChanged: (v) { RadioListTile<String>(
setState(() { title: Text("Direct".tl),
type = v ?? type; value: 'direct',
}); groupValue: type,
if (type != 'manual') { onChanged: (v) {
appdata.settings['proxy'] = toProxyStr(); setState(() {
appdata.saveData(); type = v!;
} });
}, appdata.settings['proxy'] = toProxyStr();
child: Column( appdata.saveData();
children: [ },
RadioListTile<String>( ),
title: Text("Direct".tl), RadioListTile<String>(
value: 'direct', title: Text("System".tl),
), value: 'system',
RadioListTile<String>( groupValue: type,
title: Text("System".tl), onChanged: (v) {
value: 'system', setState(() {
), type = v!;
RadioListTile( });
title: Text("Manual".tl), appdata.settings['proxy'] = toProxyStr();
value: 'manual', appdata.saveData();
), },
if (type == 'manual') buildManualProxy(), ),
], RadioListTile(
), title: Text("Manual".tl),
value: 'manual',
groupValue: type,
onChanged: (v) {
setState(() {
type = v!;
});
},
),
if (type == 'manual') buildManualProxy(),
],
), ),
), ),
); );

View File

@@ -416,10 +416,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_memory_info name: flutter_memory_info
sha256: eacfd0dd01ff596b4e5bf022442769a1807a73f2af43d62802436f0a5de99137 sha256: "1f112f1d7503aa1681fc8e923f6cd0e847bb2fbeec3753ed021cf1e5f7e9cd74"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.0.3" version: "0.0.1"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: transitive
description: description:

View File

@@ -75,7 +75,7 @@ dependencies:
ref: fe182cdf40e5fa6230f451bc1d643b860f610d13 ref: fe182cdf40e5fa6230f451bc1d643b860f610d13
dynamic_color: ^1.7.0 dynamic_color: ^1.7.0
shimmer_animation: ^2.1.0 shimmer_animation: ^2.1.0
flutter_memory_info: ^0.0.3 flutter_memory_info: ^0.0.1
syntax_highlight: ^0.4.0 syntax_highlight: ^0.4.0
flutter_7zip: flutter_7zip:
git: git: