Merge pull request #22 from venera-app/dev

v 1.0.3
This commit is contained in:
nyne
2024-11-07 10:26:40 +08:00
committed by GitHub
18 changed files with 150 additions and 54 deletions

View File

@@ -4,7 +4,7 @@ on:
workflow_dispatch: {} workflow_dispatch: {}
jobs: jobs:
Build_MacOS: Build_MacOS:
runs-on: macos-13 runs-on: macos-15
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: subosito/flutter-action@v2 - uses: subosito/flutter-action@v2
@@ -12,7 +12,7 @@ jobs:
channel: "stable" channel: "stable"
flutter-version-file: pubspec.yaml flutter-version-file: pubspec.yaml
architecture: x64 architecture: x64
- run: sudo xcode-select --switch /Applications/Xcode_14.3.1.app - run: sudo xcode-select --switch /Applications/Xcode_16.0.app
- run: flutter pub get - run: flutter pub get
# Step 1: Decode and install the certificate # Step 1: Decode and install the certificate
- name: Decode and install certificate - name: Decode and install certificate
@@ -38,12 +38,12 @@ jobs:
# Step 4: Attach and upload artifacts (optional) # Step 4: Attach and upload artifacts (optional)
- name: Upload DMG - name: Upload DMG
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: venera.dmg name: venera.dmg
path: dist/venera.dmg path: dist/venera.dmg
Build_IOS: Build_IOS:
runs-on: macos-13 runs-on: macos-15
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: subosito/flutter-action@v2 - uses: subosito/flutter-action@v2
@@ -51,7 +51,7 @@ jobs:
channel: "stable" channel: "stable"
flutter-version-file: pubspec.yaml flutter-version-file: pubspec.yaml
architecture: x64 architecture: x64
- run: sudo xcode-select --switch /Applications/Xcode_14.3.1.app - run: sudo xcode-select --switch /Applications/Xcode_16.0.app
- run: flutter pub get - run: flutter pub get
- run: flutter build ios --release --no-codesign - run: flutter build ios --release --no-codesign
- run: | - run: |

View File

@@ -4,6 +4,7 @@
[![License](https://img.shields.io/github/license/venera-app/venera)](https://github.com/venera-app/venera/blob/master/LICENSE) [![License](https://img.shields.io/github/license/venera-app/venera)](https://github.com/venera-app/venera/blob/master/LICENSE)
[![Download](https://img.shields.io/github/v/release/venera-app/venera)](https://github.com/venera-app/venera/releases) [![Download](https://img.shields.io/github/v/release/venera-app/venera)](https://github.com/venera-app/venera/releases)
[![stars](https://img.shields.io/github/stars/venera-app/venera)](https://github.com/venera-app/venera/stargazers) [![stars](https://img.shields.io/github/stars/venera-app/venera)](https://github.com/venera-app/venera/stargazers)
[![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=flat&logo=telegram&logoColor=white)](https://t.me/+Ws-IpmUutzkxMjhl)
A comic reader that support reading local and network comics. A comic reader that support reading local and network comics.

View File

@@ -169,7 +169,17 @@
"minAppVersion @version is required": "需要最低App版本 @version", "minAppVersion @version is required": "需要最低App版本 @version",
"Remove": "移除", "Remove": "移除",
"Long press to zoom": "长按缩放", "Long press to zoom": "长按缩放",
"Updates Available": "更新可用" "Updates Available": "更新可用",
"Unselected": "未选择",
"Long press and drag to reorder.": "长按并拖动以重新排序。",
"Limit image width": "限制图片宽度",
"When using Continuous(Top to Bottom) mode": "当使用连续(从上到下)模式",
"Open link": "打开链接",
"Open comic": "打开漫画",
"Move To First": "移动到最前",
"Cancel": "取消",
"Paused": "已暂停",
"Pause": "暂停"
}, },
"zh_TW": { "zh_TW": {
"Home": "首頁", "Home": "首頁",
@@ -341,6 +351,16 @@
"minAppVersion @version is required": "需要最低App版本 @version", "minAppVersion @version is required": "需要最低App版本 @version",
"Remove": "移除", "Remove": "移除",
"Long press to zoom": "長按縮放", "Long press to zoom": "長按縮放",
"Updates Available": "更新可用" "Updates Available": "更新可用",
"Unselected": "未選擇",
"Long press and drag to reorder.": "長按並拖動以重新排序。",
"Limit image width": "限制圖片寬度",
"When using Continuous(Top to Bottom) mode": "當使用連續(從上到下)模式",
"Open link": "打開鏈接",
"Open comic": "打開漫畫",
"Move To First": "移動到最前",
"Cancel": "取消",
"Paused": "已暫停",
"Pause": "暫停"
} }
} }

View File

@@ -10,7 +10,7 @@ export "widget_utils.dart";
export "context.dart"; export "context.dart";
class _App { class _App {
final version = "1.0.2"; final version = "1.0.3";
bool get isAndroid => Platform.isAndroid; bool get isAndroid => Platform.isAndroid;

View File

@@ -113,6 +113,7 @@ class _Settings with ChangeNotifier {
'downloadThreads': 5, 'downloadThreads': 5,
'enableLongPressToZoom': true, 'enableLongPressToZoom': true,
'checkUpdateOnStart': true, 'checkUpdateOnStart': true,
'limitImageWidth': true,
}; };
operator [](String key) { operator [](String key) {

View File

@@ -196,12 +196,6 @@ class AppDio with DioMixin {
: rhttp.ProxySettings.proxy(proxy!), : rhttp.ProxySettings.proxy(proxy!),
)); ));
} }
Log.info(
"Network",
"${options?.method ?? 'GET'} $path\n"
"Headers: ${options?.headers}\n"
"Data: $data\n",
);
return super.request( return super.request(
path, path,
data: data, data: data,
@@ -218,14 +212,14 @@ class RHttpAdapter implements HttpClientAdapter {
rhttp.ClientSettings settings; rhttp.ClientSettings settings;
RHttpAdapter(this.settings) { RHttpAdapter(this.settings) {
settings.copyWith( settings = settings.copyWith(
redirectSettings: const rhttp.RedirectSettings.limited(5), redirectSettings: const rhttp.RedirectSettings.limited(5),
timeoutSettings: const rhttp.TimeoutSettings( timeoutSettings: const rhttp.TimeoutSettings(
connectTimeout: Duration(seconds: 15), connectTimeout: Duration(seconds: 15),
keepAliveTimeout: Duration(seconds: 60), keepAliveTimeout: Duration(seconds: 60),
keepAlivePing: Duration(seconds: 30), keepAlivePing: Duration(seconds: 30),
), ),
httpVersionPref: rhttp.HttpVersionPref.http1_1, throwOnStatusCode: false,
); );
} }
@@ -238,6 +232,12 @@ class RHttpAdapter implements HttpClientAdapter {
Stream<Uint8List>? requestStream, Stream<Uint8List>? requestStream,
Future<void>? cancelFuture, Future<void>? cancelFuture,
) async { ) async {
Log.info(
"Network",
"${options.method} ${options.uri}\n"
"Headers: ${options.headers}\n"
"Data: ${options.data}\n",
);
var res = await rhttp.Rhttp.request( var res = await rhttp.Rhttp.request(
method: switch (options.method) { method: switch (options.method) {
'GET' => rhttp.HttpMethod.get, 'GET' => rhttp.HttpMethod.get,
@@ -275,12 +275,7 @@ class RHttpAdapter implements HttpClientAdapter {
var data = res.body; var data = res.body;
if(headers['content-encoding']?.contains('gzip') ?? false) { if(headers['content-encoding']?.contains('gzip') ?? false) {
// rhttp does not support gzip decoding // rhttp does not support gzip decoding
var buffer = <int>[]; data = gzip.decoder.bind(data).map((data) => Uint8List.fromList(data));
await for (var chunk in data) {
buffer.addAll(chunk);
}
data = Stream.value(Uint8List.fromList(gzip.decode(buffer)));
buffer.clear();
} }
return ResponseBody( return ResponseBody(
data, data,

View File

@@ -90,7 +90,7 @@ class ImagesDownloadTask extends DownloadTask with _TransferSpeedMixin {
var local = LocalManager().find(id, comicType); var local = LocalManager().find(id, comicType);
if (path != null) { if (path != null) {
if (local == null) { if (local == null) {
Directory(path!).deleteIgnoreError(); Directory(path!).deleteIgnoreError(recursive: true);
} else if (chapters != null) { } else if (chapters != null) {
for (var c in chapters!) { for (var c in chapters!) {
var dir = Directory(FilePath.join(path!, c)); var dir = Directory(FilePath.join(path!, c));

View File

@@ -6,7 +6,6 @@ Future<void> newFolder() async {
context: App.rootContext, context: App.rootContext,
builder: (context) { builder: (context) {
var controller = TextEditingController(); var controller = TextEditingController();
var folders = LocalFavoritesManager().folderNames;
String? error; String? error;
return StatefulBuilder(builder: (context, setState) { return StatefulBuilder(builder: (context, setState) {

View File

@@ -152,7 +152,8 @@ class _FavoritesPageState extends State<FavoritesPage> {
} else { } else {
var favoriteData = getFavoriteDataOrNull(folder!); var favoriteData = getFavoriteDataOrNull(folder!);
if (favoriteData == null) { if (favoriteData == null) {
return const Center(child: Text("Unknown source")); folder = null;
return buildBody();
} else { } else {
return NetworkFavoritePage(favoriteData, key: Key(folder!)); return NetworkFavoritePage(favoriteData, key: Key(folder!));
} }

View File

@@ -15,10 +15,8 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
late List<FavoriteItem> comics; late List<FavoriteItem> comics;
void updateComics() { void updateComics() {
print(comics.length);
setState(() { setState(() {
comics = LocalFavoritesManager().getAllComics(widget.folder); comics = LocalFavoritesManager().getAllComics(widget.folder);
print(comics.length);
}); });
} }
@@ -107,7 +105,9 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
}, },
).then( ).then(
(value) { (value) {
if(mounted) {
setState(() {}); setState(() {});
}
}, },
); );
}), }),
@@ -199,6 +199,7 @@ class _ReorderComicsPageState extends State<_ReorderComicsPage> {
var comicSource = e.type.comicSource; var comicSource = e.type.comicSource;
return ComicTile( return ComicTile(
key: Key(e.hashCode.toString()), key: Key(e.hashCode.toString()),
enableLongPressed: false,
comic: Comic( comic: Comic(
e.name, e.name,
e.coverPath, e.coverPath,

View File

@@ -22,6 +22,8 @@ class _ReaderGestureDetectorState extends State<_ReaderGestureDetector> {
_DragListener? dragListener; _DragListener? dragListener;
int fingers = 0;
@override @override
void initState() { void initState() {
_tapGestureRecognizer = TapGestureRecognizer() _tapGestureRecognizer = TapGestureRecognizer()
@@ -38,6 +40,7 @@ class _ReaderGestureDetectorState extends State<_ReaderGestureDetector> {
return Listener( return Listener(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
onPointerDown: (event) { onPointerDown: (event) {
fingers++;
_lastTapPointer = event.pointer; _lastTapPointer = event.pointer;
_lastTapMoveDistance = Offset.zero; _lastTapMoveDistance = Offset.zero;
_tapGestureRecognizer.addPointer(event); _tapGestureRecognizer.addPointer(event);
@@ -46,7 +49,7 @@ class _ReaderGestureDetectorState extends State<_ReaderGestureDetector> {
_dragInProgress = false; _dragInProgress = false;
} }
Future.delayed(_kLongPressMinTime, () { Future.delayed(_kLongPressMinTime, () {
if (_lastTapPointer == event.pointer) { if (_lastTapPointer == event.pointer && fingers == 1) {
if(_lastTapMoveDistance!.distanceSquared < 20.0 * 20.0) { if(_lastTapMoveDistance!.distanceSquared < 20.0 * 20.0) {
onLongPressedDown(event.position); onLongPressedDown(event.position);
_longPressInProgress = true; _longPressInProgress = true;
@@ -67,6 +70,19 @@ class _ReaderGestureDetectorState extends State<_ReaderGestureDetector> {
} }
}, },
onPointerUp: (event) { onPointerUp: (event) {
fingers--;
if (_longPressInProgress) {
onLongPressedUp(event.position);
}
if(_dragInProgress) {
dragListener?.onEnd?.call();
_dragInProgress = false;
}
_lastTapPointer = null;
_lastTapMoveDistance = null;
},
onPointerCancel: (event) {
fingers--;
if (_longPressInProgress) { if (_longPressInProgress) {
onLongPressedUp(event.position); onLongPressedUp(event.position);
} }

View File

@@ -471,18 +471,24 @@ class _ContinuousModeState extends State<_ContinuousMode>
}, },
child: widget, child: widget,
); );
var width = MediaQuery.of(context).size.width;
var height = MediaQuery.of(context).size.height;
if(appdata.settings['limitImageWidth'] && width / height > 0.7) {
width = height * 0.7;
}
return PhotoView.customChild( return PhotoView.customChild(
backgroundDecoration: BoxDecoration( backgroundDecoration: BoxDecoration(
color: context.colorScheme.surface, color: context.colorScheme.surface,
), ),
childSize: Size(width, height),
minScale: 1.0, minScale: 1.0,
maxScale: 2.5, maxScale: 2.5,
strictScale: true, strictScale: true,
controller: photoViewController, controller: photoViewController,
child: SizedBox( child: SizedBox(
width: MediaQuery.of(context).size.width, width: width,
height: MediaQuery.of(context).size.height, height: height,
child: widget, child: widget,
), ),
); );

View File

@@ -369,6 +369,9 @@ class _SearchPageState extends State<SearchPage> {
), ),
trailing: const Icon(Icons.arrow_right), trailing: const Icon(Icons.arrow_right),
onTap: () { onTap: () {
setState(() {
suggestions.clear();
});
handleAppLink(Uri.parse(controller.text)); handleAppLink(Uri.parse(controller.text));
}, },
); );

View File

@@ -135,14 +135,18 @@ class _SearchResultPageState extends State<SearchResultPage> {
onChanged: onChanged, onChanged: onChanged,
action: buildAction(), action: buildAction(),
), ),
loadPage: source!.searchPageData!.loadPage == null ? null : (i) { loadPage: source!.searchPageData!.loadPage == null
? null
: (i) {
return source.searchPageData!.loadPage!( return source.searchPageData!.loadPage!(
text, text,
i, i,
options, options,
); );
}, },
loadNext: source.searchPageData!.loadNext == null ? null : (i) { loadNext: source.searchPageData!.loadNext == null
? null
: (i) {
return source.searchPageData!.loadNext!( return source.searchPageData!.loadNext!(
text, text,
i, i,
@@ -424,6 +428,11 @@ class _SearchSettingsDialogState extends State<_SearchSettingsDialog> {
setState(() { setState(() {
searchTarget = e.key; searchTarget = e.key;
options.clear(); options.clear();
final searchOptions = ComicSource.find(searchTarget)!
.searchPageData!
.searchOptions ??
<SearchOptions>[];
options = searchOptions.map((e) => e.defaultValue).toList();
onChanged(); onChanged();
}); });
}, },

View File

@@ -61,6 +61,14 @@ class _ReaderSettingsState extends State<ReaderSettings> {
widget.onChanged?.call('enableLongPressToZoom'); widget.onChanged?.call('enableLongPressToZoom');
}, },
).toSliver(), ).toSliver(),
_SwitchSetting(
title: 'Limit image width'.tl,
subtitle: 'When using Continuous(Top to Bottom) mode'.tl,
settingKey: 'limitImageWidth',
onChanged: () {
widget.onChanged?.call('limitImageWidth');
},
).toSliver(),
], ],
); );
} }

View File

@@ -5,6 +5,7 @@ class _SwitchSetting extends StatefulWidget {
required this.title, required this.title,
required this.settingKey, required this.settingKey,
this.onChanged, this.onChanged,
this.subtitle,
}); });
final String title; final String title;
@@ -13,6 +14,8 @@ class _SwitchSetting extends StatefulWidget {
final VoidCallback? onChanged; final VoidCallback? onChanged;
final String? subtitle;
@override @override
State<_SwitchSetting> createState() => _SwitchSettingState(); State<_SwitchSetting> createState() => _SwitchSettingState();
} }
@@ -24,6 +27,7 @@ class _SwitchSettingState extends State<_SwitchSetting> {
return ListTile( return ListTile(
title: Text(widget.title), title: Text(widget.title),
subtitle: widget.subtitle == null ? null : Text(widget.subtitle!),
trailing: Switch( trailing: Switch(
value: appdata.settings[widget.settingKey], value: appdata.settings[widget.settingKey],
onChanged: (value) { onChanged: (value) {

View File

@@ -345,10 +345,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_reorderable_grid_view name: flutter_reorderable_grid_view
sha256: "40abcc5bff228ebff119326502e7357ee6399956b60b80b17385e9770b7458c0" sha256: "93a2b9e279bf40b9333428a67e70e520ca1528554984eb6f6304538400897e64"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.1" version: "5.3.2"
flutter_rust_bridge: flutter_rust_bridge:
dependency: transitive dependency: transitive
description: description:
@@ -638,10 +638,42 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: screen_retriever name: screen_retriever
sha256: "6ee02c8a1158e6dae7ca430da79436e3b1c9563c8cf02f524af997c201ac2b90" sha256: "570dbc8e4f70bac451e0efc9c9bb19fa2d6799a11e6ef04f946d7886d2e23d0c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.1.9" version: "0.2.0"
screen_retriever_linux:
dependency: transitive
description:
name: screen_retriever_linux
sha256: f7f8120c92ef0784e58491ab664d01efda79a922b025ff286e29aa123ea3dd18
url: "https://pub.dev"
source: hosted
version: "0.2.0"
screen_retriever_macos:
dependency: transitive
description:
name: screen_retriever_macos
sha256: "71f956e65c97315dd661d71f828708bd97b6d358e776f1a30d5aa7d22d78a149"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
screen_retriever_platform_interface:
dependency: transitive
description:
name: screen_retriever_platform_interface
sha256: ee197f4581ff0d5608587819af40490748e1e39e648d7680ecf95c05197240c0
url: "https://pub.dev"
source: hosted
version: "0.2.0"
screen_retriever_windows:
dependency: transitive
description:
name: screen_retriever_windows
sha256: "449ee257f03ca98a57288ee526a301a430a344a161f9202b4fcc38576716fe13"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
scrollable_positioned_list: scrollable_positioned_list:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -868,10 +900,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: window_manager name: window_manager
sha256: ab8b2a7f97543d3db2b506c9d875e637149d48ee0c6a5cb5f5fd6e0dac463792 sha256: "732896e1416297c63c9e3fb95aea72d0355f61390263982a47fd519169dc5059"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.4.2" version: "0.4.3"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:

View File

@@ -2,7 +2,7 @@ name: venera
description: "A comic app." description: "A comic app."
publish_to: 'none' publish_to: 'none'
version: 1.0.2+102 version: 1.0.3+103
environment: environment:
sdk: '>=3.5.0 <4.0.0' sdk: '>=3.5.0 <4.0.0'
@@ -39,7 +39,7 @@ dependencies:
url: https://github.com/venera-app/flutter.widgets url: https://github.com/venera-app/flutter.widgets
ref: 09e756b1f1b04e6298318d99ec20a787fb360f59 ref: 09e756b1f1b04e6298318d99ec20a787fb360f59
path: packages/scrollable_positioned_list path: packages/scrollable_positioned_list
flutter_reorderable_grid_view: 5.0.1 flutter_reorderable_grid_view: 5.3.2
yaml: any yaml: any
uuid: ^4.5.1 uuid: ^4.5.1
desktop_webview_window: desktop_webview_window: