home page

This commit is contained in:
nyne
2024-09-29 21:49:57 +08:00
parent e8276f243c
commit 932e0c3896
6 changed files with 301 additions and 27 deletions

View File

@@ -144,7 +144,7 @@ class RandomCategoryPartWithRuntimeData extends BaseCategoryPart {
} }
CategoryData getCategoryDataWithKey(String key) { CategoryData getCategoryDataWithKey(String key) {
for (var source in ComicSource.sources) { for (var source in ComicSource._sources) {
if (source.categoryData?.key == key) { if (source.categoryData?.key == key) {
return source.categoryData!; return source.categoryData!;
} }

View File

@@ -43,13 +43,31 @@ typedef GetThumbnailLoadingConfigFunc = Map<String, dynamic> Function(
String imageKey)?; String imageKey)?;
class ComicSource { class ComicSource {
static List<ComicSource> sources = []; static final List<ComicSource> _sources = [];
static final List<Function> _listeners = [];
static void addListener(Function listener) {
_listeners.add(listener);
}
static void removeListener(Function listener) {
_listeners.remove(listener);
}
static void notifyListeners() {
for (var listener in _listeners) {
listener();
}
}
static List<ComicSource> all() => List.from(_sources);
static ComicSource? find(String key) => static ComicSource? find(String key) =>
sources.firstWhereOrNull((element) => element.key == key); _sources.firstWhereOrNull((element) => element.key == key);
static ComicSource? fromIntKey(int key) => static ComicSource? fromIntKey(int key) =>
sources.firstWhereOrNull((element) => element.key.hashCode == key); _sources.firstWhereOrNull((element) => element.key.hashCode == key);
static Future<void> init() async { static Future<void> init() async {
final path = "${App.dataPath}/comic_source"; final path = "${App.dataPath}/comic_source";
@@ -62,7 +80,7 @@ class ComicSource {
try { try {
var source = await ComicSourceParser() var source = await ComicSourceParser()
.parse(await entity.readAsString(), entity.absolute.path); .parse(await entity.readAsString(), entity.absolute.path);
sources.add(source); _sources.add(source);
} catch (e, s) { } catch (e, s) {
Log.error("ComicSource", "$e\n$s"); Log.error("ComicSource", "$e\n$s");
} }
@@ -71,9 +89,20 @@ class ComicSource {
} }
static Future reload() async { static Future reload() async {
sources.clear(); _sources.clear();
JsEngine().runCode("ComicSource.sources = {};"); JsEngine().runCode("ComicSource.sources = {};");
await init(); await init();
notifyListeners();
}
static void add(ComicSource source) {
_sources.add(source);
notifyListeners();
}
static void remove(String key) {
_sources.removeWhere((element) => element.key == key);
notifyListeners();
} }
/// Name of this source. /// Name of this source.
@@ -123,7 +152,7 @@ class ComicSource {
var data = <String, dynamic>{}; var data = <String, dynamic>{};
bool get isLogin => data["account"] != null; bool get isLogged => data["account"] != null;
final String filePath; final String filePath;

View File

@@ -105,7 +105,7 @@ class ComicSourceParser {
throw ComicSourceParseException("minAppVersion $minAppVersion is required"); throw ComicSourceParseException("minAppVersion $minAppVersion is required");
} }
} }
for(var source in ComicSource.sources){ for(var source in ComicSource.all()){
if(source.key == key){ if(source.key == key){
throw ComicSourceParseException("key($key) already exists"); throw ComicSourceParseException("key($key) already exists");
} }
@@ -188,8 +188,7 @@ class ComicSourceParser {
ComicSource.sources.$_key.account.login(${jsonEncode(account)}, ComicSource.sources.$_key.account.login(${jsonEncode(account)},
${jsonEncode(pwd)}) ${jsonEncode(pwd)})
"""); """);
var source = ComicSource.sources var source = ComicSource.find(_key!)!;
.firstWhere((element) => element.key == _key);
source.data["account"] = <String>[account, pwd]; source.data["account"] = <String>[account, pwd];
source.saveData(); source.saveData();
return const Res(true); return const Res(true);
@@ -461,7 +460,7 @@ class ComicSourceParser {
final bool multiFolder = _getValue("favorites.multiFolder"); final bool multiFolder = _getValue("favorites.multiFolder");
Future<Res<T>> retryZone<T>(Future<Res<T>> Function() func) async{ Future<Res<T>> retryZone<T>(Future<Res<T>> Function() func) async{
if(!ComicSource.find(_key!)!.isLogin){ if(!ComicSource.find(_key!)!.isLogged){
return const Res.error("Not login"); return const Res.error("Not login");
} }
var res = await func(); var res = await func();

View File

@@ -15,7 +15,7 @@ class ComicType {
if(this == local) { if(this == local) {
return null; return null;
} else { } else {
return ComicSource.sources.firstWhere((element) => element.intKey == value); return ComicSource.fromIntKey(value);
} }
} }

View File

@@ -22,7 +22,6 @@ import 'package:pointycastle/block/modes/ecb.dart';
import 'package:pointycastle/block/modes/ofb.dart'; import 'package:pointycastle/block/modes/ofb.dart';
import 'package:venera/network/app_dio.dart'; import 'package:venera/network/app_dio.dart';
import 'package:venera/network/cookie_jar.dart'; import 'package:venera/network/cookie_jar.dart';
import 'package:venera/utils/ext.dart';
import 'comic_source/comic_source.dart'; import 'comic_source/comic_source.dart';
import 'consts.dart'; import 'consts.dart';
@@ -107,8 +106,7 @@ class JsEngine with _JSEngineApi{
{ {
String key = message["key"]; String key = message["key"];
String dataKey = message["data_key"]; String dataKey = message["data_key"];
return ComicSource.sources return ComicSource.find(key)
.firstWhereOrNull((element) => element.key == key)
?.data[dataKey]; ?.data[dataKey];
} }
case 'save_data': case 'save_data':
@@ -116,8 +114,7 @@ class JsEngine with _JSEngineApi{
String key = message["key"]; String key = message["key"];
String dataKey = message["data_key"]; String dataKey = message["data_key"];
var data = message["data"]; var data = message["data"];
var source = ComicSource.sources var source = ComicSource.find(key)!;
.firstWhere((element) => element.key == key);
source.data[dataKey] = data; source.data[dataKey] = data;
source.saveData(); source.saveData();
} }
@@ -125,8 +122,7 @@ class JsEngine with _JSEngineApi{
{ {
String key = message["key"]; String key = message["key"];
String dataKey = message["data_key"]; String dataKey = message["data_key"];
var source = ComicSource.sources var source = ComicSource.find(key);
.firstWhereOrNull((element) => element.key == key);
source?.data.remove(dataKey); source?.data.remove(dataKey);
source?.saveData(); source?.saveData();
} }

View File

@@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:venera/components/components.dart'; import 'package:venera/components/components.dart';
import 'package:venera/foundation/app.dart'; import 'package:venera/foundation/app.dart';
import 'package:venera/foundation/comic_source/comic_source.dart';
import 'package:venera/foundation/comic_type.dart'; import 'package:venera/foundation/comic_type.dart';
import 'package:venera/foundation/history.dart'; import 'package:venera/foundation/history.dart';
import 'package:venera/foundation/image_provider/cached_image.dart'; import 'package:venera/foundation/image_provider/cached_image.dart';
@@ -21,19 +22,47 @@ class HomePage extends StatelessWidget {
slivers: [ slivers: [
_History(), _History(),
_Local(), _Local(),
_ComicSourceWidget(),
_AccountsWidget(),
], ],
); );
} }
} }
class _History extends StatelessWidget { class _History extends StatefulWidget {
const _History(); const _History();
@override @override
Widget build(BuildContext context) { State<_History> createState() => _HistoryState();
final history = HistoryManager().getRecent(); }
final count = HistoryManager().count();
class _HistoryState extends State<_History> {
late List<History> history;
late int count;
void onHistoryChange() {
setState(() {
history = HistoryManager().getRecent();
count = HistoryManager().count();
});
}
@override
void initState() {
history = HistoryManager().getRecent();
count = HistoryManager().count();
HistoryManager().addListener(onHistoryChange);
super.initState();
}
@override
void dispose() {
HistoryManager().removeListener(onHistoryChange);
super.dispose();
}
@override
Widget build(BuildContext context) {
return SliverToBoxAdapter( return SliverToBoxAdapter(
child: InkWell( child: InkWell(
onTap: () {}, onTap: () {},
@@ -117,14 +146,40 @@ class _History extends StatelessWidget {
} }
} }
class _Local extends StatelessWidget { class _Local extends StatefulWidget {
const _Local(); const _Local();
@override @override
Widget build(BuildContext context) { State<_Local> createState() => _LocalState();
final local = LocalManager().getRecent(); }
final count = LocalManager().count;
class _LocalState extends State<_Local> {
late List<LocalComic> local;
late int count;
void onLocalComicsChange() {
setState(() {
local = LocalManager().getRecent();
count = LocalManager().count;
});
}
@override
void initState() {
local = LocalManager().getRecent();
count = LocalManager().count;
LocalManager().addListener(onLocalComicsChange);
super.initState();
}
@override
void dispose() {
LocalManager().removeListener(onLocalComicsChange);
super.dispose();
}
@override
Widget build(BuildContext context) {
return SliverToBoxAdapter( return SliverToBoxAdapter(
child: InkWell( child: InkWell(
onTap: () {}, onTap: () {},
@@ -495,3 +550,198 @@ class _ImportComicsWidgetState extends State<_ImportComicsWidget> {
); );
} }
} }
class _ComicSourceWidget extends StatefulWidget {
const _ComicSourceWidget();
@override
State<_ComicSourceWidget> createState() => _ComicSourceWidgetState();
}
class _ComicSourceWidgetState extends State<_ComicSourceWidget> {
late List<String> comicSources;
void onComicSourceChange() {
setState(() {
comicSources = ComicSource.all().map((e) => e.name).toList();
});
}
@override
void initState() {
comicSources = ComicSource.all().map((e) => e.name).toList();
ComicSource.addListener(onComicSourceChange);
super.initState();
}
@override
void dispose() {
ComicSource.removeListener(onComicSourceChange);
super.dispose();
}
@override
Widget build(BuildContext context) {
return SliverToBoxAdapter(
child: InkWell(
onTap: () {},
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).colorScheme.outlineVariant,
width: 0.6,
),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 56,
child: Row(
children: [
Center(
child: Text('Comic Source'.tl, style: ts.s18),
),
Container(
margin: const EdgeInsets.symmetric(horizontal: 8),
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(8),
),
child: Text(comicSources.length.toString(), style: ts.s12),
),
const Spacer(),
const Icon(Icons.arrow_right),
],
),
).paddingHorizontal(16),
SizedBox(
width: double.infinity,
child: Wrap(
children: comicSources.map((e) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8),
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(8),
),
child: Text(e),
);
}).toList(),
),
),
],
),
),
),
);
}
}
class _AccountsWidget extends StatefulWidget {
const _AccountsWidget();
@override
State<_AccountsWidget> createState() => _AccountsWidgetState();
}
class _AccountsWidgetState extends State<_AccountsWidget> {
late List<String> accounts;
void onComicSourceChange() {
setState(() {
for(var c in ComicSource.all()) {
if(c.isLogged) {
accounts.add(c.name);
}
}
});
}
@override
void initState() {
accounts = [];
for(var c in ComicSource.all()) {
if(c.isLogged) {
accounts.add(c.name);
}
}
ComicSource.addListener(onComicSourceChange);
super.initState();
}
@override
void dispose() {
ComicSource.removeListener(onComicSourceChange);
super.dispose();
}
@override
Widget build(BuildContext context) {
return SliverToBoxAdapter(
child: InkWell(
onTap: () {},
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).colorScheme.outlineVariant,
width: 0.6,
),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 56,
child: Row(
children: [
Center(
child: Text('Accounts'.tl, style: ts.s18),
),
Container(
margin: const EdgeInsets.symmetric(horizontal: 8),
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(8),
),
child: Text(accounts.length.toString(), style: ts.s12),
),
const Spacer(),
const Icon(Icons.arrow_right),
],
),
).paddingHorizontal(16),
SizedBox(
width: double.infinity,
child: Wrap(
children: accounts.map((e) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8),
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(8),
),
child: Text(e),
);
}).toList(),
),
),
],
),
),
),
);
}
}