plugin_framework, debug config, mid commit

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou
2023-04-24 18:45:22 +08:00
parent 8340573277
commit d8dc56a743
15 changed files with 623 additions and 276 deletions

View File

@@ -3,8 +3,7 @@ import 'dart:convert';
typedef PluginId = String;
// ui location
const String kLocationHostMainDisplayOthers =
'host|main|settings|display|others';
const String kLocationHostMainPlugin = 'host|main|settings|plugin';
const String kLocationClientRemoteToolbarDisplay =
'client|remote|toolbar|display';

View File

@@ -2,6 +2,8 @@ import 'dart:convert';
import 'dart:collection';
import 'package:flutter/foundation.dart';
import './common.dart';
const String kValueTrue = '1';
const String kValueFalse = '0';
@@ -59,7 +61,7 @@ class UiCheckbox extends UiType {
class Location {
// location key:
// host|main|settings|display|others
// host|main|settings|plugin
// client|remote|toolbar|display
HashMap<String, UiType> ui;
@@ -76,14 +78,12 @@ class Location {
class ConfigItem {
String key;
String value;
String description;
String defaultValue;
ConfigItem(this.key, this.value, this.defaultValue, this.description);
ConfigItem(this.key, this.defaultValue, this.description);
ConfigItem.fromJson(Map<String, dynamic> json)
: key = json['key'] ?? '',
value = json['value'] ?? '',
description = json['description'] ?? '',
defaultValue = json['default'] ?? '';
@@ -151,7 +151,7 @@ class Desc {
}
class DescModel with ChangeNotifier {
final data = <String, Desc>{};
final data = <PluginId, Desc>{};
DescModel._();
@@ -169,7 +169,7 @@ class DescModel with ChangeNotifier {
return data[id];
}
Map<String, Desc> get all => data;
Map<PluginId, Desc> get all => data;
static final DescModel _instance = DescModel._();
static DescModel get instance => _instance;

View File

@@ -55,16 +55,17 @@ class LocationModel with ChangeNotifier {
}
void addLocationUi(String location, PluginId id, UiType ui) {
_locationModels[location]?.add(id, ui);
}
LocationModel addLocation(String location) {
if (_locationModels[location] == null) {
_locationModels[location] = LocationModel();
}
return _locationModels[location]!;
_locationModels[location]?.add(id, ui);
}
LocationModel? getLocationModel(String location) => _locationModels[location];
PluginModel? getPluginModel(String location, PluginId id) =>
_locationModels[location]?.pluginModels[id];
void clearPlugin(PluginId pluginId) {
for (var element in _locationModels.values) {
element.pluginModels.remove(pluginId);
@@ -77,7 +78,7 @@ void clearLocations() {
}
}
OptionModel addOptionModel(
OptionModel getOptionModel(
String location, PluginId pluginId, String peer, String key) {
final k = OptionModel.key(location, pluginId, peer, key);
if (_optionModels[k] == null) {

View File

@@ -2,8 +2,10 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/models/model.dart';
import 'package:provider/provider.dart';
import 'package:get/get.dart';
// to-do: do not depend on desktop
import 'package:flutter_hbb/desktop/widgets/remote_toolbar.dart';
import 'package:flutter_hbb/models/platform_model.dart';
@@ -12,11 +14,15 @@ import './desc.dart';
import './model.dart';
import './common.dart';
// dup to flutter\lib\desktop\pages\desktop_setting_page.dart
const double _kCheckBoxLeftMargin = 10;
class LocationItem extends StatelessWidget {
final String peerId;
final FFI ffi;
final String location;
final LocationModel locationModel;
final bool isMenu;
LocationItem({
Key? key,
@@ -24,19 +30,23 @@ class LocationItem extends StatelessWidget {
required this.ffi,
required this.location,
required this.locationModel,
required this.isMenu,
}) : super(key: key);
bool get isEmpty => locationModel.isEmpty;
static LocationItem createLocationItem(
String peerId, FFI ffi, String location) {
final model = addLocation(location);
return LocationItem(
peerId: peerId,
ffi: ffi,
location: location,
locationModel: model,
);
static Widget createLocationItem(
String peerId, FFI ffi, String location, bool isMenu) {
final model = getLocationModel(location);
return model == null
? Container()
: LocationItem(
peerId: peerId,
ffi: ffi,
location: location,
locationModel: model,
isMenu: isMenu,
);
}
@override
@@ -59,23 +69,26 @@ class LocationItem extends StatelessWidget {
ffi: ffi,
location: location,
pluginModel: model,
isMenu: isMenu,
);
}
class PluginItem extends StatelessWidget {
final PluginId pluginId;
final String peerId;
final FFI ffi;
final FFI? ffi;
final String location;
final PluginModel pluginModel;
final isMenu;
PluginItem({
Key? key,
required this.pluginId,
required this.peerId,
required this.ffi,
this.ffi,
required this.location,
required this.pluginModel,
required this.isMenu,
}) : super(key: key);
bool get isEmpty => pluginModel.isEmpty;
@@ -95,74 +108,88 @@ class PluginItem extends StatelessWidget {
}
Widget _buildItem(UiType ui) {
late Widget child;
Widget? child;
switch (ui.runtimeType) {
case UiButton:
child = _buildMenuButton(ui as UiButton);
if (isMenu) {
if (ffi != null) {
child = _buildMenuButton(ui as UiButton, ffi!);
}
} else {
child = _buildButton(ui as UiButton);
}
break;
case UiCheckbox:
child = _buildCheckboxMenuButton(ui as UiCheckbox);
if (isMenu) {
if (ffi != null) {
child = _buildCheckboxMenuButton(ui as UiCheckbox, ffi!);
}
} else {
child = _buildCheckbox(ui as UiCheckbox);
}
break;
default:
child = Container();
break;
}
// to-do: add plugin icon and tooltip
return child;
return child ?? Container();
}
Uint8List _makeEvent(
String key, {
bool? v,
}) {
final event = MsgFromUi(
id: pluginId,
name: getDesc(pluginId)?.name ?? '',
location: location,
key: key,
value:
v != null ? (v ? ConfigItem.trueValue : ConfigItem.falseValue) : '',
action: '',
);
return Uint8List.fromList(event.toString().codeUnits);
}
Widget _buildMenuButton(UiButton ui) {
return MenuButton(
Widget _buildButton(UiButton ui) {
return TextButton(
onPressed: () => bind.pluginEvent(
id: pluginId,
peer: peerId,
event: _makeEvent(ui.key),
),
// to-do: support trailing icon, but it will cause tree shake error.
// ```
// This application cannot tree shake icons fonts. It has non-constant instances of IconData at the following locations:
// Target release_macos_bundle_flutter_assets failed: Exception: Avoid non-constant invocations of IconData or try to build again with --no-tree-shake-icons.
// ```
//
// trailingIcon: Icon(
// IconData(int.parse(ui.icon, radix: 16), fontFamily: 'MaterialIcons')),
//
// to-do: RustDesk translate or plugin translate ?
child: Text(ui.text),
ffi: ffi,
);
}
String? getOption(OptionModel model, String key) {
var v = model.value;
if (v == null) {
if (peerId.isEmpty) {
v = bind.pluginGetSharedOption(id: pluginId, key: key);
} else {
v = bind.pluginGetSessionOption(id: pluginId, peer: peerId, key: key);
Widget _buildCheckbox(UiCheckbox ui) {
getChild(OptionModel model) {
final v = _getOption(model, ui.key);
if (v == null) {
// session or plugin not found
return Container();
}
onChanged(bool value) {
bind.pluginEvent(
id: pluginId,
peer: peerId,
event: _makeEvent(ui.key, v: value),
);
}
final value = ConfigItem.isTrue(v);
return GestureDetector(
child: Row(
children: [
Checkbox(
value: value,
onChanged: (_) => onChanged(!value),
).marginOnly(right: 5),
Expanded(
child: Text(translate(ui.text)),
)
],
).marginOnly(left: _kCheckBoxLeftMargin),
onTap: () => onChanged(!value),
);
}
return v;
return ChangeNotifierProvider.value(
value: getOptionModel(location, pluginId, peerId, ui.key),
child: Consumer<OptionModel>(
builder: (context, model, child) => getChild(model),
),
);
}
Widget _buildCheckboxMenuButton(UiCheckbox ui) {
Widget _buildCheckboxMenuButton(UiCheckbox ui, FFI ffi) {
getChild(OptionModel model) {
final v = getOption(model, ui.key);
final v = _getOption(model, ui.key);
if (v == null) {
// session or plugin not found
return Container();
@@ -184,16 +211,63 @@ class PluginItem extends StatelessWidget {
);
}
final optionModel = addOptionModel(location, pluginId, peerId, ui.key);
return ChangeNotifierProvider.value(
value: optionModel,
value: getOptionModel(location, pluginId, peerId, ui.key),
child: Consumer<OptionModel>(
builder: (context, model, child) {
return getChild(model);
},
builder: (context, model, child) => getChild(model),
),
);
}
Widget _buildMenuButton(UiButton ui, FFI ffi) {
return MenuButton(
onPressed: () => bind.pluginEvent(
id: pluginId,
peer: peerId,
event: _makeEvent(ui.key),
),
// to-do: support trailing icon, but it will cause tree shake error.
// ```
// This application cannot tree shake icons fonts. It has non-constant instances of IconData at the following locations:
// Target release_macos_bundle_flutter_assets failed: Exception: Avoid non-constant invocations of IconData or try to build again with --no-tree-shake-icons.
// ```
//
// trailingIcon: Icon(
// IconData(int.parse(ui.icon, radix: 16), fontFamily: 'MaterialIcons')),
//
// to-do: RustDesk translate or plugin translate ?
child: Text(ui.text),
ffi: ffi,
);
}
Uint8List _makeEvent(
String key, {
bool? v,
}) {
final event = MsgFromUi(
id: pluginId,
name: getDesc(pluginId)?.name ?? '',
location: location,
key: key,
value:
v != null ? (v ? ConfigItem.trueValue : ConfigItem.falseValue) : '',
action: '',
);
return Uint8List.fromList(event.toString().codeUnits);
}
String? _getOption(OptionModel model, String key) {
var v = model.value;
if (v == null) {
if (peerId.isEmpty) {
v = bind.pluginGetSharedOption(id: pluginId, key: key);
} else {
v = bind.pluginGetSessionOption(id: pluginId, peer: peerId, key: key);
}
}
return v;
}
}
void handleReloading(Map<String, dynamic> evt, String peer) {