32 Commits

Author SHA1 Message Date
nyne
bf634f8654 Merge pull request #104 from venera-app/dev
v1.1.2
2024-12-18 20:11:11 +08:00
nyne
bda215ebb7 Merge branch 'master' into dev 2024-12-18 20:10:41 +08:00
a70b690d3c Run dart fix 2024-12-18 20:07:35 +08:00
0b8ae2d377 Update version code 2024-12-18 20:05:59 +08:00
24c5a1bb01 Improve local comics page 2024-12-18 20:04:45 +08:00
ea973a2787 fix #92 2024-12-18 19:36:54 +08:00
nyne
17bce96143 Merge pull request #103 from UjuiUjuMandan/abivercode
Add abiVersionCode & Remove x86
2024-12-18 19:17:58 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
909c0014ac * 10 for universal 2024-12-18 19:15:45 +08:00
eb1abfc02a Fixed the issue where the images of multi-chapter comic are downloaded to invalid folder. 2024-12-18 19:13:35 +08:00
UjuiUjuMandan
788e41f584 Add abiVersionCode & Remove x86 2024-12-18 10:50:19 +00:00
929ec88e84 Fixed issue where deleting a download caused favourites to be deleted. 2024-12-18 17:58:18 +08:00
abaeaf4f77 improve mouse hover effects on click areas 2024-12-18 17:37:03 +08:00
nyne
a614e83470 Merge pull request #102 from UjuiUjuMandan/rb
update dependencies again
2024-12-18 17:22:30 +08:00
8b9fd0d03d improve pop_up_widget and side_bar in dark mode 2024-12-18 17:19:34 +08:00
UjuiUjuMandan
1964c4c0d5 update dependencies again 2024-12-18 09:16:28 +00:00
43d724dd27 fix #97 2024-12-18 17:08:03 +08:00
f9c42aef4b fix #98 2024-12-18 16:51:57 +08:00
06a6e5156a Fix minimum support platform version 2024-12-18 15:48:35 +08:00
deltamaya
be45a06981 update minimum support platform version 2024-12-18 15:25:32 +08:00
4763b9c7b4 test zip_flutter 2024-12-18 15:14:27 +08:00
7e608be70f test zip_flutter 2024-12-18 14:15:08 +08:00
211e6ab8c8 update dependencies 2024-12-18 13:29:43 +08:00
nyne
100dc6458b Merge pull request #100 from UjuiUjuMandan/master
F-Droid
2024-12-17 22:56:39 +08:00
UjuiUjuMandan
8dab5f9e88 test fastlane
add icon.png

add icon.png

scale to 512x512

metadata for zh-CN

Revert "metadata for zh-CN"

This reverts commit 77b30b9209dd1b082f050c55fa175fa96afbfcf6.
2024-12-17 14:18:41 +00:00
d08383e14b disable Impeller 2024-12-17 20:11:18 +08:00
a55e4eff67 Update to flutter 3.27.1 & Fix android build 2024-12-17 17:21:10 +08:00
ab3953292b fix https://github.com/venera-app/venera-configs/issues/28 2024-12-17 13:01:44 +08:00
b49e0974ab improve zip 2024-12-17 12:10:57 +08:00
nyne
b6cccb7749 update version code 2024-12-13 09:34:37 +08:00
nyne
dac07cfac4 Fix windows build script 2024-12-13 09:30:28 +08:00
nyne
da12b3bcca Fix favorites_page 2024-12-13 09:27:53 +08:00
nyne
017f964705 [Android] Disable Impeller 2024-12-13 09:25:09 +08:00
39 changed files with 569 additions and 252 deletions

16
.github/workflows/fastlane.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: Validate Fastlane metadata
on:
workflow_dispatch:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
go:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate Fastlane Supply Metadata
uses: ashutoshgngwr/validate-fastlane-supply-metadata@v2.0.0

View File

@@ -35,7 +35,7 @@ android {
splits{ splits{
abi { abi {
reset() reset()
include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' include 'armeabi-v7a', 'arm64-v8a', 'x86_64'
enable true enable true
universalApk true universalApk true
} }
@@ -78,16 +78,22 @@ android {
buildTypes { buildTypes {
release { release {
ndk { ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" abiFilters "armeabi-v7a", "arm64-v8a", "x86_64"
} }
signingConfig signingConfigs.release signingConfig signingConfigs.release
ext.abiCodes = ["armeabi-v7a": 1, "arm64-v8a": 2, "x86_64": 3]
applicationVariants.all { variant -> applicationVariants.all { variant ->
variant.outputs.all { output -> variant.outputs.all { output ->
def abi = output.getFilter(com.android.build.OutputFile.ABI) def abi = output.getFilter(com.android.build.OutputFile.ABI)
if (abi != null) { if (abi != null) {
outputFileName = "venera-${variant.versionName}-${abi}.apk" outputFileName = "venera-${variant.versionName}-${abi}.apk"
def abiVersionCode = project.ext.abiCodes.get(abi)
if (abiVersionCode != null) {
versionCodeOverride = variant.versionCode * 10 + abiVersionCode
}
} else { } else {
outputFileName = "venera-${variant.versionName}.apk" outputFileName = "venera-${variant.versionName}.apk"
versionCodeOverride = variant.versionCode * 10
} }
} }
} }

View File

@@ -53,6 +53,8 @@
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<!-- [flutter 3.27.1] Impeller is still worse than skia, disable it -->
<meta-data android:name="io.flutter.embedding.android.EnableImpeller" android:value="false"/>
</application> </application>
<!-- Required to query activities that can process text, see: <!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and https://developer.android.com/training/package-visibility and

View File

@@ -251,7 +251,14 @@
"Aggregated Search": "聚合搜索", "Aggregated Search": "聚合搜索",
"No search results found": "未找到搜索结果", "No search results found": "未找到搜索结果",
"Added @c comics to download queue." : "已添加 @c 本漫画到下载队列", "Added @c comics to download queue." : "已添加 @c 本漫画到下载队列",
"Download started": "下载已开始" "Download started": "下载已开始",
"Click favorite": "点击收藏",
"End": "末尾",
"None": "无",
"View Detail": "查看详情",
"Select a directory which contains multiple cbz/zip files." : "选择一个包含多个cbz/zip文件的目录",
"Multiple cbz files" : "多个cbz文件",
"No valid comics found" : "未找到有效的漫画"
}, },
"zh_TW": { "zh_TW": {
"Home": "首頁", "Home": "首頁",
@@ -505,6 +512,13 @@
"Aggregated Search": "聚合搜索", "Aggregated Search": "聚合搜索",
"No search results found": "未找到搜索結果", "No search results found": "未找到搜索結果",
"Added @c comics to download queue." : "已添加 @c 本漫畫到下載隊列", "Added @c comics to download queue." : "已添加 @c 本漫畫到下載隊列",
"Download started": "下載已開始" "Download started": "下載已開始",
"Click favorite": "點擊收藏",
"End": "末尾",
"None": "無",
"View Detail": "查看詳情",
"Select a directory which contains multiple cbz/zip files." : "選擇一個包含多個cbz/zip文件的目錄",
"Multiple cbz files" : "多個cbz文件",
"No valid comics found" : "未找到有效的漫畫"
} }
} }

View File

@@ -0,0 +1,40 @@
<p><a href="https://flutter.dev/"><img src="https://img.shields.io/badge/flutter-3.24.4-blue" alt="flutter"></a>
<a href="https://github.com/venera-app/venera/blob/master/LICENSE"><img src="https://img.shields.io/github/license/venera-app/venera" alt="License"></a>
<a href="https://github.com/venera-app/venera/releases"><img src="https://img.shields.io/github/v/release/venera-app/venera" alt="Download"></a>
<a href="https://github.com/venera-app/venera/stargazers"><img src="https://img.shields.io/github/stars/venera-app/venera" alt="stars"></a>
<a href="https://t.me/+Ws-IpmUutzkxMjhl"><img src="https://img.shields.io/badge/Telegram-2CA5E0?style=flat&amp;logo=telegram&amp;logoColor=white" alt="Telegram"></a></p>
<p>A comic reader that support reading local and network comics.</p>
<h2>Features</h2>
<ul>
<li>Read local comics</li>
<li>Use javascript to create comic sources</li>
<li>Read comics from network sources</li>
<li>Manage favorite comics</li>
<li>Download comics</li>
<li>View comments, tags, and other information of comics if the source supports</li>
<li>Login to comment, rate, and other operations if the source supports</li>
</ul>
<h2>Build from source</h2>
<ol>
<li>Clone the repository</li>
<li>Install flutter, see <a href="https://flutter.dev/docs/get-started/install">flutter.dev</a></li>
<li>Install rust, see <a href="https://rustup.rs/">rustup.rs</a></li>
<li>Build for your platform: e.g. <code>flutter build apk</code></li>
</ol>
<h2>Create a new comic source</h2>
<p>See <a href="https://github.com/venera-app/venera-configs">venera-configs</a></p>
<h2>Thanks</h2>
<h3>Tags Translation</h3>
<p><a href="https://github.com/EhTagTranslation/Database"><img src="https://github-readme-stats.vercel.app/api/pin/?username=EhTagTranslation&amp;repo=Database" alt="Readme Card"></a></p>
<p>The Chinese translation of the manga tags is from this project.</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1 @@
A comic reader that support reading local and network comics.

View File

@@ -0,0 +1 @@
venera

View File

@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
platform :ios, '14.0' platform :ios, '15.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'

View File

@@ -77,7 +77,7 @@ class ComicTile extends StatelessWidget {
icon: Icons.stars_outlined, icon: Icons.stars_outlined,
text: 'Add to favorites'.tl, text: 'Add to favorites'.tl,
onClick: () { onClick: () {
addFavorite(comic); addFavorite([comic]);
}, },
), ),
MenuEntry( MenuEntry(

View File

@@ -41,13 +41,29 @@ class AnimatedTapRegion extends StatefulWidget {
} }
class _AnimatedTapRegionState extends State<AnimatedTapRegion> { class _AnimatedTapRegionState extends State<AnimatedTapRegion> {
bool isScaled = false;
bool isHovered = false; bool isHovered = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MouseRegion( return MouseRegion(
onEnter: (_) => setState(() => isHovered = true), onEnter: (_) {
onExit: (_) => setState(() => isHovered = false), isHovered = true;
if (!isScaled) {
Future.delayed(const Duration(milliseconds: 100), () {
if (isHovered) {
setState(() => isScaled = true);
}
});
}
},
onExit: (_) {
isHovered = false;
if(isScaled) {
setState(() => isScaled = false);
}
},
child: GestureDetector( child: GestureDetector(
onTap: widget.onTap, onTap: widget.onTap,
child: ClipRRect( child: ClipRRect(
@@ -55,7 +71,7 @@ class _AnimatedTapRegionState extends State<AnimatedTapRegion> {
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: AnimatedScale( child: AnimatedScale(
duration: _fastAnimationDuration, duration: _fastAnimationDuration,
scale: isHovered ? 1.1 : 1, scale: isScaled ? 1.1 : 1,
child: widget.child, child: widget.child,
), ),
), ),

View File

@@ -22,8 +22,15 @@ class PopUpWidget<T> extends PopupRoute<T> {
Widget body = PopupIndicatorWidget( Widget body = PopupIndicatorWidget(
child: Container( child: Container(
decoration: showPopUp decoration: showPopUp
? const BoxDecoration( ? BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(12)), borderRadius: BorderRadius.all(Radius.circular(12)),
boxShadow: context.brightness == ui.Brightness.dark ? [
BoxShadow(
color: Colors.white.withAlpha(50),
blurRadius: 10,
offset: Offset(0, 2),
),
] : null,
) )
: null, : null,
clipBehavior: showPopUp ? Clip.antiAlias : Clip.none, clipBehavior: showPopUp ? Clip.antiAlias : Clip.none,
@@ -86,7 +93,8 @@ class PopupIndicatorWidget extends InheritedWidget {
} }
Future<T> showPopUpWidget<T>(BuildContext context, Widget widget) async { Future<T> showPopUpWidget<T>(BuildContext context, Widget widget) async {
return await Navigator.of(context, rootNavigator: true).push(PopUpWidget(widget)); return await Navigator.of(context, rootNavigator: true)
.push(PopUpWidget(widget));
} }
class PopUpWidgetScaffold extends StatefulWidget { class PopUpWidgetScaffold extends StatefulWidget {
@@ -127,9 +135,8 @@ class _PopUpWidgetScaffoldState extends State<PopUpWidgetScaffold> {
message: "Back".tl, message: "Back".tl,
child: IconButton( child: IconButton(
icon: const Icon(Icons.arrow_back_sharp), icon: const Icon(Icons.arrow_back_sharp),
onPressed: () => context.canPop() onPressed: () =>
? context.pop() context.canPop() ? context.pop() : App.pop(),
: App.pop(),
), ),
), ),
const SizedBox( const SizedBox(

View File

@@ -57,10 +57,18 @@ class SideBarRoute<T> extends PopupRoute<T> {
body = Container( body = Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: showSideBar borderRadius: showSideBar
? const BorderRadius.horizontal(left: Radius.circular(16)) ? const BorderRadius.horizontal(left: Radius.circular(16))
: null, : null,
color: Theme.of(context).colorScheme.surfaceTint), color: Theme.of(context).colorScheme.surfaceTint,
boxShadow: context.brightness == ui.Brightness.dark ? [
BoxShadow(
color: Colors.white.withAlpha(50),
blurRadius: 10,
offset: Offset(0, 2),
),
] : null,
),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
constraints: BoxConstraints(maxWidth: sideBarWidth), constraints: BoxConstraints(maxWidth: sideBarWidth),
height: MediaQuery.of(context).size.height, height: MediaQuery.of(context).size.height,

View File

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

View File

@@ -122,6 +122,7 @@ class _Settings with ChangeNotifier {
'enableClockAndBatteryInfoInReader': true, 'enableClockAndBatteryInfoInReader': true,
'ignoreCertificateErrors': false, 'ignoreCertificateErrors': false,
'authorizationRequired': false, 'authorizationRequired': false,
'onClickFavorite': 'viewDetail', // viewDetail, read
}; };
operator [](String key) { operator [](String key) {

View File

@@ -145,7 +145,7 @@ class ComicDetails with HistoryMixin {
final int? likesCount; final int? likesCount;
final int? commentsCount; final int? commentCount;
final String? uploader; final String? uploader;
@@ -189,7 +189,7 @@ class ComicDetails with HistoryMixin {
subId = json["subId"], subId = json["subId"],
likesCount = json["likesCount"], likesCount = json["likesCount"],
isLiked = json["isLiked"], isLiked = json["isLiked"],
commentsCount = json["commentsCount"], commentCount = json["commentCount"],
uploader = json["uploader"], uploader = json["uploader"],
uploadTime = json["uploadTime"], uploadTime = json["uploadTime"],
updateTime = json["updateTime"], updateTime = json["updateTime"],
@@ -216,7 +216,7 @@ class ComicDetails with HistoryMixin {
"subId": subId, "subId": subId,
"isLiked": isLiked, "isLiked": isLiked,
"likesCount": likesCount, "likesCount": likesCount,
"commentsCount": commentsCount, "commentsCount": commentCount,
"uploader": uploader, "uploader": uploader,
"uploadTime": uploadTime, "uploadTime": uploadTime,
"updateTime": updateTime, "updateTime": updateTime,

View File

@@ -28,4 +28,12 @@ class ComicType {
} }
static const local = ComicType(0); static const local = ComicType(0);
factory ComicType.fromKey(String key) {
if(key == "local") {
return local;
} else {
return ComicType(key.hashCode);
}
}
} }

View File

@@ -27,10 +27,8 @@ abstract class BaseImageProvider<T extends BaseImageProvider<T>>
screen.size.height * _normalComicImageRatio, screen.size.height * _normalComicImageRatio,
); );
} else { } else {
_effectiveScreenWidth = max( _effectiveScreenWidth =
_effectiveScreenWidth ?? 0, max(_effectiveScreenWidth ?? 0, screen.size.width);
screen.size.width
);
} }
} }
if (_effectiveScreenWidth! < _minComicImageWidth) { if (_effectiveScreenWidth! < _minComicImageWidth) {
@@ -110,7 +108,10 @@ abstract class BaseImageProvider<T extends BaseImageProvider<T>>
try { try {
final buffer = await ImmutableBuffer.fromUint8List(data); final buffer = await ImmutableBuffer.fromUint8List(data);
return await decode(buffer, getTargetSize: _getTargetSize); return await decode(
buffer,
getTargetSize: enableResize ? _getTargetSize : null,
);
} catch (e) { } catch (e) {
await CacheManager().delete(this.key); await CacheManager().delete(this.key);
if (data.length < 2 * 1024) { if (data.length < 2 * 1024) {
@@ -151,6 +152,8 @@ abstract class BaseImageProvider<T extends BaseImageProvider<T>>
String toString() { String toString() {
return "$runtimeType($key)"; return "$runtimeType($key)";
} }
bool get enableResize => false;
} }
typedef FileDecoderCallback = Future<ui.Codec> Function(Uint8List); typedef FileDecoderCallback = Future<ui.Codec> Function(Uint8List);

View File

@@ -49,4 +49,7 @@ class ReaderImageProvider
@override @override
String get key => "$imageKey@$sourceKey@$cid@$eid"; String get key => "$imageKey@$sourceKey@$cid@$eid";
@override
bool get enableResize => true;
} }

View File

@@ -473,13 +473,15 @@ class LocalManager with ChangeNotifier {
var dir = Directory(FilePath.join(path, c.directory)); var dir = Directory(FilePath.join(path, c.directory));
dir.deleteIgnoreError(recursive: true); dir.deleteIgnoreError(recursive: true);
} }
//Deleting a local comic means that it's nolonger available, thus both favorite and history should be deleted. // Deleting a local comic means that it's nolonger available, thus both favorite and history should be deleted.
if(HistoryManager().findSync(c.id, c.comicType) != null) { if(c.comicType == ComicType.local) {
HistoryManager().remove(c.id, c.comicType); if(HistoryManager().findSync(c.id, c.comicType) != null) {
} HistoryManager().remove(c.id, c.comicType);
var folders = LocalFavoritesManager().find(c.id, c.comicType); }
for (var f in folders) { var folders = LocalFavoritesManager().find(c.id, c.comicType);
LocalFavoritesManager().deleteComicWithId(f, c.id, c.comicType); for (var f in folders) {
LocalFavoritesManager().deleteComicWithId(f, c.id, c.comicType);
}
} }
remove(c.id, c.comicType); remove(c.id, c.comicType);
notifyListeners(); notifyListeners();

View File

@@ -146,14 +146,19 @@ class ImagesDownloadTask extends DownloadTask with _TransferSpeedMixin {
String? _cover; String? _cover;
/// All images to download, key is chapter name
Map<String, List<String>>? _images; Map<String, List<String>>? _images;
/// Downloaded image count
int _downloadedCount = 0; int _downloadedCount = 0;
/// Total image count
int _totalCount = 0; int _totalCount = 0;
/// Current downloading image index
int _index = 0; int _index = 0;
/// Current downloading chapter, index of [_images]
int _chapter = 0; int _chapter = 0;
var tasks = <int, _ImageDownloadWrapper>{}; var tasks = <int, _ImageDownloadWrapper>{};
@@ -180,10 +185,10 @@ class ImagesDownloadTask extends DownloadTask with _TransferSpeedMixin {
if (comic!.chapters != null) { if (comic!.chapters != null) {
saveTo = Directory(FilePath.join( saveTo = Directory(FilePath.join(
path!, path!,
comic!.chapters!.keys.elementAt(_chapter), _images!.keys.elementAt(_chapter),
)); ));
if (!saveTo.existsSync()) { if (!saveTo.existsSync()) {
saveTo.createSync(); saveTo.createSync(recursive: true);
} }
} else { } else {
saveTo = Directory(path!); saveTo = Directory(path!);

View File

@@ -172,7 +172,7 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
isLiked = comic.isLiked ?? false; isLiked = comic.isLiked ?? false;
isFavorite = comic.isFavorite ?? false; isFavorite = comic.isFavorite ?? false;
if (comic.chapters == null) { if (comic.chapters == null) {
isDownloaded = await LocalManager().isDownloaded( isDownloaded = LocalManager().isDownloaded(
comic.id, comic.id,
comic.comicType, comic.comicType,
0, 0,
@@ -292,7 +292,7 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
if (comicSource.commentsLoader != null) if (comicSource.commentsLoader != null)
_ActionButton( _ActionButton(
icon: const Icon(Icons.comment), icon: const Icon(Icons.comment),
text: (comic.commentsCount ?? 'Comments'.tl).toString(), text: (comic.commentCount ?? 'Comments'.tl).toString(),
onPressed: showComments, onPressed: showComments,
iconColor: context.useTextColor(Colors.green), iconColor: context.useTextColor(Colors.green),
), ),
@@ -679,7 +679,7 @@ abstract mixin class _ComicPageActions {
return; return;
} }
if (comic.chapters == null && if (comic.chapters == null &&
await LocalManager().isDownloaded(comic.id, comic.comicType, 0)) { LocalManager().isDownloaded(comic.id, comic.comicType, 0)) {
App.rootContext.showMessage(message: "The comic is downloaded".tl); App.rootContext.showMessage(message: "The comic is downloaded".tl);
return; return;
} }

View File

@@ -77,7 +77,7 @@ String? validateFolderName(String newFolderName) {
return null; return null;
} }
void addFavorite(Comic comic) { void addFavorite(List<Comic> comics) {
var folders = LocalFavoritesManager().folderNames; var folders = LocalFavoritesManager().folderNames;
showDialog( showDialog(
@@ -105,19 +105,21 @@ void addFavorite(Comic comic) {
FilledButton( FilledButton(
onPressed: () { onPressed: () {
if (selectedFolder != null) { if (selectedFolder != null) {
LocalFavoritesManager().addComic( for (var comic in comics) {
selectedFolder!, LocalFavoritesManager().addComic(
FavoriteItem( selectedFolder!,
id: comic.id, FavoriteItem(
name: comic.title, id: comic.id,
coverPath: comic.cover, name: comic.title,
author: comic.subtitle ?? '', coverPath: comic.cover,
type: ComicType((comic.sourceKey == 'local' author: comic.subtitle ?? '',
? 0 type: ComicType((comic.sourceKey == 'local'
: comic.sourceKey.hashCode)), ? 0
tags: comic.tags ?? [], : comic.sourceKey.hashCode)),
), tags: comic.tags ?? [],
); ),
);
}
context.pop(); context.pop();
} }
}, },

View File

@@ -14,6 +14,7 @@ import 'package:venera/foundation/local.dart';
import 'package:venera/foundation/res.dart'; import 'package:venera/foundation/res.dart';
import 'package:venera/network/download.dart'; import 'package:venera/network/download.dart';
import 'package:venera/pages/comic_page.dart'; import 'package:venera/pages/comic_page.dart';
import 'package:venera/pages/reader/reader.dart';
import 'package:venera/utils/io.dart'; import 'package:venera/utils/io.dart';
import 'package:venera/utils/translations.dart'; import 'package:venera/utils/translations.dart';
@@ -152,14 +153,14 @@ class _FavoritesPageState extends State<FavoritesPage> {
); );
} }
if (!isNetwork) { if (!isNetwork) {
return _LocalFavoritesPage(folder: folder!, key: PageStorageKey(folder!)); return _LocalFavoritesPage(folder: folder!, key: PageStorageKey("local_$folder"));
} else { } else {
var favoriteData = getFavoriteDataOrNull(folder!); var favoriteData = getFavoriteDataOrNull(folder!);
if (favoriteData == null) { if (favoriteData == null) {
folder = null; folder = null;
return buildBody(); return buildBody();
} else { } else {
return NetworkFavoritePage(favoriteData, key: PageStorageKey(folder!)); return NetworkFavoritePage(favoriteData, key: PageStorageKey("network_$folder"));
} }
} }
} }

View File

@@ -389,22 +389,29 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
), ),
]; ];
}, },
onTap: multiSelectMode onTap: (c) {
? (c) { if (multiSelectMode) {
setState(() { setState(() {
if (selectedComics.containsKey(c as FavoriteItem)) { if (selectedComics.containsKey(c as FavoriteItem)) {
selectedComics.remove(c); selectedComics.remove(c);
_checkExitSelectMode(); _checkExitSelectMode();
} else { } else {
selectedComics[c] = true; selectedComics[c] = true;
}
lastSelectedIndex = comics.indexOf(c);
});
} }
: (c) { lastSelectedIndex = comics.indexOf(c);
App.mainNavigatorKey?.currentContext });
?.to(() => ComicPage(id: c.id, sourceKey: c.sourceKey)); } else if (appdata.settings["onClickFavorite"] == "viewDetail") {
}, App.mainNavigatorKey?.currentContext
?.to(() => ComicPage(id: c.id, sourceKey: c.sourceKey));
} else {
App.mainNavigatorKey?.currentContext?.to(
() => ReaderWithLoading(
id: c.id,
sourceKey: c.sourceKey,
),
);
}
},
onLongPressed: (c) { onLongPressed: (c) {
setState(() { setState(() {
if (!multiSelectMode) { if (!multiSelectMode) {

View File

@@ -264,7 +264,8 @@ class _HistoryState extends State<_History> {
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: history.length, itemCount: history.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return InkWell( return AnimatedTapRegion(
borderRadius: 8,
onTap: () { onTap: () {
context.to( context.to(
() => ComicPage( () => ComicPage(
@@ -273,11 +274,9 @@ class _HistoryState extends State<_History> {
), ),
); );
}, },
borderRadius: BorderRadius.circular(8),
child: Container( child: Container(
width: 92, width: 92,
height: 114, height: 114,
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
color: Theme.of(context) color: Theme.of(context)
@@ -293,7 +292,7 @@ class _HistoryState extends State<_History> {
filterQuality: FilterQuality.medium, filterQuality: FilterQuality.medium,
), ),
), ),
); ).paddingHorizontal(8);
}, },
), ),
).paddingHorizontal(8).paddingBottom(16), ).paddingHorizontal(8).paddingBottom(16),
@@ -386,15 +385,14 @@ class _LocalState extends State<_Local> {
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: local.length, itemCount: local.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return InkWell( return AnimatedTapRegion(
onTap: () { onTap: () {
local[index].read(); local[index].read();
}, },
borderRadius: BorderRadius.circular(8), borderRadius: 8,
child: Container( child: Container(
width: 92, width: 92,
height: 114, height: 114,
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
color: Theme.of(context) color: Theme.of(context)
@@ -412,7 +410,7 @@ class _LocalState extends State<_Local> {
filterQuality: FilterQuality.medium, filterQuality: FilterQuality.medium,
), ),
), ),
); ).paddingHorizontal(8);
}, },
), ),
).paddingHorizontal(8), ).paddingHorizontal(8),
@@ -497,12 +495,14 @@ class _ImportComicsWidgetState extends State<_ImportComicsWidget> {
"Select a directory which contains the comic files.".tl, "Select a directory which contains the comic files.".tl,
"Select a directory which contains the comic directories.".tl, "Select a directory which contains the comic directories.".tl,
"Select a cbz/zip file.".tl, "Select a cbz/zip file.".tl,
"Select a directory which contains multiple cbz/zip files.".tl,
"Select an EhViewer database and a download folder.".tl "Select an EhViewer database and a download folder.".tl
][type]; ][type];
List<String> importMethods = [ List<String> importMethods = [
"Single Comic".tl, "Single Comic".tl,
"Multiple Comics".tl, "Multiple Comics".tl,
"A cbz file".tl, "A cbz file".tl,
"Multiple cbz files".tl,
"EhViewer downloads".tl "EhViewer downloads".tl
]; ];
@@ -630,7 +630,8 @@ class _ImportComicsWidgetState extends State<_ImportComicsWidget> {
0 => await importer.directory(true), 0 => await importer.directory(true),
1 => await importer.directory(false), 1 => await importer.directory(false),
2 => await importer.cbz(), 2 => await importer.cbz(),
3 => await importer.ehViewer(), 3 => await importer.multipleCbz(),
4 => await importer.ehViewer(),
int() => true, int() => true,
}; };
if(result) { if(result) {

View File

@@ -2,10 +2,10 @@ 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/appdata.dart'; import 'package:venera/foundation/appdata.dart';
import 'package:venera/foundation/comic_source/comic_source.dart';
import 'package:venera/foundation/local.dart'; import 'package:venera/foundation/local.dart';
import 'package:venera/foundation/log.dart'; import 'package:venera/foundation/log.dart';
import 'package:venera/pages/downloading_page.dart'; import 'package:venera/pages/downloading_page.dart';
import 'package:venera/pages/favorites/favorites_page.dart';
import 'package:venera/utils/cbz.dart'; import 'package:venera/utils/cbz.dart';
import 'package:venera/utils/epub.dart'; import 'package:venera/utils/epub.dart';
import 'package:venera/utils/io.dart'; import 'package:venera/utils/io.dart';
@@ -30,7 +30,7 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
bool multiSelectMode = false; bool multiSelectMode = false;
Map<Comic, bool> selectedComics = {}; Map<LocalComic, bool> selectedComics = {};
void update() { void update() {
if (keyword.isEmpty) { if (keyword.isEmpty) {
@@ -117,48 +117,55 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
); );
} }
Widget buildMultiSelectMenu() {
return MenuButton(entries: [
MenuEntry(
icon: Icons.delete_outline,
text: "Delete".tl,
onClick: () {
deleteComics(selectedComics.keys.toList()).then((value) {
if (value) {
setState(() {
multiSelectMode = false;
selectedComics.clear();
});
}
});
},
),
MenuEntry(
icon: Icons.favorite_border,
text: "Add to favorites".tl,
onClick: () {
addFavorite(selectedComics.keys.toList());
},
),
]);
}
void selectAll() {
setState(() {
selectedComics = comics.asMap().map((k, v) => MapEntry(v, true));
});
}
void deSelect() {
setState(() {
selectedComics.clear();
});
}
void invertSelection() {
setState(() {
comics.asMap().forEach((k, v) {
selectedComics[v] = !selectedComics.putIfAbsent(v, () => false);
});
selectedComics.removeWhere((k, v) => !v);
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
void selectAll() {
setState(() {
selectedComics = comics.asMap().map((k, v) => MapEntry(v, true));
});
}
void deSelect() {
setState(() {
selectedComics.clear();
});
}
void invertSelection() {
setState(() {
comics.asMap().forEach((k, v) {
selectedComics[v] = !selectedComics.putIfAbsent(v, () => false);
});
selectedComics.removeWhere((k, v) => !v);
});
}
void selectRange() {
setState(() {
List<int> l = [];
selectedComics.forEach((k, v) {
l.add(comics.indexOf(k as LocalComic));
});
if (l.isEmpty) {
return;
}
l.sort();
int start = l.first;
int end = l.last;
selectedComics.clear();
selectedComics.addEntries(List.generate(end - start + 1, (i) {
return MapEntry(comics[start + i], true);
}));
});
}
List<Widget> selectActions = [ List<Widget> selectActions = [
IconButton( IconButton(
icon: const Icon(Icons.select_all), icon: const Icon(Icons.select_all),
@@ -172,10 +179,7 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
icon: const Icon(Icons.flip), icon: const Icon(Icons.flip),
tooltip: "Invert Selection".tl, tooltip: "Invert Selection".tl,
onPressed: invertSelection), onPressed: invertSelection),
IconButton( buildMultiSelectMenu(),
icon: const Icon(Icons.border_horizontal_outlined),
tooltip: "Select in range".tl,
onPressed: selectRange),
]; ];
var body = Scaffold( var body = Scaffold(
@@ -212,19 +216,6 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
}, },
), ),
), ),
Tooltip(
message: multiSelectMode
? "Exit Multi-Select".tl
: "Multi-Select".tl,
child: IconButton(
icon: const Icon(Icons.checklist),
onPressed: () {
setState(() {
multiSelectMode = !multiSelectMode;
});
},
),
),
], ],
) )
else if (multiSelectMode) else if (multiSelectMode)
@@ -275,65 +266,42 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
SliverGridComics( SliverGridComics(
comics: comics, comics: comics,
selections: selectedComics, selections: selectedComics,
onTap: multiSelectMode onLongPressed: (c) {
? (c) { setState(() {
setState(() { multiSelectMode = true;
if (selectedComics.containsKey(c as LocalComic)) { selectedComics[c as LocalComic] = true;
selectedComics.remove(c); });
} else { },
selectedComics[c] = true; onTap: (c) {
} if(multiSelectMode) {
}); setState(() {
if (selectedComics.containsKey(c as LocalComic)) {
selectedComics.remove(c);
} else {
selectedComics[c] = true;
} }
: (c) { if(selectedComics.isEmpty) {
(c as LocalComic).read(); multiSelectMode = false;
}, }
});
} else {
(c as LocalComic).read();
}
},
menuBuilder: (c) { menuBuilder: (c) {
return [ return [
MenuEntry( MenuEntry(
icon: Icons.delete, icon: Icons.delete,
text: "Delete".tl, text: "Delete".tl,
onClick: () { onClick: () {
showDialog( deleteComics([c as LocalComic]).then((value) {
context: context, if (value && multiSelectMode) {
builder: (context) { setState(() {
bool removeComicFile = true; multiSelectMode = false;
return StatefulBuilder(builder: (context, state) { selectedComics.clear();
return ContentDialog(
title: "Delete".tl,
content: CheckboxListTile(
title: Text("Also remove files on disk".tl),
value: removeComicFile,
onChanged: (v) {
state(() {
removeComicFile = !removeComicFile;
});
},
),
actions: [
FilledButton(
onPressed: () {
context.pop();
if (multiSelectMode) {
for (var comic in selectedComics.keys) {
LocalManager().deleteComic(
comic as LocalComic,
removeComicFile);
}
setState(() {
selectedComics.clear();
});
} else {
LocalManager().deleteComic(
c as LocalComic, removeComicFile);
}
},
child: Text("Confirm".tl),
),
],
);
});
}); });
}
});
}), }),
MenuEntry( MenuEntry(
icon: Icons.outbox_outlined, icon: Icons.outbox_outlined,
@@ -344,26 +312,14 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
allowCancel: false, allowCancel: false,
); );
try { try {
if (multiSelectMode) { var file = await CBZ.export(c as LocalComic);
for (var comic in selectedComics.keys) { await saveFile(filename: file.name, file: file);
var file = await CBZ.export(comic as LocalComic); await file.delete();
await saveFile(filename: file.name, file: file);
await file.delete();
}
setState(() {
selectedComics.clear();
});
} else {
var file = await CBZ.export(c as LocalComic);
await saveFile(filename: file.name, file: file);
await file.delete();
}
} catch (e) { } catch (e) {
context.showMessage(message: e.toString()); context.showMessage(message: e.toString());
} }
controller.close(); controller.close();
}), }),
if (!multiSelectMode)
MenuEntry( MenuEntry(
icon: Icons.picture_as_pdf_outlined, icon: Icons.picture_as_pdf_outlined,
text: "Export as pdf".tl, text: "Export as pdf".tl,
@@ -391,7 +347,6 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
} }
}, },
), ),
if (!multiSelectMode)
MenuEntry( MenuEntry(
icon: Icons.import_contacts_outlined, icon: Icons.import_contacts_outlined,
text: "Export as epub".tl, text: "Export as epub".tl,
@@ -444,4 +399,44 @@ class _LocalComicsPageState extends State<LocalComicsPage> {
child: body, child: body,
); );
} }
Future<bool> deleteComics(List<LocalComic> comics) async {
bool isDeleted = false;
await showDialog(
context: App.rootContext,
builder: (context) {
bool removeComicFile = true;
return StatefulBuilder(builder: (context, state) {
return ContentDialog(
title: "Delete".tl,
content: CheckboxListTile(
title: Text("Also remove files on disk".tl),
value: removeComicFile,
onChanged: (v) {
state(() {
removeComicFile = !removeComicFile;
});
},
),
actions: [
FilledButton(
onPressed: () {
context.pop();
for (var comic in comics) {
LocalManager().deleteComic(
comic,
removeComicFile,
);
}
isDeleted = true;
},
child: Text("Confirm".tl),
),
],
);
});
},
);
return isDeleted;
}
} }

View File

@@ -25,7 +25,7 @@ class _ReaderImagesState extends State<_ReaderImages> {
if (inProgress) return; if (inProgress) return;
inProgress = true; inProgress = true;
if (reader.type == ComicType.local || if (reader.type == ComicType.local ||
(await LocalManager() (LocalManager()
.isDownloaded(reader.cid, reader.type, reader.chapter))) { .isDownloaded(reader.cid, reader.type, reader.chapter))) {
try { try {
var images = await LocalManager() var images = await LocalManager()

View File

@@ -0,0 +1,101 @@
part of 'reader.dart';
class ReaderWithLoading extends StatefulWidget {
const ReaderWithLoading({
super.key,
required this.id,
required this.sourceKey,
});
final String id;
final String sourceKey;
@override
State<ReaderWithLoading> createState() => _ReaderWithLoadingState();
}
class _ReaderWithLoadingState
extends LoadingState<ReaderWithLoading, ReaderProps> {
@override
Widget buildContent(BuildContext context, ReaderProps data) {
return Reader(
type: data.type,
cid: data.cid,
name: data.name,
chapters: data.chapters,
history: data.history,
);
}
@override
Future<Res<ReaderProps>> loadData() async {
var comicSource = ComicSource.find(widget.sourceKey);
var history = HistoryManager().findSync(
widget.id,
ComicType.fromKey(widget.sourceKey),
);
if (comicSource == null) {
var localComic = LocalManager().find(
widget.id,
ComicType.fromKey(widget.sourceKey),
);
if (localComic == null) {
return Res.error("comic not found");
}
return Res(
ReaderProps(
type: ComicType.fromKey(widget.sourceKey),
cid: widget.id,
name: localComic.title,
chapters: localComic.chapters,
history: history ??
History.fromModel(
model: localComic,
ep: 0,
page: 0,
),
),
);
} else {
var comic = await comicSource.loadComicInfo!(widget.id);
if (comic.error) {
return Res.fromErrorRes(comic);
}
return Res(
ReaderProps(
type: ComicType.fromKey(widget.sourceKey),
cid: widget.id,
name: comic.data.title,
chapters: comic.data.chapters,
history: history ??
History.fromModel(
model: comic.data,
ep: 0,
page: 0,
),
),
);
}
}
}
class ReaderProps {
final ComicType type;
final String cid;
final String name;
final Map<String, String>? chapters;
final History history;
const ReaderProps({
required this.type,
required this.cid,
required this.name,
required this.chapters,
required this.history,
});
}

View File

@@ -18,11 +18,13 @@ import 'package:venera/components/custom_slider.dart';
import 'package:venera/foundation/app.dart'; import 'package:venera/foundation/app.dart';
import 'package:venera/foundation/appdata.dart'; import 'package:venera/foundation/appdata.dart';
import 'package:venera/foundation/cache_manager.dart'; import 'package:venera/foundation/cache_manager.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/reader_image.dart'; import 'package:venera/foundation/image_provider/reader_image.dart';
import 'package:venera/foundation/local.dart'; import 'package:venera/foundation/local.dart';
import 'package:venera/foundation/log.dart'; import 'package:venera/foundation/log.dart';
import 'package:venera/foundation/res.dart';
import 'package:venera/pages/settings/settings_page.dart'; import 'package:venera/pages/settings/settings_page.dart';
import 'package:venera/utils/data_sync.dart'; import 'package:venera/utils/data_sync.dart';
import 'package:venera/utils/file_type.dart'; import 'package:venera/utils/file_type.dart';
@@ -36,6 +38,7 @@ part 'scaffold.dart';
part 'images.dart'; part 'images.dart';
part 'gesture.dart'; part 'gesture.dart';
part 'comic_image.dart'; part 'comic_image.dart';
part 'loading.dart';
extension _ReaderContext on BuildContext { extension _ReaderContext on BuildContext {
_ReaderState get reader => findAncestorStateOfType<_ReaderState>()!; _ReaderState get reader => findAncestorStateOfType<_ReaderState>()!;

View File

@@ -16,18 +16,18 @@ class _LocalFavoritesSettingsState extends State<LocalFavoritesSettings> {
SelectSetting( SelectSetting(
title: "Add new favorite to".tl, title: "Add new favorite to".tl,
settingKey: "newFavoriteAddTo", settingKey: "newFavoriteAddTo",
optionTranslation: const { optionTranslation: {
"start": "Start", "start": "Start".tl,
"end": "End", "end": "End".tl,
}, },
).toSliver(), ).toSliver(),
SelectSetting( SelectSetting(
title: "Move favorite after reading".tl, title: "Move favorite after reading".tl,
settingKey: "moveFavoriteAfterRead", settingKey: "moveFavoriteAfterRead",
optionTranslation: const { optionTranslation: {
"none": "None", "none": "None".tl,
"end": "End", "end": "End".tl,
"start": "Start", "start": "Start".tl,
}, },
).toSliver(), ).toSliver(),
SelectSetting( SelectSetting(
@@ -48,6 +48,14 @@ class _LocalFavoritesSettingsState extends State<LocalFavoritesSettings> {
}, },
actionTitle: 'Delete'.tl, actionTitle: 'Delete'.tl,
).toSliver(), ).toSliver(),
SelectSetting(
title: "Click favorite".tl,
settingKey: "onClickFavorite",
optionTranslation: {
"viewDetail": "View Detail".tl,
"read": "Read".tl,
},
).toSliver(),
], ],
); );
} }

View File

@@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:isolate';
import 'package:venera/foundation/app.dart'; import 'package:venera/foundation/app.dart';
import 'package:venera/foundation/comic_type.dart'; import 'package:venera/foundation/comic_type.dart';
@@ -63,7 +62,7 @@ abstract class CBZ {
var cache = Directory(FilePath.join(App.cachePath, 'cbz_import')); var cache = Directory(FilePath.join(App.cachePath, 'cbz_import'));
if (cache.existsSync()) cache.deleteSync(recursive: true); if (cache.existsSync()) cache.deleteSync(recursive: true);
cache.createSync(); cache.createSync();
await Isolate.run(() => ZipFile.openAndExtract(file.path, cache.path)); await ZipFile.openAndExtractAsync(file.path, cache.path, 4);
var metaDataFile = File(FilePath.join(cache.path, 'metadata.json')); var metaDataFile = File(FilePath.join(cache.path, 'metadata.json'));
ComicMetaData? metaData; ComicMetaData? metaData;
if (metaDataFile.existsSync()) { if (metaDataFile.existsSync()) {
@@ -208,13 +207,13 @@ abstract class CBZ {
).toJson(), ).toJson(),
), ),
); );
var cbz = File(FilePath.join(App.cachePath, '${comic.title}.cbz')); var cbz = File(FilePath.join(App.cachePath, sanitizeFileName('${comic.title}.cbz')));
await _compress(cache.path, cbz.path); await _compress(cache.path, cbz.path);
cache.deleteSync(recursive: true); cache.deleteSync(recursive: true);
return cbz; return cbz;
} }
static _compress(String src, String dst) async { static _compress(String src, String dst) async {
await Isolate.run(() => ZipFile.compressFolder(src, dst)); await ZipFile.compressFolderAsync(src, dst, 4);
} }
} }

View File

@@ -37,6 +37,33 @@ class ImportComic {
return registerComics(imported, false); return registerComics(imported, false);
} }
Future<bool> multipleCbz() async {
var picker = DirectoryPicker();
var dir = await picker.pickDirectory();
if (dir != null) {
var files = (await dir.list().toList()).whereType<File>().toList();
files.removeWhere((e) => e.extension != 'cbz' && e.extension != 'zip');
Map<String?, List<LocalComic>> imported = {};
var controller = showLoadingDialog(App.rootContext, allowCancel: false);
var comics = <LocalComic>[];
for (var file in files) {
try {
var comic = await CBZ.import(file);
comics.add(comic);
} catch (e, s) {
Log.error("Import Comic", e.toString(), s);
}
}
if (comics.isEmpty) {
App.rootContext.showMessage(message: "No valid comics found".tl);
}
imported[selectedFolder] = comics;
controller.close();
return registerComics(imported, false);
}
return false;
}
Future<bool> ehViewer() async { Future<bool> ehViewer() async {
var dbFile = await selectFile(ext: ['db']); var dbFile = await selectFile(ext: ['db']);
final picker = DirectoryPicker(); final picker = DirectoryPicker();

View File

@@ -72,6 +72,7 @@ extension FileSystemEntityExt on FileSystemEntity {
} }
extension FileExtension on File { extension FileExtension on File {
/// Get the file extension, not including the dot.
String get extension => path.split('.').last; String get extension => path.split('.').last;
/// Copy the file to the specified path using memory. /// Copy the file to the specified path using memory.

43
macos/Podfile Normal file
View File

@@ -0,0 +1,43 @@
platform :osx, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_macos_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_macos_build_settings(target)
end
end

View File

@@ -557,7 +557,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14; MACOSX_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule; SWIFT_COMPILATION_MODE = wholemodule;
@@ -639,7 +639,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14; MACOSX_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx; SDKROOT = macosx;
@@ -689,7 +689,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14; MACOSX_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule; SWIFT_COMPILATION_MODE = wholemodule;

View File

@@ -408,8 +408,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: ade0b9d ref: "1657f62fe7545ac43a339e0a5ee2b82bacd81e9f"
resolved-ref: ade0b9d67331118c13a2b836684858e251512373 resolved-ref: "1657f62fe7545ac43a339e0a5ee2b82bacd81e9f"
url: "https://github.com/wgh136/flutter_qjs" url: "https://github.com/wgh136/flutter_qjs"
source: git source: git
version: "0.3.7" version: "0.3.7"
@@ -433,8 +433,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: "3315082b9f7055655610e4f6f136b69e48228c05" ref: "7637b8b67d0a831f3cd7e702b8173e300880d32e"
resolved-ref: "3315082b9f7055655610e4f6f136b69e48228c05" resolved-ref: "7637b8b67d0a831f3cd7e702b8173e300880d32e"
url: "https://github.com/pkuislm/flutter_saf.git" url: "https://github.com/pkuislm/flutter_saf.git"
source: git source: git
version: "0.0.1" version: "0.0.1"
@@ -446,11 +446,10 @@ packages:
flutter_to_arch: flutter_to_arch:
dependency: "direct dev" dependency: "direct dev"
description: description:
path: "." name: flutter_to_arch
ref: HEAD sha256: "656cffc182b05af38aa96a1115931620b8865c4b0cfe00813b26fcff0875f2ab"
resolved-ref: "15bfead0380fda79b0256b37c73b886b0882f1bf" url: "https://pub.dev"
url: "https://github.com/wgh136/flutter_to_arch" source: hosted
source: git
version: "1.0.0" version: "1.0.0"
flutter_to_debian: flutter_to_debian:
dependency: "direct dev" dependency: "direct dev"
@@ -629,8 +628,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: d1c96cd6503103b3270dfe2f320d4a1c93780f53 ref: "9a784b193af5d55b2a35e58fa390bda3e4f35d00"
resolved-ref: d1c96cd6503103b3270dfe2f320d4a1c93780f53 resolved-ref: "9a784b193af5d55b2a35e58fa390bda3e4f35d00"
url: "https://github.com/venera-app/lodepng_flutter" url: "https://github.com/venera-app/lodepng_flutter"
source: git source: git
version: "0.0.1" version: "0.0.1"
@@ -1125,12 +1124,11 @@ packages:
zip_flutter: zip_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." name: zip_flutter
ref: HEAD sha256: "955b53d58709fcd9feefbed3d41b5522bc5273e677603e9fc67017a81e568d24"
resolved-ref: d5721f1fd8179ee4a5db59f932ae7c89d94e12a0 url: "https://pub.dev"
url: "https://github.com/wgh136/zip_flutter" source: hosted
source: git version: "0.0.5"
version: "0.0.1"
sdks: sdks:
dart: ">=3.6.0 <4.0.0" dart: ">=3.6.0 <4.0.0"
flutter: ">=3.27.0" flutter: ">=3.27.1"

View File

@@ -2,11 +2,11 @@ name: venera
description: "A comic app." description: "A comic app."
publish_to: 'none' publish_to: 'none'
version: 1.1.0+110 version: 1.1.2+112
environment: environment:
sdk: '>=3.6.0 <4.0.0' sdk: '>=3.6.0 <4.0.0'
flutter: 3.27.0 flutter: 3.27.1
dependencies: dependencies:
flutter: flutter:
@@ -21,7 +21,7 @@ dependencies:
flutter_qjs: flutter_qjs:
git: git:
url: https://github.com/wgh136/flutter_qjs url: https://github.com/wgh136/flutter_qjs
ref: ade0b9d ref: 1657f62fe7545ac43a339e0a5ee2b82bacd81e9f
crypto: ^3.0.6 crypto: ^3.0.6
dio: ^5.7.0 dio: ^5.7.0
html: ^0.15.5 html: ^0.15.5
@@ -51,13 +51,11 @@ dependencies:
sliver_tools: ^0.2.12 sliver_tools: ^0.2.12
flutter_file_dialog: ^3.0.2 flutter_file_dialog: ^3.0.2
file_selector: ^1.0.3 file_selector: ^1.0.3
zip_flutter: zip_flutter: ^0.0.5
git:
url: https://github.com/wgh136/zip_flutter
lodepng_flutter: lodepng_flutter:
git: git:
url: https://github.com/venera-app/lodepng_flutter url: https://github.com/venera-app/lodepng_flutter
ref: d1c96cd6503103b3270dfe2f320d4a1c93780f53 ref: 9a784b193af5d55b2a35e58fa390bda3e4f35d00
rhttp: 0.9.6 rhttp: 0.9.6
webdav_client: webdav_client:
git: git:
@@ -68,7 +66,7 @@ dependencies:
flutter_saf: flutter_saf:
git: git:
url: https://github.com/pkuislm/flutter_saf.git url: https://github.com/pkuislm/flutter_saf.git
ref: 3315082b9f7055655610e4f6f136b69e48228c05 ref: 7637b8b67d0a831f3cd7e702b8173e300880d32e
pdf: ^3.11.1 pdf: ^3.11.1
dynamic_color: ^1.7.0 dynamic_color: ^1.7.0
shimmer: ^3.0.0 shimmer: ^3.0.0
@@ -78,8 +76,7 @@ dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^5.0.0 flutter_lints: ^5.0.0
flutter_to_arch: flutter_to_arch: ^1.0.0
git: https://github.com/wgh136/flutter_to_arch
flutter_to_debian: flutter_to_debian:
flutter: flutter:

View File

@@ -58,6 +58,7 @@ Source: "{#RootPath}\build\windows\x64\runner\Release\local_auth_windows_plugin.
Source: "{#RootPath}\build\windows\x64\runner\Release\zip_flutter.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "{#RootPath}\build\windows\x64\runner\Release\zip_flutter.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#RootPath}\build\windows\x64\runner\Release\rhttp.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "{#RootPath}\build\windows\x64\runner\Release\rhttp.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#RootPath}\build\windows\x64\runner\Release\lodepng_flutter.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "{#RootPath}\build\windows\x64\runner\Release\lodepng_flutter.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#RootPath}\build\windows\x64\runner\Release\dynamic_color_plugin.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#RootPath}\build\windows\x64\runner\Release\data\*"; DestDir: "{app}\data"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "{#RootPath}\build\windows\x64\runner\Release\data\*"; DestDir: "{app}\data"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files ; NOTE: Don't use "Flags: ignoreversion" on any shared system files