From ddf6c0ddcba54e13f628a8eec446b300c2720fa8 Mon Sep 17 00:00:00 2001 From: MiaoMint <1981324730@qq.com> Date: Thu, 27 Jul 2023 03:01:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=BC=AB=E7=94=BB=E3=80=81=E5=B0=8F?= =?UTF-8?q?=E8=AF=B4=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- assets/i18n/en.json | 11 + assets/i18n/zh.json | 11 + lib/models/index.dart | 1 + lib/models/manga_setting.dart | 21 + lib/models/manga_setting.g.dart | 750 ++++++++++++++++++ lib/pages/search/widgets/search_all_tile.dart | 4 +- .../widgets/reader/comic/comic_reader.dart | 13 +- .../reader/comic/comic_reader_content.dart | 145 +++- .../reader/comic/comic_reader_settings.dart | 126 +++ .../widgets/reader/comic/controller.dart | 88 ++ .../widgets/reader/control_panel_footer.dart | 4 +- .../widgets/reader/control_panel_header.dart | 12 +- .../widgets/reader/novel/controller.dart | 28 + .../widgets/reader/novel/novel_reader.dart | 59 +- .../reader/novel/novel_reader_content.dart | 16 +- .../reader/novel/novel_reader_settings.dart | 77 ++ lib/pages/watch/widgets/reader/view.dart | 6 +- lib/utils/database.dart | 26 +- lib/utils/miru_storage.dart | 13 +- lib/widgets/horizontal_list.dart | 4 +- pubspec.lock | 2 +- pubspec.yaml | 3 +- 23 files changed, 1291 insertions(+), 131 deletions(-) create mode 100644 lib/models/manga_setting.dart create mode 100644 lib/models/manga_setting.g.dart create mode 100644 lib/pages/watch/widgets/reader/comic/comic_reader_settings.dart create mode 100644 lib/pages/watch/widgets/reader/comic/controller.dart create mode 100644 lib/pages/watch/widgets/reader/novel/controller.dart create mode 100644 lib/pages/watch/widgets/reader/novel/novel_reader_settings.dart diff --git a/README.md b/README.md index d923ae0c..b2aa603c 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Miru App - [x] i18n 国际化 - [x] 扩展设置 - [x] 影视播放进度 -- [ ] 漫画小说视频设置 +- [x] 漫画小说设置 - [ ] 漫画小说历史记录 - [ ] TMDB 元数据 - [ ] 字幕 diff --git a/assets/i18n/en.json b/assets/i18n/en.json index b54e5e1d..e7e7bef0 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -94,6 +94,17 @@ "resume-last-playback": "Resume last playback" }, + "comic-settings": { + "read-mode": "Read mode", + "standard": "Standard", + "right-to-left": "Right to left", + "web-tonn": "Web Tonn" + }, + + "novel-settings": { + "font-size": "Font size" + }, + "reader": { "chapters": "Chapters", "read-now": "Read Now", diff --git a/assets/i18n/zh.json b/assets/i18n/zh.json index 40357146..a33afe8a 100644 --- a/assets/i18n/zh.json +++ b/assets/i18n/zh.json @@ -105,6 +105,17 @@ "no-chapters": "暂无章节" }, + "comic-settings": { + "read-mode": "漫画阅读模式", + "standard": "标准", + "right-to-left": "从右到左", + "web-tonn": "条漫" + }, + + "novel-settings": { + "font-size": "字体大小" + }, + "upgrade": { "check-update": "检查更新", "new-version": "检测到新版本 {version}", diff --git a/lib/models/index.dart b/lib/models/index.dart index 4a6f7095..3e4f0001 100644 --- a/lib/models/index.dart +++ b/lib/models/index.dart @@ -2,3 +2,4 @@ export 'extension.dart'; export 'favorite.dart'; export 'history.dart'; export 'extension_setting.dart'; +export 'manga_setting.dart'; diff --git a/lib/models/manga_setting.dart b/lib/models/manga_setting.dart new file mode 100644 index 00000000..1f37b57a --- /dev/null +++ b/lib/models/manga_setting.dart @@ -0,0 +1,21 @@ +import 'package:isar/isar.dart'; + +part 'manga_setting.g.dart'; + +enum MangaReadMode { + // 标准 从左到右 + standard, + // 从右到左 + rightToLeft, + // 条漫 + webTonn, +} + +@collection +class MangaSetting { + Id id = Isar.autoIncrement; + @Index(unique: true) + late String url; + @Enumerated(EnumType.name) + late MangaReadMode readMode; +} diff --git a/lib/models/manga_setting.g.dart b/lib/models/manga_setting.g.dart new file mode 100644 index 00000000..47f074e0 --- /dev/null +++ b/lib/models/manga_setting.g.dart @@ -0,0 +1,750 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'manga_setting.dart'; + +// ************************************************************************** +// IsarCollectionGenerator +// ************************************************************************** + +// coverage:ignore-file +// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types + +extension GetMangaSettingCollection on Isar { + IsarCollection get mangaSettings => this.collection(); +} + +const MangaSettingSchema = CollectionSchema( + name: r'MangaSetting', + id: -6684337324789595454, + properties: { + r'readMode': PropertySchema( + id: 0, + name: r'readMode', + type: IsarType.string, + enumMap: _MangaSettingreadModeEnumValueMap, + ), + r'url': PropertySchema( + id: 1, + name: r'url', + type: IsarType.string, + ) + }, + estimateSize: _mangaSettingEstimateSize, + serialize: _mangaSettingSerialize, + deserialize: _mangaSettingDeserialize, + deserializeProp: _mangaSettingDeserializeProp, + idName: r'id', + indexes: { + r'url': IndexSchema( + id: -5756857009679432345, + name: r'url', + unique: true, + replace: false, + properties: [ + IndexPropertySchema( + name: r'url', + type: IndexType.hash, + caseSensitive: true, + ) + ], + ) + }, + links: {}, + embeddedSchemas: {}, + getId: _mangaSettingGetId, + getLinks: _mangaSettingGetLinks, + attach: _mangaSettingAttach, + version: '3.1.0+1', +); + +int _mangaSettingEstimateSize( + MangaSetting object, + List offsets, + Map> allOffsets, +) { + var bytesCount = offsets.last; + bytesCount += 3 + object.readMode.name.length * 3; + bytesCount += 3 + object.url.length * 3; + return bytesCount; +} + +void _mangaSettingSerialize( + MangaSetting object, + IsarWriter writer, + List offsets, + Map> allOffsets, +) { + writer.writeString(offsets[0], object.readMode.name); + writer.writeString(offsets[1], object.url); +} + +MangaSetting _mangaSettingDeserialize( + Id id, + IsarReader reader, + List offsets, + Map> allOffsets, +) { + final object = MangaSetting(); + object.id = id; + object.readMode = + _MangaSettingreadModeValueEnumMap[reader.readStringOrNull(offsets[0])] ?? + MangaReadMode.standard; + object.url = reader.readString(offsets[1]); + return object; +} + +P _mangaSettingDeserializeProp

( + IsarReader reader, + int propertyId, + int offset, + Map> allOffsets, +) { + switch (propertyId) { + case 0: + return (_MangaSettingreadModeValueEnumMap[ + reader.readStringOrNull(offset)] ?? + MangaReadMode.standard) as P; + case 1: + return (reader.readString(offset)) as P; + default: + throw IsarError('Unknown property with id $propertyId'); + } +} + +const _MangaSettingreadModeEnumValueMap = { + r'standard': r'standard', + r'rightToLeft': r'rightToLeft', + r'webTonn': r'webTonn', +}; +const _MangaSettingreadModeValueEnumMap = { + r'standard': MangaReadMode.standard, + r'rightToLeft': MangaReadMode.rightToLeft, + r'webTonn': MangaReadMode.webTonn, +}; + +Id _mangaSettingGetId(MangaSetting object) { + return object.id; +} + +List> _mangaSettingGetLinks(MangaSetting object) { + return []; +} + +void _mangaSettingAttach( + IsarCollection col, Id id, MangaSetting object) { + object.id = id; +} + +extension MangaSettingByIndex on IsarCollection { + Future getByUrl(String url) { + return getByIndex(r'url', [url]); + } + + MangaSetting? getByUrlSync(String url) { + return getByIndexSync(r'url', [url]); + } + + Future deleteByUrl(String url) { + return deleteByIndex(r'url', [url]); + } + + bool deleteByUrlSync(String url) { + return deleteByIndexSync(r'url', [url]); + } + + Future> getAllByUrl(List urlValues) { + final values = urlValues.map((e) => [e]).toList(); + return getAllByIndex(r'url', values); + } + + List getAllByUrlSync(List urlValues) { + final values = urlValues.map((e) => [e]).toList(); + return getAllByIndexSync(r'url', values); + } + + Future deleteAllByUrl(List urlValues) { + final values = urlValues.map((e) => [e]).toList(); + return deleteAllByIndex(r'url', values); + } + + int deleteAllByUrlSync(List urlValues) { + final values = urlValues.map((e) => [e]).toList(); + return deleteAllByIndexSync(r'url', values); + } + + Future putByUrl(MangaSetting object) { + return putByIndex(r'url', object); + } + + Id putByUrlSync(MangaSetting object, {bool saveLinks = true}) { + return putByIndexSync(r'url', object, saveLinks: saveLinks); + } + + Future> putAllByUrl(List objects) { + return putAllByIndex(r'url', objects); + } + + List putAllByUrlSync(List objects, + {bool saveLinks = true}) { + return putAllByIndexSync(r'url', objects, saveLinks: saveLinks); + } +} + +extension MangaSettingQueryWhereSort + on QueryBuilder { + QueryBuilder anyId() { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(const IdWhereClause.any()); + }); + } +} + +extension MangaSettingQueryWhere + on QueryBuilder { + QueryBuilder idEqualTo(Id id) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: id, + upper: id, + )); + }); + } + + QueryBuilder idNotEqualTo( + Id id) { + return QueryBuilder.apply(this, (query) { + if (query.whereSort == Sort.asc) { + return query + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ) + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ); + } else { + return query + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ) + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ); + } + }); + } + + QueryBuilder idGreaterThan( + Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: include), + ); + }); + } + + QueryBuilder idLessThan(Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: include), + ); + }); + } + + QueryBuilder idBetween( + Id lowerId, + Id upperId, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder urlEqualTo( + String url) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IndexWhereClause.equalTo( + indexName: r'url', + value: [url], + )); + }); + } + + QueryBuilder urlNotEqualTo( + String url) { + return QueryBuilder.apply(this, (query) { + if (query.whereSort == Sort.asc) { + return query + .addWhereClause(IndexWhereClause.between( + indexName: r'url', + lower: [], + upper: [url], + includeUpper: false, + )) + .addWhereClause(IndexWhereClause.between( + indexName: r'url', + lower: [url], + includeLower: false, + upper: [], + )); + } else { + return query + .addWhereClause(IndexWhereClause.between( + indexName: r'url', + lower: [url], + includeLower: false, + upper: [], + )) + .addWhereClause(IndexWhereClause.between( + indexName: r'url', + lower: [], + upper: [url], + includeUpper: false, + )); + } + }); + } +} + +extension MangaSettingQueryFilter + on QueryBuilder { + QueryBuilder idEqualTo( + Id value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idGreaterThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idLessThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idBetween( + Id lower, + Id upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder + readModeEqualTo( + MangaReadMode value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'readMode', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + readModeGreaterThan( + MangaReadMode value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'readMode', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + readModeLessThan( + MangaReadMode value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'readMode', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + readModeBetween( + MangaReadMode lower, + MangaReadMode upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'readMode', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + readModeStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'readMode', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + readModeEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'readMode', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + readModeContains(String value, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'readMode', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + readModeMatches(String pattern, {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'readMode', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + readModeIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'readMode', + value: '', + )); + }); + } + + QueryBuilder + readModeIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'readMode', + value: '', + )); + }); + } + + QueryBuilder urlEqualTo( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'url', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder + urlGreaterThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'url', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder urlLessThan( + String value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'url', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder urlBetween( + String lower, + String upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'url', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder urlStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'url', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder urlEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'url', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder urlContains( + String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'url', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder urlMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'url', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder urlIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'url', + value: '', + )); + }); + } + + QueryBuilder + urlIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'url', + value: '', + )); + }); + } +} + +extension MangaSettingQueryObject + on QueryBuilder {} + +extension MangaSettingQueryLinks + on QueryBuilder {} + +extension MangaSettingQuerySortBy + on QueryBuilder { + QueryBuilder sortByReadMode() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'readMode', Sort.asc); + }); + } + + QueryBuilder sortByReadModeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'readMode', Sort.desc); + }); + } + + QueryBuilder sortByUrl() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'url', Sort.asc); + }); + } + + QueryBuilder sortByUrlDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'url', Sort.desc); + }); + } +} + +extension MangaSettingQuerySortThenBy + on QueryBuilder { + QueryBuilder thenById() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.asc); + }); + } + + QueryBuilder thenByIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.desc); + }); + } + + QueryBuilder thenByReadMode() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'readMode', Sort.asc); + }); + } + + QueryBuilder thenByReadModeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'readMode', Sort.desc); + }); + } + + QueryBuilder thenByUrl() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'url', Sort.asc); + }); + } + + QueryBuilder thenByUrlDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'url', Sort.desc); + }); + } +} + +extension MangaSettingQueryWhereDistinct + on QueryBuilder { + QueryBuilder distinctByReadMode( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'readMode', caseSensitive: caseSensitive); + }); + } + + QueryBuilder distinctByUrl( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'url', caseSensitive: caseSensitive); + }); + } +} + +extension MangaSettingQueryProperty + on QueryBuilder { + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'id'); + }); + } + + QueryBuilder + readModeProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'readMode'); + }); + } + + QueryBuilder urlProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'url'); + }); + } +} diff --git a/lib/pages/search/widgets/search_all_tile.dart b/lib/pages/search/widgets/search_all_tile.dart index a2d72412..533450a7 100644 --- a/lib/pages/search/widgets/search_all_tile.dart +++ b/lib/pages/search/widgets/search_all_tile.dart @@ -52,14 +52,14 @@ class _SearchAllTileState extends State { } return SizedBox( - height: Platform.isAndroid ? 186 : 280, + height: Platform.isAndroid ? 170 : 280, child: ListView.builder( scrollDirection: Axis.horizontal, controller: controller, itemCount: data!.length, itemBuilder: ((context, index) { return Container( - width: Platform.isAndroid ? 128 : 170, + width: Platform.isAndroid ? 110 : 170, margin: const EdgeInsets.only(right: 16), child: ExtensionItemCard( key: ValueKey(data[index].url), diff --git a/lib/pages/watch/widgets/reader/comic/comic_reader.dart b/lib/pages/watch/widgets/reader/comic/comic_reader.dart index 90eb3dee..8d31fad7 100644 --- a/lib/pages/watch/widgets/reader/comic/comic_reader.dart +++ b/lib/pages/watch/widgets/reader/comic/comic_reader.dart @@ -2,7 +2,8 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; import 'package:miru_app/models/extension.dart'; import 'package:miru_app/pages/watch/widgets/reader/comic/comic_reader_content.dart'; -import 'package:miru_app/pages/watch/reader_controller.dart'; +import 'package:miru_app/pages/watch/widgets/reader/comic/comic_reader_settings.dart'; +import 'package:miru_app/pages/watch/widgets/reader/comic/controller.dart'; import 'package:miru_app/pages/watch/widgets/reader/view.dart'; import 'package:miru_app/utils/extension_runtime.dart'; import 'package:window_manager/window_manager.dart'; @@ -32,8 +33,8 @@ class ComicReader extends StatefulWidget { class _ComicReaderState extends State { @override void initState() { - Get.put>( - ReaderController( + Get.put( + ComicController( title: widget.title, playList: widget.playList, detailUrl: widget.detailUrl, @@ -48,18 +49,18 @@ class _ComicReaderState extends State { @override void dispose() { - Get.delete>(tag: widget.title); + Get.delete(tag: widget.title); super.dispose(); } @override Widget build(BuildContext context) { - return ReadView( + return ReadView( widget.title, content: DragToMoveArea( child: ComicReaderContent(widget.title), ), - buildSettings: (context) => const SizedBox(), + buildSettings: (context) => ComicReaderSettings(widget.title), ); } } diff --git a/lib/pages/watch/widgets/reader/comic/comic_reader_content.dart b/lib/pages/watch/widgets/reader/comic/comic_reader_content.dart index 90481dab..e3cfc616 100644 --- a/lib/pages/watch/widgets/reader/comic/comic_reader_content.dart +++ b/lib/pages/watch/widgets/reader/comic/comic_reader_content.dart @@ -1,15 +1,17 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:get/get.dart'; -import 'package:miru_app/models/extension.dart'; import 'package:fluent_ui/fluent_ui.dart' as fluent; -import 'package:miru_app/pages/watch/reader_controller.dart'; +import 'package:miru_app/models/index.dart'; +import 'package:miru_app/pages/watch/widgets/reader/comic/controller.dart'; import 'package:miru_app/utils/i18n.dart'; import 'package:miru_app/widgets/button.dart'; import 'package:miru_app/widgets/cache_network_image.dart'; import 'package:miru_app/widgets/platform_widget.dart'; import 'package:miru_app/widgets/progress_ring.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; class ComicReaderContent extends StatefulWidget { const ComicReaderContent(this.tag, {Key? key}) : super(key: key); @@ -20,10 +22,7 @@ class ComicReaderContent extends StatefulWidget { } class _ComicReaderContentState extends State { - late final c = Get.find>( - tag: widget.tag, - ); - + late final _c = Get.find(tag: widget.tag); _buildContent() { late Color backgroundColor; if (Platform.isAndroid) { @@ -31,47 +30,109 @@ class _ComicReaderContentState extends State { } else { backgroundColor = fluent.FluentTheme.of(context).micaBackgroundColor; } - return Container( - color: backgroundColor, - width: double.infinity, - child: LayoutBuilder(builder: ((context, constraints) { - final maxWidth = constraints.maxWidth; - return Obx(() { - if (c.error.value.isNotEmpty) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(c.error.value), - PlatformButton( - child: Text('common.retry'.i18n), - onPressed: () { - c.getContent(); - }, - ) - ], - ); + return RawKeyboardListener( + focusNode: FocusNode(), + autofocus: true, + onKey: (event) { + // 上下 + if (event.isKeyPressed(LogicalKeyboardKey.arrowUp)) { + if (_c.readerType.value == MangaReadMode.webTonn) { + return _c.previousPage(); + } + } + if (event.isKeyPressed(LogicalKeyboardKey.arrowDown)) { + if (_c.readerType.value == MangaReadMode.webTonn) { + return _c.nextPage(); } + } - if (c.watchData.value == null) { - return const Center(child: ProgressRing()); + if (event.isKeyPressed(LogicalKeyboardKey.arrowLeft)) { + if (_c.readerType.value == MangaReadMode.rightToLeft) { + return _c.nextPage(); } - final listviewPadding = maxWidth > 800 ? ((maxWidth - 800) / 2) : 0.0; + _c.previousPage(); + } - return ListView.builder( - padding: EdgeInsets.symmetric( - horizontal: listviewPadding, - ), - itemBuilder: (context, index) { - final url = c.watchData.value!.urls[index]; - return CacheNetWorkImage( - url, - fit: BoxFit.fitWidth, + if (event.isKeyPressed(LogicalKeyboardKey.arrowRight)) { + if (_c.readerType.value == MangaReadMode.rightToLeft) { + return _c.previousPage(); + } + _c.nextPage(); + } + }, + child: Container( + color: backgroundColor, + width: double.infinity, + child: LayoutBuilder(builder: ((context, constraints) { + final maxWidth = constraints.maxWidth; + return Obx(() { + if (_c.error.value.isNotEmpty) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(_c.error.value), + PlatformButton( + child: Text('common.retry'.i18n), + onPressed: () { + _c.getContent(); + }, + ) + ], ); - }, - itemCount: c.watchData.value!.urls.length, - ); - }); - })), + } + + if (_c.watchData.value == null) { + return const Center(child: ProgressRing()); + } + final viewPadding = maxWidth > 800 ? ((maxWidth - 800) / 2) : 0.0; + + final images = _c.watchData.value!.urls; + final readerType = _c.readerType.value; + final cuurentPage = _c.currentPage.value; + + if (readerType == MangaReadMode.webTonn) { + return ScrollablePositionedList.builder( + padding: EdgeInsets.symmetric( + horizontal: viewPadding, + ), + initialScrollIndex: cuurentPage, + itemPositionsListener: _c.itemPositionsListener, + scrollOffsetController: _c.scrollOffsetController, + itemBuilder: (context, index) { + final url = images[index]; + return CacheNetWorkImage( + url, + fit: BoxFit.fitWidth, + ); + }, + itemCount: images.length, + ); + } + + return PageView.builder( + reverse: readerType == MangaReadMode.rightToLeft, + controller: _c.pageController.value, + onPageChanged: (index) { + _c.currentPage.value = index; + }, + itemBuilder: (context, index) { + final url = images[index]; + return Container( + padding: EdgeInsets.symmetric( + horizontal: viewPadding, + ), + child: CacheNetWorkImage( + url, + key: ValueKey(url), + fit: BoxFit.contain, + ), + ); + }, + itemCount: images.length, + ); + }); + })), + ), ); } diff --git a/lib/pages/watch/widgets/reader/comic/comic_reader_settings.dart b/lib/pages/watch/widgets/reader/comic/comic_reader_settings.dart new file mode 100644 index 00000000..856c4b5b --- /dev/null +++ b/lib/pages/watch/widgets/reader/comic/comic_reader_settings.dart @@ -0,0 +1,126 @@ +import 'package:fluent_ui/fluent_ui.dart' as fluent; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:miru_app/models/index.dart'; +import 'package:miru_app/pages/watch/widgets/reader/comic/controller.dart'; +import 'package:miru_app/utils/i18n.dart'; +import 'package:miru_app/widgets/platform_widget.dart'; + +class ComicReaderSettings extends StatefulWidget { + const ComicReaderSettings(this.tag, {Key? key}) : super(key: key); + final String tag; + + @override + State createState() => _ComicReaderSettingsState(); +} + +class _ComicReaderSettingsState extends State { + late final ComicController _c = Get.find(tag: widget.tag); + + Widget _buildAndroid(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 阅读模式 + Text('comic-settings.read-mode'.i18n), + const SizedBox(height: 16), + SizedBox( + width: double.infinity, + child: SegmentedButton( + segments: [ + ButtonSegment( + value: MangaReadMode.standard, + label: Text('comic-settings.standard'.i18n), + ), + ButtonSegment( + value: MangaReadMode.rightToLeft, + label: Text('comic-settings.right-to-left'.i18n), + ), + ButtonSegment( + value: MangaReadMode.webTonn, + label: Text('comic-settings.web-tonn'.i18n), + ), + ], + selected: {_c.readerType.value}, + onSelectionChanged: (value) { + if (value.isNotEmpty) { + setState(() { + _c.readerType.value = value.first; + }); + } + }, + showSelectedIcon: false, + ), + ), + ], + ), + ); + } + + Widget _buildDesktop(BuildContext context) { + return Obx(() { + return fluent.Card( + backgroundColor: fluent.FluentTheme.of(context).micaBackgroundColor, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('comic-settings.read-mode'.i18n), + const SizedBox(height: 16), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + fluent.ToggleButton( + checked: _c.readerType.value == MangaReadMode.standard, + onChanged: (value) { + if (value) { + setState(() { + _c.readerType.value = MangaReadMode.standard; + }); + } + }, + child: Text('comic-settings.standard'.i18n), + ), + const SizedBox(width: 8), + fluent.ToggleButton( + checked: _c.readerType.value == MangaReadMode.rightToLeft, + onChanged: (value) { + if (value) { + setState(() { + _c.readerType.value = MangaReadMode.rightToLeft; + }); + } + }, + child: Text('comic-settings.right-to-left'.i18n), + ), + const SizedBox(width: 8), + fluent.ToggleButton( + checked: _c.readerType.value == MangaReadMode.webTonn, + onChanged: (value) { + if (value) { + setState(() { + _c.readerType.value = MangaReadMode.webTonn; + }); + } + }, + child: Text('comic-settings.web-tonn'.i18n), + ) + ], + ) + ], + ), + ); + }); + } + + @override + Widget build(BuildContext context) { + return PlatformBuildWidget( + androidBuilder: _buildAndroid, + desktopBuilder: _buildDesktop, + ); + } +} diff --git a/lib/pages/watch/widgets/reader/comic/controller.dart b/lib/pages/watch/widgets/reader/comic/controller.dart new file mode 100644 index 00000000..83567bd5 --- /dev/null +++ b/lib/pages/watch/widgets/reader/comic/controller.dart @@ -0,0 +1,88 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:get/get.dart'; +import 'package:miru_app/models/index.dart'; +import 'package:miru_app/pages/watch/reader_controller.dart'; +import 'package:miru_app/utils/database.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; + +class ComicController extends ReaderController { + ComicController({ + required super.title, + required super.playList, + required super.detailUrl, + required super.playIndex, + required super.episodeGroupId, + required super.runtime, + }); + + final readerType = MangaReadMode.standard.obs; + // 当前页码 + final currentPage = 0.obs; + + final pageController = PageController().obs; + final itemPositionsListener = ItemPositionsListener.create(); + final scrollOffsetController = ScrollOffsetController(); + + @override + void onInit() { + initSettings(); + itemPositionsListener.itemPositions.addListener(() { + if (itemPositionsListener.itemPositions.value.isEmpty) { + return; + } + final pos = itemPositionsListener.itemPositions.value.first; + currentPage.value = pos.index; + }); + ever(readerType, (callback) { + if (pageController.value.hasClients) { + pageController.value.jumpToPage(currentPage.value); + } else { + pageController.value = PageController(initialPage: currentPage.value); + } + // 保存设置 + DatabaseUtils.setMangaReaderType( + super.detailUrl, + callback, + ); + }); + // 如果切换章节,重置当前页码 + ever(super.index, (callback) => currentPage.value = 0); + super.onInit(); + } + + initSettings() async { + readerType.value = await DatabaseUtils.getMnagaReaderType(super.detailUrl); + } + + // 下一页 + void nextPage() { + if (readerType.value != MangaReadMode.webTonn) { + pageController.value.nextPage( + duration: const Duration(milliseconds: 300), + curve: Curves.ease, + ); + } else { + scrollOffsetController.animateScroll( + duration: const Duration(milliseconds: 100), + curve: Curves.ease, + offset: 200.0, + ); + } + } + + // 上一页 + void previousPage() { + if (readerType.value != MangaReadMode.webTonn) { + pageController.value.previousPage( + duration: const Duration(milliseconds: 300), + curve: Curves.ease, + ); + } else { + scrollOffsetController.animateScroll( + duration: const Duration(milliseconds: 100), + curve: Curves.ease, + offset: -200.0, + ); + } + } +} diff --git a/lib/pages/watch/widgets/reader/control_panel_footer.dart b/lib/pages/watch/widgets/reader/control_panel_footer.dart index 99563d4f..88dd472c 100644 --- a/lib/pages/watch/widgets/reader/control_panel_footer.dart +++ b/lib/pages/watch/widgets/reader/control_panel_footer.dart @@ -7,13 +7,13 @@ import 'package:miru_app/pages/watch/reader_controller.dart'; import 'package:miru_app/utils/i18n.dart'; import 'package:miru_app/widgets/button.dart'; -class ControlPanelFooter extends StatelessWidget { +class ControlPanelFooter extends StatelessWidget { const ControlPanelFooter(this.tag, {Key? key}) : super(key: key); final String tag; @override Widget build(BuildContext context) { - final c = Get.find>(tag: tag); + final c = Get.find(tag: tag); return Container( height: 80, padding: const EdgeInsets.symmetric(horizontal: 20), diff --git a/lib/pages/watch/widgets/reader/control_panel_header.dart b/lib/pages/watch/widgets/reader/control_panel_header.dart index 429bac4d..558217e9 100644 --- a/lib/pages/watch/widgets/reader/control_panel_header.dart +++ b/lib/pages/watch/widgets/reader/control_panel_header.dart @@ -9,7 +9,7 @@ import 'package:miru_app/utils/router.dart'; import 'package:miru_app/widgets/platform_widget.dart'; import 'package:window_manager/window_manager.dart'; -class ControlPanelHeader extends StatefulWidget { +class ControlPanelHeader extends StatefulWidget { const ControlPanelHeader( this.tag, { Key? key, @@ -22,8 +22,9 @@ class ControlPanelHeader extends StatefulWidget { State createState() => _ControlPanelHeaderState(); } -class _ControlPanelHeaderState extends State { - late final _c = Get.find>(tag: widget.tag); +class _ControlPanelHeaderState + extends State { + late final _c = Get.find(tag: widget.tag); final fluent.FlyoutController _playListFlayoutcontroller = fluent.FlyoutController(); final fluent.FlyoutController _settingFlayoutcontroller = @@ -39,7 +40,10 @@ class _ControlPanelHeaderState extends State { actions: [ IconButton( onPressed: () { - // Get.to(widget.buildSettings(context)); + showModalBottomSheet( + context: context, + builder: (context) => widget.buildSettings(context), + ); }, icon: const Icon(Icons.settings), ), diff --git a/lib/pages/watch/widgets/reader/novel/controller.dart b/lib/pages/watch/widgets/reader/novel/controller.dart new file mode 100644 index 00000000..ce67a076 --- /dev/null +++ b/lib/pages/watch/widgets/reader/novel/controller.dart @@ -0,0 +1,28 @@ +import 'package:get/get.dart'; +import 'package:miru_app/models/index.dart'; +import 'package:miru_app/pages/watch/reader_controller.dart'; +import 'package:miru_app/utils/miru_storage.dart'; + +class NovelController extends ReaderController { + NovelController({ + required super.title, + required super.playList, + required super.detailUrl, + required super.playIndex, + required super.episodeGroupId, + required super.runtime, + }); + + // 字体大小 + final fontSize = (18.0).obs; + + @override + void onInit() { + super.onInit(); + fontSize.value = MiruStorage.getSetting(SettingKey.novelFontSize); + ever( + fontSize, + (callback) => MiruStorage.setSetting(SettingKey.novelFontSize, callback), + ); + } +} diff --git a/lib/pages/watch/widgets/reader/novel/novel_reader.dart b/lib/pages/watch/widgets/reader/novel/novel_reader.dart index 60dad0c0..0bb3832e 100644 --- a/lib/pages/watch/widgets/reader/novel/novel_reader.dart +++ b/lib/pages/watch/widgets/reader/novel/novel_reader.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:miru_app/models/index.dart'; -import 'package:miru_app/pages/watch/reader_controller.dart'; +import 'package:miru_app/pages/watch/widgets/reader/novel/controller.dart'; import 'package:miru_app/pages/watch/widgets/reader/novel/novel_reader_content.dart'; +import 'package:miru_app/pages/watch/widgets/reader/novel/novel_reader_settings.dart'; import 'package:miru_app/pages/watch/widgets/reader/view.dart'; import 'package:miru_app/utils/extension_runtime.dart'; @@ -30,8 +31,8 @@ class NovelReader extends StatefulWidget { class _NovelReaderState extends State { @override void initState() { - Get.put>( - ReaderController( + Get.put( + NovelController( title: widget.title, playList: widget.playList, detailUrl: widget.detailUrl, @@ -46,62 +47,16 @@ class _NovelReaderState extends State { @override void dispose() { - Get.delete>(tag: widget.title); + Get.delete(tag: widget.title); super.dispose(); } @override Widget build(BuildContext context) { - return ReadView( + return ReadView( widget.title, content: NovelReaderContent(widget.title), - buildSettings: (context) => const Card(), + buildSettings: (context) => NovelReaderSettings(widget.title), ); - // return Obx( - // () => Stack( - // children: [ - // MouseRegion( - // onHover: (event) { - // if (event.position.dy < 60) { - // _c.showControlPanel(); - // } - // }, - // child: NovelReaderContent(widget.title), - // ), - - // // 点击中间显示控制面板 - // Positioned( - // top: 120, - // bottom: 120, - // left: 0, - // right: 0, - // child: GestureDetector( - // onTap: () { - // // 中间点击的话 将不会定时关闭 - // _c.isShowControlPanel.value = !_c.isShowControlPanel.value; - // }, - // ), - // ), - - // if (_c.isShowControlPanel.value) ...[ - // // 顶部控制 - // Positioned( - // child: ControlPanelHeader( - // widget.title, - // buildSettings: (context) { - // return Card(); - // }, - // ), - // ), - // // 底部控制 - // Positioned( - // child: ControlPanelFooter( - // widget.title, - // ), - // ), - // ] - // ], - // ), - // ); } } diff --git a/lib/pages/watch/widgets/reader/novel/novel_reader_content.dart b/lib/pages/watch/widgets/reader/novel/novel_reader_content.dart index 0d765bb8..22f9fd37 100644 --- a/lib/pages/watch/widgets/reader/novel/novel_reader_content.dart +++ b/lib/pages/watch/widgets/reader/novel/novel_reader_content.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:miru_app/models/extension.dart'; -import 'package:miru_app/pages/watch/reader_controller.dart'; +import 'package:miru_app/pages/watch/widgets/reader/novel/controller.dart'; import 'package:miru_app/utils/i18n.dart'; import 'package:miru_app/widgets/button.dart'; import 'package:miru_app/widgets/platform_widget.dart'; @@ -17,8 +16,7 @@ class NovelReaderContent extends StatefulWidget { } class _NovelReaderContentState extends State { - late final _c = - Get.find>(tag: widget.tag); + late final _c = Get.find(tag: widget.tag); _buildContent() { return LayoutBuilder( @@ -51,10 +49,14 @@ class _NovelReaderContentState extends State { final listviewPadding = maxWidth > 800 ? ((maxWidth - 800) / 2) : 16.0; + final fontSize = _c.fontSize.value; + return Center( child: ListView.builder( padding: EdgeInsets.symmetric( - horizontal: listviewPadding, vertical: 16), + horizontal: listviewPadding, + vertical: 16, + ), itemBuilder: (context, index) { if (index == 0) { return Padding( @@ -84,8 +86,8 @@ class _NovelReaderContentState extends State { const WidgetSpan(child: SizedBox(width: 40.0)), TextSpan( text: watchData.content[index - 2], - style: const TextStyle( - fontSize: 18, + style: TextStyle( + fontSize: fontSize, fontWeight: FontWeight.w400, height: 2, textBaseline: TextBaseline.ideographic, diff --git a/lib/pages/watch/widgets/reader/novel/novel_reader_settings.dart b/lib/pages/watch/widgets/reader/novel/novel_reader_settings.dart new file mode 100644 index 00000000..103354bc --- /dev/null +++ b/lib/pages/watch/widgets/reader/novel/novel_reader_settings.dart @@ -0,0 +1,77 @@ +import 'package:fluent_ui/fluent_ui.dart' as fluent; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:miru_app/pages/watch/widgets/reader/novel/controller.dart'; +import 'package:miru_app/utils/i18n.dart'; +import 'package:miru_app/widgets/platform_widget.dart'; + +class NovelReaderSettings extends StatefulWidget { + const NovelReaderSettings(this.tag, {Key? key}) : super(key: key); + final String tag; + + @override + State createState() => _NovelReaderSettingsState(); +} + +class _NovelReaderSettingsState extends State { + late final NovelController _c = Get.find(tag: widget.tag); + + Widget _buildAndroid(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text("novel-settings.font-size".i18n), + const SizedBox(height: 16), + Obx( + () => Slider( + value: _c.fontSize.value, + onChanged: (value) { + _c.fontSize.value = value; + }, + min: 12, + max: 24, + ), + ), + ], + ), + ); + } + + Widget _buildDesktop(BuildContext context) { + return fluent.Card( + backgroundColor: fluent.FluentTheme.of(context).micaBackgroundColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text("novel-settings.font-size".i18n), + const SizedBox(height: 16), + Obx( + () => SizedBox( + width: 200, + child: fluent.Slider( + value: _c.fontSize.value, + onChanged: (value) { + _c.fontSize.value = value; + }, + min: 12, + max: 24, + ), + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return PlatformBuildWidget( + androidBuilder: _buildAndroid, + desktopBuilder: _buildDesktop, + ); + } +} diff --git a/lib/pages/watch/widgets/reader/view.dart b/lib/pages/watch/widgets/reader/view.dart index 9aad9036..ea555732 100644 --- a/lib/pages/watch/widgets/reader/view.dart +++ b/lib/pages/watch/widgets/reader/view.dart @@ -1,10 +1,10 @@ -import 'package:fluent_ui/fluent_ui.dart'; +import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:miru_app/pages/watch/widgets/reader/control_panel_footer.dart'; import 'package:miru_app/pages/watch/widgets/reader/control_panel_header.dart'; import 'package:miru_app/pages/watch/reader_controller.dart'; -class ReadView extends StatelessWidget { +class ReadView extends StatelessWidget { const ReadView( this.tag, { Key? key, @@ -17,7 +17,7 @@ class ReadView extends StatelessWidget { @override Widget build(BuildContext context) { - final c = Get.find>(tag: tag); + final c = Get.find(tag: tag); return Obx( () => Stack( children: [ diff --git a/lib/utils/database.dart b/lib/utils/database.dart index e91fbd16..a73c5b78 100644 --- a/lib/utils/database.dart +++ b/lib/utils/database.dart @@ -1,9 +1,6 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:isar/isar.dart'; -import 'package:miru_app/models/extension.dart'; -import 'package:miru_app/models/extension_setting.dart'; -import 'package:miru_app/models/favorite.dart'; -import 'package:miru_app/models/history.dart'; +import 'package:miru_app/models/index.dart'; import 'package:miru_app/utils/extension.dart'; import 'package:miru_app/utils/miru_storage.dart'; @@ -201,4 +198,25 @@ class DatabaseUtils { return db.writeTxn(() => db.extensionSettings.deleteAll(ids)); } + + // 获取漫画阅读模式 + static Future getMnagaReaderType(String url) { + return db.mangaSettings.filter().urlEqualTo(url).findFirst().then( + (value) => value?.readMode ?? MangaReadMode.standard, + ); + } + + // 设置漫画阅读模式 + static Future setMangaReaderType( + String url, + MangaReadMode readMode, + ) { + return db.writeTxn( + () => db.mangaSettings.putByUrl( + MangaSetting() + ..url = url + ..readMode = readMode, + ), + ); + } } diff --git a/lib/utils/miru_storage.dart b/lib/utils/miru_storage.dart index 1817e809..67c37746 100644 --- a/lib/utils/miru_storage.dart +++ b/lib/utils/miru_storage.dart @@ -1,8 +1,6 @@ import 'package:hive_flutter/adapters.dart'; import 'package:isar/isar.dart'; -import 'package:miru_app/models/extension_setting.dart'; -import 'package:miru_app/models/favorite.dart'; -import 'package:miru_app/models/history.dart'; +import 'package:miru_app/models/index.dart'; import 'package:miru_app/utils/miru_directory.dart'; class MiruStorage { @@ -13,7 +11,12 @@ class MiruStorage { final path = await MiruDirectory.getDirectory; // 初始化数据库 database = await Isar.open( - [FavoriteSchema, HistorySchema, ExtensionSettingSchema], + [ + FavoriteSchema, + HistorySchema, + ExtensionSettingSchema, + MangaSettingSchema, + ], directory: path, ); // 初始化设置 @@ -27,6 +30,7 @@ class MiruStorage { await _initSetting(SettingKey.tmdbKay, ""); await _initSetting(SettingKey.autoCheckUpdate, true); await _initSetting(SettingKey.language, 'en'); + await _initSetting(SettingKey.novelFontSize, 18.0); } static _initSetting(String key, dynamic value) async { @@ -49,4 +53,5 @@ class SettingKey { static String tmdbKay = 'TMDBKey'; static String autoCheckUpdate = 'AutoCheckUpdate'; static String language = 'Language'; + static String novelFontSize = 'NovelFontSize'; } diff --git a/lib/widgets/horizontal_list.dart b/lib/widgets/horizontal_list.dart index b6397239..520a4d25 100644 --- a/lib/widgets/horizontal_list.dart +++ b/lib/widgets/horizontal_list.dart @@ -55,14 +55,14 @@ class _HorizontalListState extends State { widget.contentBuilder!(_controller) else SizedBox( - height: 186, + height: 170, child: ListView.builder( scrollDirection: Axis.horizontal, controller: _controller, itemCount: widget.itemCount, itemBuilder: ((context, index) { return Container( - width: 128, + width: 110, margin: const EdgeInsets.only(right: 16), child: widget.itemBuilder!(context, index), ); diff --git a/pubspec.lock b/pubspec.lock index e0925cf6..eea7e1c0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -958,7 +958,7 @@ packages: source: hosted version: "0.4.0" scrollable_positioned_list: - dependency: transitive + dependency: "direct main" description: name: scrollable_positioned_list sha256: "1b54d5f1329a1e263269abc9e2543d90806131aa14fe7c6062a8054d57249287" diff --git a/pubspec.yaml b/pubspec.yaml index 9d904ff5..7f764270 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: miru_app description: A new Flutter project. publish_to: "none" -version: 1.4.2+14 +version: 1.5.0+15 environment: sdk: ">=3.0.3 <4.0.0" @@ -40,6 +40,7 @@ dependencies: path: ^1.8.3 path_provider: ^2.0.15 screenshot: ^2.1.0 + scrollable_positioned_list: ^0.3.8 system_theme: ^2.2.0 tmdb_api: ^2.1.5 url_launcher: ^6.1.11