download and downloading page

This commit is contained in:
wgh19
2024-05-14 13:49:54 +08:00
parent 615720ab49
commit 842a52f53d
13 changed files with 661 additions and 68 deletions

View File

@@ -1,6 +1,9 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'foundation/app.dart';
import 'network/models.dart';
@@ -9,9 +12,18 @@ class _Appdata {
var searchOptions = SearchOptions();
Map<String, dynamic> settings = {
"downloadPath": null,
"downloadSubPath": r"/${id}-p${index}.${ext}",
"tagsWeight": "",
"useTranslatedNameForDownload": false,
};
void writeData() async {
await File("${App.dataPath}/account.json")
.writeAsString(jsonEncode(account));
await File("${App.dataPath}/settings.json")
.writeAsString(jsonEncode(settings));
}
Future<void> readData() async {
@@ -19,6 +31,39 @@ class _Appdata {
if (file.existsSync()) {
account = Account.fromJson(jsonDecode(await file.readAsString()));
}
final settingsFile = File("${App.dataPath}/settings.json");
if (settingsFile.existsSync()) {
var json = jsonDecode(await settingsFile.readAsString());
for(var key in json.keys) {
settings[key] = json[key];
}
}
if(settings["downloadPath"] == null) {
settings["downloadPath"] = await _defaultDownloadPath;
}
}
String get downloadPath => settings["downloadPath"];
Future<String> get _defaultDownloadPath async{
if(App.isAndroid) {
var externalStoragePaths = await getExternalStorageDirectories(type: StorageDirectory.downloads);
var res = externalStoragePaths?.first.path;
res ??= (await getExternalStorageDirectory())!.path;
return "$res/pixes";
} else if (App.isWindows){
var res = await const MethodChannel("pixes/picture_folder").invokeMethod("");
if(res != "error") {
return res + "/pixes";
}
} else if (App.isMacOS || App.isLinux) {
var downloadPath = (await getDownloadsDirectory())?.path;
if(downloadPath != null) {
return "$downloadPath/pixes";
}
}
return "${App.dataPath}/download";
}
}

View File

@@ -150,12 +150,16 @@ class CachedImageProvider extends BaseImageProvider<CachedImageProvider> {
Future<Uint8List> load(StreamController<ImageChunkEvent> chunkEvents) async{
var cached = await CacheManager().findCache(key);
if(cached != null) {
chunkEvents.add(const ImageChunkEvent(
cumulativeBytesLoaded: 1,
expectedTotalBytes: 1,
));
return await File(cached).readAsBytes();
}
var dio = AppDio();
final time = DateFormat("yyyy-MM-dd'T'HH:mm:ss'+00:00'").format(DateTime.now());
final hash = md5.convert(utf8.encode(time + Network.hashSalt)).toString();
var res = await dio.get(
var res = await dio.get<ResponseBody>(
url,
options: Options(
responseType: ResponseType.stream,
@@ -174,12 +178,16 @@ class CachedImageProvider extends BaseImageProvider<CachedImageProvider> {
}
var data = <int>[];
var cachingFile = await CacheManager().openWrite(key);
await for (var chunk in res.data.stream) {
await for (var chunk in res.data!.stream) {
var length = res.data!.contentLength+1;
if(length < data.length) {
length = data.length + 1;
}
data.addAll(chunk);
await cachingFile.writeBytes(chunk);
chunkEvents.add(ImageChunkEvent(
cumulativeBytesLoaded: data.length,
expectedTotalBytes: res.data.contentLength+1,
expectedTotalBytes: length,
));
}
await cachingFile.close();

View File

@@ -56,4 +56,12 @@ extension WidgetExtension on Widget{
Widget sliverPaddingHorizontal(double padding){
return SliverPadding(padding: EdgeInsets.symmetric(horizontal: padding), sliver: this);
}
Widget fixWidth(double width){
return SizedBox(width: width, child: this);
}
Widget fixHeight(double height){
return SizedBox(height: height, child: this);
}
}

View File

@@ -1,5 +1,268 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:intl/intl.dart';
import 'package:pixes/appdata.dart';
import 'package:pixes/foundation/app.dart';
import 'package:pixes/foundation/log.dart';
import 'package:pixes/network/app_dio.dart';
import 'package:pixes/network/network.dart';
import 'package:pixes/utils/io.dart';
import 'package:sqlite3/sqlite3.dart';
extension IllustExt on Illust {
bool get downloaded => false;
bool get downloaded => DownloadManager().checkDownloaded(id);
bool get downloading =>
DownloadManager().tasks.any((element) => element.illust.id == id);
}
class DownloadedIllust {
final int illustId;
final String title;
final String author;
final int imageCount;
DownloadedIllust({
required this.illustId,
required this.title,
required this.author,
required this.imageCount,
});
}
class DownloadingTask {
final Illust illust;
void Function(int)? receiveBytesCallback;
void Function(DownloadingTask)? onCompleted;
DownloadingTask(this.illust, {this.receiveBytesCallback, this.onCompleted});
int _downloadingIndex = 0;
int get totalImages => illust.images.length;
int get downloadedImages => _downloadingIndex;
bool _stop = true;
String? error;
void start() {
_stop = false;
_download();
}
Dio get dio => Network().dio;
void cancel() {
_stop = true;
DownloadManager().tasks.remove(this);
for(var path in imagePaths) {
File(path).deleteIfExists();
}
}
List<String> imagePaths = [];
void _download() async{
try{
while(_downloadingIndex < illust.images.length) {
if(_stop) return;
var url = illust.images[_downloadingIndex].original;
var ext = url.split('.').last;
if(!["jpg", "png", "gif", "webp", "jpeg", "avif"].contains(ext)) {
ext = "jpg";
}
var path = _generateFilePath(illust, _downloadingIndex, ext);
final time = DateFormat("yyyy-MM-dd'T'HH:mm:ss'+00:00'").format(DateTime.now());
final hash = md5.convert(utf8.encode(time + Network.hashSalt)).toString();
var res = await dio.get<ResponseBody>(url, options: Options(
responseType: ResponseType.stream,
headers: {
"referer": "https://app-api.pixiv.net/",
"user-agent": "PixivAndroidApp/5.0.234 (Android 14; Pixes)",
"x-client-time": time,
"x-client-hash": hash,
"accept-enconding": "gzip",
},
));
var file = File(path);
if(!file.existsSync()) {
file.createSync(recursive: true);
}
await for (var data in res.data!.stream) {
await file.writeAsBytes(data, mode: FileMode.append);
receiveBytesCallback?.call(data.length);
}
imagePaths.add(path);
_downloadingIndex++;
}
onCompleted?.call(this);
}
catch(e, s) {
error = e.toString();
_stop = true;
Log.error("Download", "Download error: $e\n$s");
}
}
static String _generateFilePath(Illust illust, int index, String ext) {
final String downloadPath = appdata.settings["downloadPath"];
final String subPathPatten = appdata.settings["downloadSubPath"];
final tags = appdata.settings["useTranslatedNameForDownload"] == false
? illust.tags.map((e) => e.name).toList()
: illust.tags.map((e) => e.translatedName ?? e.name).toList();
final tagsWeight = (appdata.settings["tagsWeight"] as String).split(' ');
tags.sort((a, b) => tagsWeight.indexOf(a) - tagsWeight.indexOf(b));
subPathPatten.replaceAll(r"${id}", illust.id.toString());
subPathPatten.replaceAll(r"${title}", illust.title);
subPathPatten.replaceAll(r"${author}", illust.author.name);
subPathPatten.replaceAll(r"${ext}", ext);
for(int i=0; i<tags.length; i++) {
subPathPatten.replaceAll("\${tag$i}", tags[i]);
}
return "$downloadPath$subPathPatten";
}
void retry() {
error = null;
_stop = false;
_download();
}
}
class DownloadManager {
factory DownloadManager() => instance ??= DownloadManager._();
static DownloadManager? instance;
DownloadManager._(){
init();
}
late Database _db;
int _currentBytes = 0;
int _bytesPerSecond = 0;
int get bytesPerSecond => _bytesPerSecond;
Timer? _loop;
var tasks = <DownloadingTask>[];
void Function()? uiUpdateCallback;
void registerUiUpdater(void Function() callback) {
uiUpdateCallback = callback;
}
void removeUiUpdater() {
uiUpdateCallback = null;
}
void init() {
_db = sqlite3.open("${App.dataPath}/download.db");
_db.execute('''
create table if not exists download (
illust_id integer primary key not null,
title text not null,
author text not null,
imageCount int not null
);
''');
_db.execute('''
create table if not exists images (
illust_id integer not null,
image_index integer not null,
path text not null,
primary key (illust_id, image_index)
);
''');
}
void saveInfo(Illust illust, List<String> imagePaths) {
_db.execute('''
insert into download (illust_id, title, author, imageCount)
values (?, ?, ?, ?)
''', [illust.id, illust.title, illust.author.name, imagePaths.length]);
for (var i = 0; i < imagePaths.length; i++) {
_db.execute('''
insert into images (illust_id, image_index, path)
values (?, ?, ?)
''', [illust.id, i, imagePaths[i]]);
}
}
File? getImage(int illustId, int index) {
var res = _db.select('''
select * from images
where illust_id = ? and image_index = ?;
''');
if (res.isEmpty) return null;
var file = File(res.first["path"] as String);
if (!file.existsSync()) return null;
return file;
}
bool checkDownloaded(int illustId) {
var res = _db.select('''
select * from download
where illust_id = ?;
''', [illustId]);
return res.isNotEmpty;
}
List<DownloadedIllust> listAll() {
var res = _db.select('''
select * from download;
''');
return res.map((e) =>
DownloadedIllust(
illustId: e["illust_id"] as int,
title: e["title"] as String,
author: e["author"] as String,
imageCount: e["imageCount"] as int,
)).toList();
}
void addDownloadingTask(Illust illust) {
var task = DownloadingTask(illust, receiveBytesCallback: receiveBytes, onCompleted: (task) {
saveInfo(illust, task.imagePaths);
tasks.remove(task);
});
tasks.add(task);
run();
}
void receiveBytes(int bytes) {
_currentBytes += bytes;
}
int get maxConcurrentTasks => 3;
void run() {
_loop ??= Timer.periodic(const Duration(seconds: 1), (timer) {
_bytesPerSecond = _currentBytes;
_currentBytes = 0;
uiUpdateCallback?.call();
for(int i=0; i<maxConcurrentTasks; i++) {
var task = tasks.elementAtOrNull(i);
if(task != null && task._stop && task.error == null) {
task.start();
}
}
if(tasks.isEmpty) {
timer.cancel();
_loop = null;
_currentBytes = 0;
_bytesPerSecond = 0;
}
});
}
}

View File

@@ -39,7 +39,7 @@ class Network {
final dio = AppDio();
Map<String, String> get _headers {
Map<String, String> get headers {
final time =
DateFormat("yyyy-MM-dd'T'HH:mm:ss'+00:00'").format(DateTime.now());
final hash = md5.convert(utf8.encode(time + hashSalt)).toString();
@@ -80,7 +80,7 @@ class Network {
},
options: Options(
contentType: Headers.formUrlEncodedContentType,
headers: _headers));
headers: headers));
if (res.statusCode != 200) {
throw "Invalid Status code ${res.statusCode}";
}
@@ -106,7 +106,7 @@ class Network {
},
options: Options(
contentType: Headers.formUrlEncodedContentType,
headers: _headers));
headers: headers));
var account = Account.fromJson(json.decode(res.data!));
appdata.account = account;
appdata.writeData();
@@ -126,7 +126,7 @@ class Network {
final res = await dio.get<Map<String, dynamic>>(path,
queryParameters: query,
options:
Options(headers: _headers, validateStatus: (status) => true));
Options(headers: headers, validateStatus: (status) => true));
if (res.statusCode == 200) {
return Res(res.data!);
} else if (res.statusCode == 400) {
@@ -162,7 +162,7 @@ class Network {
queryParameters: query,
data: data,
options: Options(
headers: _headers,
headers: headers,
validateStatus: (status) => true,
contentType: Headers.formUrlEncodedContentType));
if (res.statusCode == 200) {

View File

@@ -1,15 +0,0 @@
import 'package:fluent_ui/fluent_ui.dart';
class DownloadPage extends StatefulWidget {
const DownloadPage({super.key});
@override
State<DownloadPage> createState() => _DownloadPageState();
}
class _DownloadPageState extends State<DownloadPage> {
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

View File

@@ -0,0 +1,15 @@
import 'package:fluent_ui/fluent_ui.dart';
class DownloadedPage extends StatefulWidget {
const DownloadedPage({super.key});
@override
State<DownloadedPage> createState() => _DownloadedPageState();
}
class _DownloadedPageState extends State<DownloadedPage> {
@override
Widget build(BuildContext context) {
return const Placeholder();
}
}

View File

@@ -0,0 +1,166 @@
import 'package:fluent_ui/fluent_ui.dart';
import 'package:pixes/components/md.dart';
import 'package:pixes/foundation/app.dart';
import 'package:pixes/foundation/image_provider.dart';
import 'package:pixes/network/download.dart';
import 'package:pixes/utils/translation.dart';
import '../utils/io.dart';
class DownloadingPage extends StatefulWidget {
const DownloadingPage({super.key});
@override
State<DownloadingPage> createState() => _DownloadingPageState();
}
class _DownloadingPageState extends State<DownloadingPage> {
@override
void initState() {
DownloadManager().registerUiUpdater(() => setState((){}));
super.initState();
}
@override
void dispose() {
DownloadManager().removeUiUpdater();
super.dispose();
}
Map<String, FlyoutController> controller = {};
@override
Widget build(BuildContext context) {
return ScaffoldPage(
content: CustomScrollView(
slivers: [
buildTop(),
const SliverPadding(padding: EdgeInsets.only(top: 16)),
buildContent()
],
),
);
}
Widget buildTop() {
int bytesPerSecond = DownloadManager().bytesPerSecond;
return SliverToBoxAdapter(
child: SizedBox(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text("${"Speed".tl}: ${bytesToText(bytesPerSecond)}/s",
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
),
),
);
}
Widget buildContent() {
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
var task = DownloadManager().tasks[index];
return buildItem(task);
},
childCount: DownloadManager().tasks.length
),
).sliverPaddingHorizontal(12);
}
Widget buildItem(DownloadingTask task) {
controller[task.illust.id.toString()] ??= FlyoutController();
return Card(
padding: const EdgeInsets.symmetric(vertical: 8),
child: SizedBox(
height: 96,
child: Row(
children: [
const SizedBox(width: 12),
Container(
height: double.infinity,
width: 72,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
border: Border.all(color: ColorScheme.of(context).outlineVariant, width: 0.6),
),
child: Image(
image: CachedImageProvider(task.illust.images.first.medium),
fit: BoxFit.cover,
filterQuality: FilterQuality.medium,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(task.illust.title, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 4),
Text(task.illust.author.name, style: const TextStyle(fontSize: 12, color: Colors.grey)),
const Spacer(),
if(task.error == null)
Text("${task.downloadedImages}/${task.totalImages} ${"Downloaded".tl}", style: const TextStyle(fontSize: 12, color: Colors.grey))
else
Text("Error: ${task.error!.replaceAll("\n", " ")}", style: TextStyle(fontSize: 12, color: ColorScheme.of(context).error), maxLines: 2,),
],
),
),
const SizedBox(width: 4),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if(task.error != null)
Button(
child: Text("Retry".tl).fixWidth(46),
onPressed: () {
task.retry();
setState(() {});
},
),
const SizedBox(height: 4),
FlyoutTarget(
controller: controller[task.illust.id.toString()]!,
child: Button(
child: Text("Cancel".tl, style: TextStyle(color: ColorScheme.of(context).error),).fixWidth(46),
onPressed: (){
controller[task.illust.id.toString()]!.showFlyout(
navigatorKey: App.rootNavigatorKey.currentState,
builder: (context) {
return FlyoutContent(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Are you sure you want to cancel this download?'.tl,
style: const TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 12.0),
Button(
onPressed: () {
Flyout.of(context).close();
task.cancel();
setState(() {});
},
child: Text('Yes'.tl),
),
],
),
);
},
);
}
),
)
],
),
const SizedBox(width: 12),
],
),
),
);
}
}

View File

@@ -1,3 +1,5 @@
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/material.dart' show Icons;
import 'package:pixes/components/animated_image.dart';
@@ -69,6 +71,11 @@ class _IllustPageState extends State<IllustPage> {
}
Widget buildImage(double width, double height, int index) {
File? downloadFile;
if(widget.illust.downloaded) {
downloadFile = DownloadManager().getImage(widget.illust.id, index);
}
if (index == 0) {
return Text(
widget.illust.title,
@@ -93,9 +100,13 @@ class _IllustPageState extends State<IllustPage> {
width: imageWidth,
height: imageHeight,
child: GestureDetector(
onTap: () => ImagePage.show(widget.illust.images[index].original),
onTap: () => ImagePage.show(downloadFile == null
? widget.illust.images[index].original
: "file://${downloadFile.path}"),
child: Image(
image: CachedImageProvider(widget.illust.images[index].large),
image: downloadFile == null
? CachedImageProvider(widget.illust.images[index].large) as ImageProvider
: FileImage(downloadFile) as ImageProvider,
width: imageWidth,
fit: BoxFit.cover,
height: imageHeight,
@@ -123,14 +134,9 @@ class _IllustPageState extends State<IllustPage> {
),
);
if (index == 0) {
return Hero(
tag: "illust_${widget.illust.id}",
child: image,
);
} else {
return image;
}
return Center(
child: image,
);
}
}
@@ -374,7 +380,10 @@ class _BottomBarState extends State<_BottomBar> {
});
}
void download() {}
void download() {
DownloadManager().addDownloadingTask(widget.illust);
setState(() {});
}
bool showText = width > 640;
@@ -416,24 +425,47 @@ class _BottomBarState extends State<_BottomBar> {
yield const SizedBox(width: 8,);
if (!widget.illust.downloaded) {
yield Button(
onPressed: download,
child: SizedBox(
height: 28,
child: Row(
children: [
const Icon(
FluentIcons.download,
size: 18,
),
if(showText)
const SizedBox(width: 8,),
if(showText)
Text("Download".tl),
],
if(widget.illust.downloading) {
yield Button(
onPressed: () => {},
child: SizedBox(
height: 28,
child: Row(
children: [
Icon(
FluentIcons.download,
color: ColorScheme.of(context).outline,
size: 18,
),
if(showText)
const SizedBox(width: 8,),
if(showText)
Text("Downloading".tl,
style: TextStyle(color: ColorScheme.of(context).outline),),
],
),
),
),
);
);
} else {
yield Button(
onPressed: download,
child: SizedBox(
height: 28,
child: Row(
children: [
const Icon(
FluentIcons.download,
size: 18,
),
if(showText)
const SizedBox(width: 8,),
if(showText)
Text("Download".tl),
],
),
),
);
}
}
yield const SizedBox(width: 8,);

View File

@@ -1,3 +1,5 @@
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:photo_view/photo_view.dart';
import 'package:pixes/components/page_route.dart';
@@ -60,7 +62,9 @@ class _ImagePageState extends State<ImagePage> with WindowListener{
color: Colors.transparent
),
filterQuality: FilterQuality.medium,
imageProvider: CachedImageProvider(widget.url),
imageProvider: widget.url.startsWith("file://")
? FileImage(File(widget.url.replaceFirst("file://", "")))
: CachedImageProvider(widget.url) as ImageProvider,
)),
Positioned(
top: 0,

View File

@@ -8,6 +8,7 @@ import "package:pixes/components/md.dart";
import "package:pixes/foundation/app.dart";
import "package:pixes/network/network.dart";
import "package:pixes/pages/bookmarks.dart";
import "package:pixes/pages/downloaded_page.dart";
import "package:pixes/pages/following_artworks.dart";
import "package:pixes/pages/ranking.dart";
import "package:pixes/pages/recommendation_page.dart";
@@ -20,7 +21,7 @@ import "package:pixes/utils/translation.dart";
import "package:window_manager/window_manager.dart";
import "../components/page_route.dart";
import "download_page.dart";
import "downloading_page.dart";
const _kAppBarHeight = 36.0;
@@ -34,7 +35,7 @@ class MainPage extends StatefulWidget {
class _MainPageState extends State<MainPage> with WindowListener {
final navigatorKey = GlobalKey<NavigatorState>();
int index = 3;
int index = 4;
int windowButtonKey = 0;
@@ -101,9 +102,14 @@ class _MainPageState extends State<MainPage> with WindowListener {
title: Text('Search'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.downloading, size: 20,),
title: Text('Downloading'.tl),
body: const SizedBox.shrink(),
),
PaneItem(
icon: const Icon(MdIcons.download, size: 20,),
title: Text('Download'.tl),
title: Text('Downloaded'.tl),
body: const SizedBox.shrink(),
),
PaneItemSeparator(),
@@ -148,7 +154,8 @@ class _MainPageState extends State<MainPage> with WindowListener {
static final pageBuilders = <Widget Function()>[
() => UserInfoPage(appdata.account!.user.id),
() => const SearchPage(),
() => const DownloadPage(),
() => const DownloadingPage(),
() => const DownloadedPage(),
() => const RecommendationPage(),
() => const BookMarkedArtworkPage(),
() => const FollowingArtworksPage(),

View File

@@ -19,4 +19,16 @@ extension FSExt on FileSystemEntity {
}
return 0;
}
}
String bytesToText(int bytes) {
if(bytes < 1024) {
return "$bytes B";
} else if(bytes < 1024 * 1024) {
return "${(bytes / 1024).toStringAsFixed(2)} KB";
} else if(bytes < 1024 * 1024 * 1024) {
return "${(bytes / 1024 / 1024).toStringAsFixed(2)} MB";
} else {
return "${(bytes / 1024 / 1024 / 1024).toStringAsFixed(2)} GB";
}
}

View File

@@ -1,14 +1,46 @@
#pragma comment(lib, "winhttp.lib")
#include "flutter_window.h"
#include <flutter/method_channel.h>
#include <flutter/event_channel.h>
#include <flutter/event_sink.h>
#include <flutter/event_stream_handler_functions.h>
#include <flutter/standard_method_codec.h>
#include <optional>
#include <ShlObj.h>
#include <winhttp.h>
#include "flutter/generated_plugin_registrant.h"
#include "utils.h"
std::unique_ptr<flutter::EventSink<flutter::EncodableValue>>&& mouseEvents = nullptr;
static std::string getProxy() {
_WINHTTP_CURRENT_USER_IE_PROXY_CONFIG net;
WinHttpGetIEProxyConfigForCurrentUser(&net);
if (net.lpszProxy == nullptr) {
GlobalFree(net.lpszAutoConfigUrl);
GlobalFree(net.lpszProxyBypass);
return "No Proxy";
}
else {
GlobalFree(net.lpszAutoConfigUrl);
GlobalFree(net.lpszProxyBypass);
return Utf8FromUtf16(net.lpszProxy);
}
}
static std::string getPicturePath() {
PWSTR picturesPath;
HRESULT result = SHGetKnownFolderPath(FOLDERID_Pictures, 0, NULL, &picturesPath);
if (SUCCEEDED(result)) {
auto res = Utf8FromUtf16(picturesPath);
CoTaskMemFree(picturesPath);
return res;
}
else {
return "error";
}
}
FlutterWindow::FlutterWindow(const flutter::DartProject& project)
: project_(project) {}
@@ -31,15 +63,13 @@ bool FlutterWindow::OnCreate() {
}
RegisterPlugins(flutter_controller_->engine());
//监听鼠标侧键的EventChannel
const auto channelName = "pixes/mouse";
flutter::EventChannel<> channel2(
const auto channelName = "pixes/mouse";
flutter::EventChannel<> channel2(
flutter_controller_->engine()->messenger(), channelName,
&flutter::StandardMethodCodec::GetInstance()
);
auto eventHandler = std::make_unique<
flutter::StreamHandlerFunctions<flutter::EncodableValue>>(
);
auto eventHandler = std::make_unique<
flutter::StreamHandlerFunctions<flutter::EncodableValue>>(
[](
const flutter::EncodableValue* arguments,
std::unique_ptr<flutter::EventSink<flutter::EncodableValue>>&& events){
@@ -50,9 +80,27 @@ bool FlutterWindow::OnCreate() {
-> std::unique_ptr<flutter::StreamHandlerError<flutter::EncodableValue>> {
mouseEvents = nullptr;
return nullptr;
});
});
channel2.SetStreamHandler(std::move(eventHandler));
channel2.SetStreamHandler(std::move(eventHandler));
const auto pictureFolderChannel = "pixes/picture_folder";
flutter::MethodChannel<> channel3(
flutter_controller_->engine()->messenger(), pictureFolderChannel,
&flutter::StandardMethodCodec::GetInstance()
);
channel3.SetMethodCallHandler([](
const flutter::MethodCall<>& call, const std::unique_ptr<flutter::MethodResult<>>& result) {
result->Success(getPicturePath());
});
const flutter::MethodChannel<> channel(
flutter_controller_->engine()->messenger(), "pixes/proxy",
&flutter::StandardMethodCodec::GetInstance()
);
channel.SetMethodCallHandler(
[](const flutter::MethodCall<>& call, const std::unique_ptr<flutter::MethodResult<>>& result) {
result->Success(getProxy());
});
SetChildContent(flutter_controller_->view()->GetNativeWindow());
@@ -114,4 +162,4 @@ FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
}
return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
}
}