Skip to content

Commit

Permalink
✨ Export download to zip or cbz
Browse files Browse the repository at this point in the history
  • Loading branch information
niuhuan committed Jun 29, 2023
1 parent 7f6891e commit a17984f
Show file tree
Hide file tree
Showing 13 changed files with 517 additions and 33 deletions.
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ android {

defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "opensource.wax"
applicationId "opensource.wax22"
minSdkVersion 19 // flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
Expand Down
2 changes: 1 addition & 1 deletion android/app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="opensource.wax">
package="opensource.wax22">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package opensource.wax
package opensource.wax22

import android.content.ContentValues
import android.content.DialogInterface
Expand Down
2 changes: 1 addition & 1 deletion android/app/src/profile/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="opensource.wax">
package="opensource.wax22">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
Expand Down
53 changes: 53 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,16 +1,64 @@
PODS:
- DKImagePickerController/Core (4.3.4):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.4)
- DKImagePickerController/PhotoGallery (4.3.4):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.4)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0)
- permission_handler_apple (9.1.0):
- Flutter
- SDWebImage (5.13.5):
- SDWebImage/Core (= 5.13.5)
- SDWebImage/Core (5.13.5)
- SwiftyGif (5.4.3)
- url_launcher_ios (0.0.1):
- Flutter

DEPENDENCIES:
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)

SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- SDWebImage
- SwiftyGif

EXTERNAL SOURCES:
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
permission_handler_apple:
Expand All @@ -19,8 +67,13 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/url_launcher_ios/ios"

SPEC CHECKSUMS:
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
permission_handler_apple: 8f116445eff3c0e7c65ad60f5fef5490aa94b4e4
SDWebImage: 23d714cd599354ee7906dbae26dff89b421c4370
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4

PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
Expand Down
18 changes: 18 additions & 0 deletions lib/basic/methods.dart
Original file line number Diff line number Diff line change
Expand Up @@ -368,4 +368,22 @@ class Methods {
Future<String> iosGetDocumentDir() async {
return await _channel.invokeMethod('iosGetDocumentDir', '');
}

Future<String> getProServerName() async {
final buff = await _flatInvoke(
"getProServerName",
FavoritesPartitionsQuery(
host: host,
));
return StringValue.fromBuffer(buff).value;
}

Future<String> setProServerName(String severName) async {
final buff = await _flatInvoke(
"setProServerName",
StringValue(
value: severName,
));
return StringValue.fromBuffer(buff).value;
}
}
47 changes: 47 additions & 0 deletions lib/protos/properties.pb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2118,6 +2118,53 @@ class DownloadComicPageDto extends $pb.GeneratedMessage {
void clearCaption() => clearField(6);
}

class StringValue extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'StringValue', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value')
..hasRequiredFields = false
;

StringValue._() : super();
factory StringValue({
$core.String? value,
}) {
final _result = create();
if (value != null) {
_result.value = value;
}
return _result;
}
factory StringValue.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory StringValue.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
StringValue clone() => StringValue()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
StringValue copyWith(void Function(StringValue) updates) => super.copyWith((message) => updates(message as StringValue)) as StringValue; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static StringValue create() => StringValue._();
StringValue createEmptyInstance() => create();
static $pb.PbList<StringValue> createRepeated() => $pb.PbList<StringValue>();
@$core.pragma('dart2js:noInline')
static StringValue getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<StringValue>(create);
static StringValue? _defaultInstance;

@$pb.TagNumber(1)
$core.String get value => $_getSZ(0);
@$pb.TagNumber(1)
set value($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasValue() => $_has(0);
@$pb.TagNumber(1)
void clearValue() => clearField(1);
}

class IntValue extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'IntValue', createEmptyInstance: create)
..aInt64(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value')
Expand Down
10 changes: 10 additions & 0 deletions lib/protos/properties.pbjson.dart
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,16 @@ const DownloadComicPageDto$json = const {

/// Descriptor for `DownloadComicPageDto`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List downloadComicPageDtoDescriptor = $convert.base64Decode('ChREb3dubG9hZENvbWljUGFnZUR0bxIUCgV3aWR0aBgBIAEoA1IFd2lkdGgSFgoGaGVpZ2h0GAIgASgDUgZoZWlnaHQSFgoGZm9ybWF0GAMgASgJUgZmb3JtYXQSEgoEcGF0aBgEIAEoCVIEcGF0aBIQCgN1cmwYBSABKAlSA3VybBIYCgdjYXB0aW9uGAYgASgJUgdjYXB0aW9u');
@$core.Deprecated('Use stringValueDescriptor instead')
const StringValue$json = const {
'1': 'StringValue',
'2': const [
const {'1': 'value', '3': 1, '4': 1, '5': 9, '10': 'value'},
],
};

/// Descriptor for `StringValue`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List stringValueDescriptor = $convert.base64Decode('CgtTdHJpbmdWYWx1ZRIUCgV2YWx1ZRgBIAEoCVIFdmFsdWU=');
@$core.Deprecated('Use intValueDescriptor instead')
const IntValue$json = const {
'1': 'IntValue',
Expand Down
187 changes: 187 additions & 0 deletions lib/screens/exporting_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import 'dart:io';

import 'package:file_picker/file_picker.dart';
import 'package:fixnum/src/int64.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:wax/basic/methods.dart';

import '../basic/commons.dart';
import '../configs/android_version.dart';

class ExportingScreen extends StatefulWidget {
final List<Int64> selected;

const ExportingScreen(this.selected, {Key? key}) : super(key: key);

@override
State<StatefulWidget> createState() => _ExportingScreenState();
}

class _ExportingScreenState extends State<ExportingScreen> {
int _exportStatus = 0; // 0: 未开始, 1: 正在导出, 2: 导出完成, 3: 导出失败
String _exportMessage = "";

@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (_exportStatus == 1) {
defaultToast(context, "正在导出, 请稍后");
return false;
}
return true;
},
child: Scaffold(
appBar: AppBar(
title: const Text("导出"),
),
body: _buildBody(),
),
);
}

Widget _buildBody() {
switch (_exportStatus) {
case 0:
return _buildStart();
case 1:
return _buildExporting();
case 2:
return _buildFinish();
case 3:
return _buildError();
default:
return Container();
}
}

Widget _buildStart() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("您一共选择了 ${widget.selected.length} 个漫画"),
const SizedBox(height: 20),
exportToZipButton(),
exportToCzbButton(),
],
),
);
}

Widget _buildExporting() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text("导出中..."),
SizedBox(height: 20),
CupertinoActivityIndicator(),
],
),
);
}

Widget _buildFinish() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("导出完成"),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text("返回"),
),
],
),
);
}

Widget _buildError() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("导出失败"),
Text(_exportMessage),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text("返回"),
),
],
),
);
}

Widget exportToZipButton() {
return ElevatedButton(
onPressed: () async {
_export(1);
},
child: const Text("导出到zip"),
);
}

Widget exportToCzbButton() {
return ElevatedButton(
onPressed: () async {
_export(2);
},
child: const Text("导出到czb"),
);
}

void _export(int type) async {
String? folder = await chooseFolder();
if (folder == null) {
return;
}
setState(() {
_exportStatus = 1;
});
try {
await methods.exportToDir(folder, widget.selected, type);
setState(() {
_exportStatus = 2;
});
} catch (e) {
setState(() {
_exportStatus = 3;
});
}
}

Future<String?> chooseFolder() async {
if (Platform.isIOS) {
if (await confirmDialog(
context,
"您确认导出吗",
"将会导出到您iOS设备的\"文件\"应用中, 曾经导出过的同名文件会覆盖",
)) {
return methods.iosGetDocumentDir();
}
return null;
}
if (Platform.isAndroid) {
late bool g;
if (androidVersion < 30) {
g = await Permission.storage.request().isGranted;
} else {
g = await Permission.manageExternalStorage.request().isGranted;
}
if (!g) {
throw Exception("申请权限被拒绝");
}
}
return FilePicker.platform
.getDirectoryPath(dialogTitle: "选择一个文件夹, 将文件保存到这里");
}
}
Loading

0 comments on commit a17984f

Please sign in to comment.