mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 08:46:18 +01:00
Refactor: extract native event to package
This commit is contained in:
parent
8841673b88
commit
e91d6410f5
24 changed files with 304 additions and 85 deletions
|
@ -3,7 +3,7 @@ import 'dart:convert';
|
|||
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/stream_extension.dart';
|
||||
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
|
||||
import 'package:np_platform_message_relay/np_platform_message_relay.dart';
|
||||
|
||||
class NativeEventListener<T> {
|
||||
NativeEventListener(this.listener);
|
||||
|
@ -26,7 +26,7 @@ class NativeEventListener<T> {
|
|||
}
|
||||
|
||||
static final _mappedStream =
|
||||
NativeEvent.stream.whereType<NativeEventObject>().map((ev) {
|
||||
MessageRelay.stream.whereType<Message>().map((ev) {
|
||||
switch (ev.event) {
|
||||
case FileExifUpdatedEvent._id:
|
||||
return FileExifUpdatedEvent.fromEvent(ev);
|
||||
|
@ -39,20 +39,21 @@ class NativeEventListener<T> {
|
|||
final void Function(T) listener;
|
||||
StreamSubscription<T>? _subscription;
|
||||
|
||||
final _log = Logger("event.native_event.NativeEventListener<${T.runtimeType}>");
|
||||
final _log =
|
||||
Logger("event.native_event.NativeEventListener<${T.runtimeType}>");
|
||||
}
|
||||
|
||||
class FileExifUpdatedEvent {
|
||||
const FileExifUpdatedEvent(this.fileIds);
|
||||
|
||||
factory FileExifUpdatedEvent.fromEvent(NativeEventObject ev) {
|
||||
factory FileExifUpdatedEvent.fromEvent(Message ev) {
|
||||
assert(ev.event == _id);
|
||||
assert(ev.data != null);
|
||||
final dataJson = jsonDecode(ev.data!) as Map;
|
||||
return FileExifUpdatedEvent((dataJson["fileIds"] as List).cast<int>());
|
||||
}
|
||||
|
||||
NativeEventObject toEvent() => NativeEventObject(
|
||||
Message toEvent() => Message(
|
||||
_id,
|
||||
jsonEncode({
|
||||
"fileIds": fileIds,
|
||||
|
|
|
@ -24,6 +24,7 @@ import 'package:nc_photos_plugin/nc_photos_plugin.dart';
|
|||
import 'package:np_async/np_async.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_geocoder/np_geocoder.dart';
|
||||
import 'package:np_platform_message_relay/np_platform_message_relay.dart';
|
||||
|
||||
part 'service.g.dart';
|
||||
|
||||
|
@ -237,7 +238,7 @@ class _MetadataTask {
|
|||
}
|
||||
if (_processedIds.isNotEmpty) {
|
||||
unawaited(
|
||||
NativeEvent.fire(FileExifUpdatedEvent(_processedIds).toEvent()),
|
||||
MessageRelay.broadcast(FileExifUpdatedEvent(_processedIds).toEvent()),
|
||||
);
|
||||
_processedIds = [];
|
||||
}
|
||||
|
@ -319,7 +320,7 @@ class _MetadataTask {
|
|||
|
||||
_processedIds.add(file.fileId!);
|
||||
if (_processedIds.length >= 10) {
|
||||
NativeEvent.fire(FileExifUpdatedEvent(_processedIds).toEvent());
|
||||
MessageRelay.broadcast(FileExifUpdatedEvent(_processedIds).toEvent());
|
||||
_processedIds = [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1032,6 +1032,13 @@ packages:
|
|||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
np_platform_message_relay:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "../np_platform_message_relay"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
np_platform_permission:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
@ -115,6 +115,8 @@ dependencies:
|
|||
path: ../np_platform_lock
|
||||
np_platform_log:
|
||||
path: ../np_platform_log
|
||||
np_platform_message_relay:
|
||||
path: ../np_platform_message_relay
|
||||
np_platform_permission:
|
||||
path: ../np_platform_permission
|
||||
np_platform_raw_image:
|
||||
|
|
30
np_platform_message_relay/.gitignore
vendored
Normal file
30
np_platform_message_relay/.gitignore
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
/pubspec.lock
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.packages
|
||||
build/
|
30
np_platform_message_relay/.metadata
Normal file
30
np_platform_message_relay/.metadata
Normal file
|
@ -0,0 +1,30 @@
|
|||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled.
|
||||
|
||||
version:
|
||||
revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
channel: stable
|
||||
|
||||
project_type: plugin
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
- platform: android
|
||||
create_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
base_revision: 4d9e56e694b656610ab87fcf2efbcd226e0ed8cf
|
||||
|
||||
# User provided section
|
||||
|
||||
# List of Local paths (relative to this file) that should be
|
||||
# ignored by the migrate tool.
|
||||
#
|
||||
# Files that are not part of the templates will be ignored by default.
|
||||
unmanaged_files:
|
||||
- 'lib/main.dart'
|
||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
1
np_platform_message_relay/analysis_options.yaml
Normal file
1
np_platform_message_relay/analysis_options.yaml
Normal file
|
@ -0,0 +1 @@
|
|||
include: package:np_lints/np.yaml
|
9
np_platform_message_relay/android/.gitignore
vendored
Normal file
9
np_platform_message_relay/android/.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.cxx
|
52
np_platform_message_relay/android/build.gradle
Normal file
52
np_platform_message_relay/android/build.gradle
Normal file
|
@ -0,0 +1,52 @@
|
|||
group 'com.nkming.nc_photos.np_platform_message_relay'
|
||||
version '1.0-SNAPSHOT'
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.8.20'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
namespace 'com.nkming.nc_photos.np_platform_message_relay'
|
||||
compileSdk 31
|
||||
|
||||
defaultConfig {
|
||||
minSdk 21
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "androidx.annotation:annotation:1.6.0"
|
||||
}
|
5
np_platform_message_relay/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
np_platform_message_relay/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
1
np_platform_message_relay/android/settings.gradle
Normal file
1
np_platform_message_relay/android/settings.gradle
Normal file
|
@ -0,0 +1 @@
|
|||
rootProject.name = 'np_platform_message_relay'
|
|
@ -0,0 +1,3 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.nkming.nc_photos.np_platform_message_relay">
|
||||
</manifest>
|
|
@ -0,0 +1,7 @@
|
|||
package com.nkming.nc_photos.np_platform_message_relay
|
||||
|
||||
internal interface K {
|
||||
companion object {
|
||||
const val LIB_ID = "com.nkming.nc_photos.np_platform_message_relay"
|
||||
}
|
||||
}
|
|
@ -1,28 +1,14 @@
|
|||
package com.nkming.nc_photos.plugin
|
||||
package com.nkming.nc_photos.np_platform_message_relay
|
||||
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
||||
internal class NativeEventChannelHandler : MethodChannel.MethodCallHandler,
|
||||
internal class MessageRelayChannelHandler : MethodChannel.MethodCallHandler,
|
||||
EventChannel.StreamHandler {
|
||||
companion object {
|
||||
const val EVENT_CHANNEL = "${K.LIB_ID}/native_event"
|
||||
const val METHOD_CHANNEL = "${K.LIB_ID}/native_event_method"
|
||||
|
||||
/**
|
||||
* Fire native events on the native side
|
||||
*/
|
||||
fun fire(eventObj: NativeEvent) {
|
||||
synchronized(eventSinks) {
|
||||
for (s in eventSinks.values) {
|
||||
s.success(buildMap {
|
||||
put("event", eventObj.getId())
|
||||
eventObj.getData()?.also { put("data", it) }
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
const val EVENT_CHANNEL = "${K.LIB_ID}/message_relay_event"
|
||||
const val METHOD_CHANNEL = "${K.LIB_ID}/message_relay_method"
|
||||
|
||||
private val eventSinks = mutableMapOf<Int, EventChannel.EventSink>()
|
||||
private var nextId = 0
|
||||
|
@ -30,9 +16,9 @@ internal class NativeEventChannelHandler : MethodChannel.MethodCallHandler,
|
|||
|
||||
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
|
||||
when (call.method) {
|
||||
"fire" -> {
|
||||
"broadcast" -> {
|
||||
try {
|
||||
fire(
|
||||
broadcast(
|
||||
call.argument("event")!!, call.argument("data"), result
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
|
@ -54,7 +40,7 @@ internal class NativeEventChannelHandler : MethodChannel.MethodCallHandler,
|
|||
}
|
||||
}
|
||||
|
||||
private fun fire(
|
||||
private fun broadcast(
|
||||
event: String, data: String?, result: MethodChannel.Result
|
||||
) {
|
||||
synchronized(eventSinks) {
|
|
@ -0,0 +1,34 @@
|
|||
package com.nkming.nc_photos.np_platform_message_relay
|
||||
|
||||
import androidx.annotation.NonNull
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
||||
class NpPlatformMessageRelayPlugin : FlutterPlugin {
|
||||
override fun onAttachedToEngine(
|
||||
@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding
|
||||
) {
|
||||
val messageRelayHandler = MessageRelayChannelHandler()
|
||||
eventChannel = EventChannel(
|
||||
flutterPluginBinding.binaryMessenger,
|
||||
MessageRelayChannelHandler.EVENT_CHANNEL
|
||||
)
|
||||
eventChannel.setStreamHandler(messageRelayHandler)
|
||||
methodChannel = MethodChannel(
|
||||
flutterPluginBinding.binaryMessenger,
|
||||
MessageRelayChannelHandler.METHOD_CHANNEL
|
||||
)
|
||||
methodChannel.setMethodCallHandler(messageRelayHandler)
|
||||
}
|
||||
|
||||
override fun onDetachedFromEngine(
|
||||
@NonNull binding: FlutterPlugin.FlutterPluginBinding
|
||||
) {
|
||||
eventChannel.setStreamHandler(null)
|
||||
methodChannel.setMethodCallHandler(null)
|
||||
}
|
||||
|
||||
private lateinit var eventChannel: EventChannel
|
||||
private lateinit var methodChannel: MethodChannel
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
library np_platform_message_relay;
|
||||
|
||||
export 'src/message_relay.dart';
|
1
np_platform_message_relay/lib/src/k.dart
Normal file
1
np_platform_message_relay/lib/src/k.dart
Normal file
|
@ -0,0 +1 @@
|
|||
const libId = "com.nkming.nc_photos.np_platform_message_relay";
|
59
np_platform_message_relay/lib/src/message_relay.dart
Normal file
59
np_platform_message_relay/lib/src/message_relay.dart
Normal file
|
@ -0,0 +1,59 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_platform_message_relay/src/k.dart' as k;
|
||||
|
||||
part 'message_relay.g.dart';
|
||||
|
||||
class Message {
|
||||
const Message(this.event, this.data);
|
||||
|
||||
static Message fromJson(Map<String, dynamic> json) {
|
||||
return Message(json["event"], json["data"]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"event": event,
|
||||
if (data != null) "data": data,
|
||||
};
|
||||
|
||||
final String event;
|
||||
final String? data;
|
||||
}
|
||||
|
||||
/// Relay messages via native side
|
||||
///
|
||||
/// Typically used to broadcast messages across different Flutter engines (e.g.,
|
||||
/// main isolate <-> background isolates)
|
||||
///
|
||||
/// Beware that the isolate that broadcasted the message will also receive the
|
||||
/// message if subscribed
|
||||
@npLog
|
||||
class MessageRelay {
|
||||
static Future<void> broadcast(Message msg) =>
|
||||
_methodChannel.invokeMethod("broadcast", msg.toJson());
|
||||
|
||||
static Stream<Message> get stream =>
|
||||
_eventChannel.receiveBroadcastStream().map(_toEvent).whereNotNull();
|
||||
|
||||
static Message? _toEvent(dynamic ev) {
|
||||
try {
|
||||
return Message.fromJson((ev as Map).cast<String, dynamic>());
|
||||
} catch (e, stackTrace) {
|
||||
_log.severe("Failed while parsing native events", e, stackTrace);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static const _eventChannel = EventChannel("${k.libId}/message_relay_event");
|
||||
static const _methodChannel =
|
||||
MethodChannel("${k.libId}/message_relay_method");
|
||||
|
||||
static final _log = _$MessageRelayNpLog.log;
|
||||
}
|
||||
|
||||
extension<T> on Stream<T?> {
|
||||
Stream<T> whereNotNull() => where((e) => e != null).cast<T>();
|
||||
}
|
14
np_platform_message_relay/lib/src/message_relay.g.dart
Normal file
14
np_platform_message_relay/lib/src/message_relay.g.dart
Normal file
|
@ -0,0 +1,14 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'message_relay.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// NpLogGenerator
|
||||
// **************************************************************************
|
||||
|
||||
extension _$MessageRelayNpLog on MessageRelay {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log = Logger("src.message_relay.MessageRelay");
|
||||
}
|
30
np_platform_message_relay/pubspec.yaml
Normal file
30
np_platform_message_relay/pubspec.yaml
Normal file
|
@ -0,0 +1,30 @@
|
|||
name: np_platform_message_relay
|
||||
description: A new Flutter plugin project.
|
||||
version: 0.0.1
|
||||
homepage:
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: '>=2.19.6 <3.0.0'
|
||||
flutter: ">=3.3.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
logging: ^1.1.1
|
||||
np_codegen:
|
||||
path: ../codegen
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.2.1
|
||||
np_codegen_build:
|
||||
path: ../codegen_build
|
||||
np_lints:
|
||||
path: ../np_lints
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
platforms:
|
||||
android:
|
||||
package: com.nkming.nc_photos.np_platform_message_relay
|
||||
pluginClass: NpPlatformMessageRelayPlugin
|
|
@ -1,6 +0,0 @@
|
|||
package com.nkming.nc_photos.plugin
|
||||
|
||||
internal interface NativeEvent {
|
||||
fun getId(): String
|
||||
fun getData(): String? = null
|
||||
}
|
|
@ -60,18 +60,6 @@ class NcPhotosPlugin : FlutterPlugin, ActivityAware,
|
|||
PreferenceChannelHandler.METHOD_CHANNEL
|
||||
)
|
||||
preferenceMethodChannel.setMethodCallHandler(preferenceChannelHandler)
|
||||
|
||||
val nativeEventHandler = NativeEventChannelHandler()
|
||||
nativeEventChannel = EventChannel(
|
||||
flutterPluginBinding.binaryMessenger,
|
||||
NativeEventChannelHandler.EVENT_CHANNEL
|
||||
)
|
||||
nativeEventChannel.setStreamHandler(nativeEventHandler)
|
||||
nativeEventMethodChannel = MethodChannel(
|
||||
flutterPluginBinding.binaryMessenger,
|
||||
NativeEventChannelHandler.METHOD_CHANNEL
|
||||
)
|
||||
nativeEventMethodChannel.setMethodCallHandler(nativeEventHandler)
|
||||
}
|
||||
|
||||
override fun onDetachedFromEngine(
|
||||
|
@ -82,8 +70,6 @@ class NcPhotosPlugin : FlutterPlugin, ActivityAware,
|
|||
mediaStoreMethodChannel.setMethodCallHandler(null)
|
||||
contentUriMethodChannel.setMethodCallHandler(null)
|
||||
preferenceMethodChannel.setMethodCallHandler(null)
|
||||
nativeEventChannel.setStreamHandler(null)
|
||||
nativeEventMethodChannel.setMethodCallHandler(null)
|
||||
}
|
||||
|
||||
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
|
||||
|
@ -136,8 +122,6 @@ class NcPhotosPlugin : FlutterPlugin, ActivityAware,
|
|||
private lateinit var mediaStoreMethodChannel: MethodChannel
|
||||
private lateinit var contentUriMethodChannel: MethodChannel
|
||||
private lateinit var preferenceMethodChannel: MethodChannel
|
||||
private lateinit var nativeEventChannel: EventChannel
|
||||
private lateinit var nativeEventMethodChannel: MethodChannel
|
||||
|
||||
private lateinit var mediaStoreChannelHandler: MediaStoreChannelHandler
|
||||
}
|
||||
|
|
|
@ -3,6 +3,5 @@ library nc_photos_plugin;
|
|||
export 'src/content_uri.dart';
|
||||
export 'src/exception.dart';
|
||||
export 'src/media_store.dart';
|
||||
export 'src/native_event.dart';
|
||||
export 'src/notification.dart';
|
||||
export 'src/preference.dart';
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:nc_photos_plugin/src/k.dart' as k;
|
||||
|
||||
class NativeEventObject {
|
||||
NativeEventObject(this.event, this.data);
|
||||
|
||||
final String event;
|
||||
final String? data;
|
||||
}
|
||||
|
||||
class NativeEvent {
|
||||
static Future<void> fire(NativeEventObject ev) =>
|
||||
_methodChannel.invokeMethod("fire", <String, dynamic>{
|
||||
"event": ev.event,
|
||||
if (ev.data != null) "data": ev.data,
|
||||
});
|
||||
|
||||
static Stream get stream => _eventStream;
|
||||
|
||||
static const _eventChannel = EventChannel("${k.libId}/native_event");
|
||||
static const _methodChannel = MethodChannel("${k.libId}/native_event_method");
|
||||
|
||||
static final _eventStream = _eventChannel
|
||||
.receiveBroadcastStream()
|
||||
.map((event) {
|
||||
if (event is Map) {
|
||||
return NativeEventObject(event["event"], event["data"]);
|
||||
} else {
|
||||
return event;
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue