diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 662f7cbd2..466b4b74a 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -4,3 +4,6 @@ const String kAppTypeDesktopRemote = "remote"; const String kAppTypeDesktopFileTransfer = "file transfer"; const String kTabLabelHomePage = "Home"; const String kTabLabelSettingPage = "Settings"; + +const int kDefaultDisplayWidth = 1280; +const int kDefaultDisplayHeight = 720; diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index d81adb3d9..ceeb96049 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -41,6 +41,7 @@ class _RemotePageState extends State String _value = ''; double _scale = 1; double _mouseScrollIntegral = 0; // mouse scroll speed controller + var _cursorOverImage = false.obs; var _more = true; var _fn = false; @@ -256,7 +257,8 @@ class _RemotePageState extends State } }); }), - bottomNavigationBar: _showBar && hasDisplays ? getBottomAppBar() : null, + bottomNavigationBar: + _showBar && hasDisplays ? getBottomAppBar(ffiModel) : null, body: Overlay( initialEntries: [ OverlayEntry(builder: (context) { @@ -274,7 +276,6 @@ class _RemotePageState extends State @override Widget build(BuildContext context) { super.build(context); - _ffi.canvasModel.tabBarHeight = super.widget.tabBarHeight; return WillPopScope( onWillPop: () async { clientClose(_ffi.dialogManager); @@ -292,201 +293,148 @@ class _RemotePageState extends State } Widget getRawPointerAndKeyBody(Widget child) { - return Listener( - onPointerHover: (e) { - if (e.kind != ui.PointerDeviceKind.mouse) return; - if (!_isPhysicalMouse) { - setState(() { - _isPhysicalMouse = true; - }); - } - if (_isPhysicalMouse) { - _ffi.handleMouse(getEvent(e, 'mousemove'), - tabBarHeight: super.widget.tabBarHeight); - } - }, - onPointerDown: (e) { - if (e.kind != ui.PointerDeviceKind.mouse) { - if (_isPhysicalMouse) { - setState(() { - _isPhysicalMouse = false; - }); - } - } - if (_isPhysicalMouse) { - _ffi.handleMouse(getEvent(e, 'mousedown'), - tabBarHeight: super.widget.tabBarHeight); - } - }, - onPointerUp: (e) { - if (e.kind != ui.PointerDeviceKind.mouse) return; - if (_isPhysicalMouse) { - _ffi.handleMouse(getEvent(e, 'mouseup'), - tabBarHeight: super.widget.tabBarHeight); - } - }, - onPointerMove: (e) { - if (e.kind != ui.PointerDeviceKind.mouse) return; - if (_isPhysicalMouse) { - _ffi.handleMouse(getEvent(e, 'mousemove'), - tabBarHeight: super.widget.tabBarHeight); - } - }, - onPointerSignal: (e) { - if (e is PointerScrollEvent) { - var dx = e.scrollDelta.dx; - var dy = e.scrollDelta.dy; - if (dx > 0) - dx = -1; - else if (dx < 0) dx = 1; - if (dy > 0) - dy = -1; - else if (dy < 0) dy = 1; - bind.sessionSendMouse( - id: widget.id, - msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}'); - } - }, - child: Consumer( - builder: (context, FfiModel, _child) => MouseRegion( - cursor: FfiModel.permissions['keyboard'] != false - ? SystemMouseCursors.none - : MouseCursor.defer, - child: FocusScope( + return Consumer( + builder: (context, FfiModel, _child) => MouseRegion( + cursor: FfiModel.permissions['keyboard'] != false + ? SystemMouseCursors.none + : MouseCursor.defer, + child: FocusScope( + autofocus: true, + child: Focus( autofocus: true, - child: Focus( - autofocus: true, - canRequestFocus: true, - focusNode: _physicalFocusNode, - onKey: (data, e) { - final key = e.logicalKey; - if (e is RawKeyDownEvent) { - if (e.repeat) { - sendRawKey(e, press: true); - } else { - if (e.isAltPressed && !_ffi.alt) { - _ffi.alt = true; - } else if (e.isControlPressed && !_ffi.ctrl) { - _ffi.ctrl = true; - } else if (e.isShiftPressed && !_ffi.shift) { - _ffi.shift = true; - } else if (e.isMetaPressed && !_ffi.command) { - _ffi.command = true; - } - sendRawKey(e, down: true); - } + canRequestFocus: true, + focusNode: _physicalFocusNode, + onKey: (data, e) { + final key = e.logicalKey; + if (e is RawKeyDownEvent) { + if (e.repeat) { + sendRawKey(e, press: true); + } else { + if (e.isAltPressed && !_ffi.alt) { + _ffi.alt = true; + } else if (e.isControlPressed && !_ffi.ctrl) { + _ffi.ctrl = true; + } else if (e.isShiftPressed && !_ffi.shift) { + _ffi.shift = true; + } else if (e.isMetaPressed && !_ffi.command) { + _ffi.command = true; } - // [!_showEdit] workaround for soft-keyboard's control_key like Backspace / Enter - if (!_showEdit && e is RawKeyUpEvent) { - if (key == LogicalKeyboardKey.altLeft || - key == LogicalKeyboardKey.altRight) { - _ffi.alt = false; - } else if (key == LogicalKeyboardKey.controlLeft || - key == LogicalKeyboardKey.controlRight) { - _ffi.ctrl = false; - } else if (key == LogicalKeyboardKey.shiftRight || - key == LogicalKeyboardKey.shiftLeft) { - _ffi.shift = false; - } else if (key == LogicalKeyboardKey.metaLeft || - key == LogicalKeyboardKey.metaRight) { - _ffi.command = false; - } - sendRawKey(e); - } - return KeyEventResult.handled; - }, - child: child))))); + sendRawKey(e, down: true); + } + } + // [!_showEdit] workaround for soft-keyboard's control_key like Backspace / Enter + if (!_showEdit && e is RawKeyUpEvent) { + if (key == LogicalKeyboardKey.altLeft || + key == LogicalKeyboardKey.altRight) { + _ffi.alt = false; + } else if (key == LogicalKeyboardKey.controlLeft || + key == LogicalKeyboardKey.controlRight) { + _ffi.ctrl = false; + } else if (key == LogicalKeyboardKey.shiftRight || + key == LogicalKeyboardKey.shiftLeft) { + _ffi.shift = false; + } else if (key == LogicalKeyboardKey.metaLeft || + key == LogicalKeyboardKey.metaRight) { + _ffi.command = false; + } + sendRawKey(e); + } + return KeyEventResult.handled; + }, + child: child)))); } - Widget? getBottomAppBar() { - return BottomAppBar( - elevation: 10, - color: MyTheme.accent, - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - IconButton( - color: Colors.white, - icon: Icon(Icons.clear), - onPressed: () { - clientClose(_ffi.dialogManager); - }, - ) - ] + - [ - IconButton( - color: Colors.white, - icon: Icon(Icons.tv), - onPressed: () { - setState(() => _showEdit = false); - showOptions(widget.id, _ffi.dialogManager); - }, - ) - ] + - (isWebDesktop - ? [] - : _ffi.ffiModel.isPeerAndroid - ? [ + Widget? getBottomAppBar(FfiModel ffiModel) { + return MouseRegion( + cursor: SystemMouseCursors.basic, + child: BottomAppBar( + elevation: 10, + color: MyTheme.accent, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + IconButton( + color: Colors.white, + icon: Icon(Icons.clear), + onPressed: () { + clientClose(_ffi.dialogManager); + }, + ) + ] + + [ + IconButton( + color: Colors.white, + icon: Icon(Icons.tv), + onPressed: () { + setState(() => _showEdit = false); + showOptions(widget.id, _ffi.dialogManager); + }, + ) + ] + + (isWebDesktop + ? [] + : _ffi.ffiModel.isPeerAndroid + ? [ + IconButton( + color: Colors.white, + icon: Icon(Icons.build), + onPressed: () { + if (mobileActionsOverlayEntry == null) { + showMobileActionsOverlay(); + } else { + hideMobileActionsOverlay(); + } + }, + ) + ] + : [ + IconButton( + color: Colors.white, + icon: Icon(Icons.keyboard), + onPressed: openKeyboard), + IconButton( + color: Colors.white, + icon: Icon(_ffi.ffiModel.touchMode + ? Icons.touch_app + : Icons.mouse), + onPressed: changeTouchMode, + ), + ]) + + (isWeb + ? [] + : [ IconButton( color: Colors.white, - icon: Icon(Icons.build), + icon: Icon(Icons.message), onPressed: () { - if (mobileActionsOverlayEntry == null) { - showMobileActionsOverlay(); - } else { - hideMobileActionsOverlay(); - } + _ffi.chatModel + .changeCurrentID(ChatModel.clientModeID); + _ffi.chatModel.toggleChatOverlay(); }, ) - ] - : [ - IconButton( - color: Colors.white, - icon: Icon(Icons.keyboard), - onPressed: openKeyboard), - IconButton( - color: Colors.white, - icon: Icon(_ffi.ffiModel.touchMode - ? Icons.touch_app - : Icons.mouse), - onPressed: changeTouchMode, - ), ]) + - (isWeb - ? [] - : [ - IconButton( - color: Colors.white, - icon: Icon(Icons.message), - onPressed: () { - _ffi.chatModel - .changeCurrentID(ChatModel.clientModeID); - _ffi.chatModel.toggleChatOverlay(); - }, - ) - ]) + - [ - IconButton( - color: Colors.white, - icon: Icon(Icons.more_vert), - onPressed: () { - setState(() => _showEdit = false); - showActions(widget.id); - }, - ), - ]), - IconButton( - color: Colors.white, - icon: Icon(Icons.expand_more), - onPressed: () { - setState(() => _showBar = !_showBar); - }), - ], - ), - ); + [ + IconButton( + color: Colors.white, + icon: Icon(Icons.more_vert), + onPressed: () { + setState(() => _showEdit = false); + showActions(widget.id, ffiModel); + }, + ), + ]), + IconButton( + color: Colors.white, + icon: Icon(Icons.expand_more), + onPressed: () { + setState(() => _showBar = !_showBar); + }), + ], + ), + )); } /// touchMode only: @@ -499,6 +447,81 @@ class _RemotePageState extends State /// DoubleFiner -> right click /// HoldDrag -> left drag + void _onPointHoverImage(PointerHoverEvent e) { + if (e.kind != ui.PointerDeviceKind.mouse) return; + if (!_isPhysicalMouse) { + setState(() { + _isPhysicalMouse = true; + }); + } + if (_isPhysicalMouse) { + _ffi.handleMouse(getEvent(e, 'mousemove'), + tabBarHeight: super.widget.tabBarHeight); + } + } + + void _onPointDownImage(PointerDownEvent e) { + if (e.kind != ui.PointerDeviceKind.mouse) { + if (_isPhysicalMouse) { + setState(() { + _isPhysicalMouse = false; + }); + } + } + if (_isPhysicalMouse) { + _ffi.handleMouse(getEvent(e, 'mousedown'), + tabBarHeight: super.widget.tabBarHeight); + } + } + + void _onPointUpImage(PointerUpEvent e) { + if (e.kind != ui.PointerDeviceKind.mouse) return; + if (_isPhysicalMouse) { + _ffi.handleMouse(getEvent(e, 'mouseup'), + tabBarHeight: super.widget.tabBarHeight); + } + } + + void _onPointMoveImage(PointerMoveEvent e) { + if (e.kind != ui.PointerDeviceKind.mouse) return; + if (_isPhysicalMouse) { + _ffi.handleMouse(getEvent(e, 'mousemove'), + tabBarHeight: super.widget.tabBarHeight); + } + } + + void _onPointerSignalImage(PointerSignalEvent e) { + if (e is PointerScrollEvent) { + var dx = e.scrollDelta.dx.toInt(); + var dy = e.scrollDelta.dy.toInt(); + if (dx > 0) + dx = -1; + else if (dx < 0) dx = 1; + if (dy > 0) + dy = -1; + else if (dy < 0) dy = 1; + bind.sessionSendMouse( + id: widget.id, msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}'); + } + } + + Widget _buildImageListener(Widget child) { + return Listener( + onPointerHover: _onPointHoverImage, + onPointerDown: _onPointDownImage, + onPointerUp: _onPointUpImage, + onPointerMove: _onPointMoveImage, + onPointerSignal: _onPointerSignalImage, + child: MouseRegion( + onEnter: (evt) { + _cursorOverImage.value = true; + }, + onExit: (evt) { + _cursorOverImage.value = false; + }, + child: child)); + } + Widget getBodyForDesktop(BuildContext context, bool keyboard) { var paints = [ MouseRegion(onEnter: (evt) { @@ -512,6 +535,8 @@ class _RemotePageState extends State }); return ImagePaint( id: widget.id, + cursorOverImage: _cursorOverImage, + listenerBuilder: _buildImageListener, ); }), )) @@ -550,7 +575,7 @@ class _RemotePageState extends State return out; } - void showActions(String id) async { + void showActions(String id, FfiModel ffiModel) async { final size = MediaQuery.of(context).size; final x = 120.0; final y = size.height - super.widget.tabBarHeight; @@ -595,12 +620,8 @@ class _RemotePageState extends State await bind.getSessionToggleOption(id: id, arg: 'privacy-mode') != true) { more.add(PopupMenuItem( - child: Consumer( - builder: (_context, ffiModel, _child) => () { - return Text(translate( - (ffiModel.inputBlocked ? 'Unb' : 'B') + - 'lock user input')); - }()), + child: Text(translate( + (ffiModel.inputBlocked ? 'Unb' : 'B') + 'lock user input')), value: 'block-input')); } } @@ -630,6 +651,9 @@ class _RemotePageState extends State } }(); } else if (value == 'enter_os_password') { + // FIXME: + // null means no session of id + // empty string means no password var password = await bind.getSessionOption(id: id, arg: "os-password"); if (password != null) { bind.sessionInputOsPassword(id: widget.id, value: password); @@ -822,18 +846,95 @@ class _RemotePageState extends State class ImagePaint extends StatelessWidget { final String id; + final Rx cursorOverImage; + final Widget Function(Widget)? listenerBuilder; + final ScrollController _horizontal = ScrollController(); + final ScrollController _vertical = ScrollController(); - const ImagePaint({Key? key, required this.id}) : super(key: key); + ImagePaint( + {Key? key, + required this.id, + required this.cursorOverImage, + this.listenerBuilder = null}) + : super(key: key); @override Widget build(BuildContext context) { final m = Provider.of(context); - final c = Provider.of(context); - var s = c.scale; - return CustomPaint( - painter: - new ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s), - ); + var c = Provider.of(context); + final s = c.scale; + if (c.scrollStyle == ScrollStyle.scrollbar) { + final imageWidget = SizedBox( + width: c.getDisplayWidth() * s, + height: c.getDisplayHeight() * s, + child: CustomPaint( + painter: new ImagePainter(image: m.image, x: 0, y: 0, scale: s), + )); + return Center( + child: NotificationListener( + onNotification: (_notification) { + final percentX = _horizontal.position.extentBefore / + (_horizontal.position.extentBefore + + _horizontal.position.extentInside + + _horizontal.position.extentAfter); + final percentY = _vertical.position.extentBefore / + (_vertical.position.extentBefore + + _vertical.position.extentInside + + _vertical.position.extentAfter); + c.setScrollPercent(percentX, percentY); + return false; + }, + child: Obx(() => MouseRegion( + cursor: cursorOverImage.value + ? SystemMouseCursors.none + : SystemMouseCursors.basic, + child: _buildCrossScrollbar(_buildListener(imageWidget)))), + )); + } else { + final imageWidget = SizedBox( + width: c.size.width, + height: c.size.height, + child: CustomPaint( + painter: new ImagePainter( + image: m.image, x: c.x / s, y: c.y / s, scale: s), + )); + return _buildListener(imageWidget); + } + } + + Widget _buildCrossScrollbar(Widget child) { + final physicsVertical = + cursorOverImage.value ? const NeverScrollableScrollPhysics() : null; + final physicsHorizontal = + cursorOverImage.value ? const NeverScrollableScrollPhysics() : null; + return Scrollbar( + controller: _vertical, + thumbVisibility: true, + trackVisibility: true, + child: Scrollbar( + controller: _horizontal, + thumbVisibility: true, + trackVisibility: true, + notificationPredicate: (notif) => notif.depth == 1, + child: SingleChildScrollView( + controller: _vertical, + physics: physicsVertical, + child: SingleChildScrollView( + controller: _horizontal, + scrollDirection: Axis.horizontal, + physics: physicsHorizontal, + child: child, + ), + ), + )); + } + + Widget _buildListener(Widget child) { + if (listenerBuilder != null) { + return listenerBuilder!(child); + } else { + return child; + } } } @@ -896,6 +997,8 @@ void showOptions(String id, OverlayDialogManager dialogManager) async { if (quality == '') quality = 'balanced'; String viewStyle = await bind.getSessionOption(id: id, arg: 'view-style') ?? ''; + String scrollStyle = + await bind.getSessionOption(id: id, arg: 'scroll-style') ?? ''; var displays = []; final pi = ffi(id).ffiModel.pi; final image = ffi(id).ffiModel.getConnectionImage(); @@ -968,6 +1071,14 @@ void showOptions(String id, OverlayDialogManager dialogManager) async { ffi(id).canvasModel.updateViewStyle(); }); }; + var setScrollStyle = (String? value) { + if (value == null) return; + setState(() { + scrollStyle = value; + bind.sessionPeerOption(id: id, name: "scroll-style", value: value); + ffi(id).canvasModel.updateScrollStyle(); + }); + }; return CustomAlertDialog( title: SizedBox.shrink(), content: Column( @@ -978,6 +1089,10 @@ void showOptions(String id, OverlayDialogManager dialogManager) async { getRadio('Shrink', 'shrink', viewStyle, setViewStyle), getRadio('Stretch', 'stretch', viewStyle, setViewStyle), Divider(color: MyTheme.border), + getRadio( + 'ScrollAuto', 'scrollauto', scrollStyle, setScrollStyle), + getRadio('Scrollbar', 'scrollbar', scrollStyle, setScrollStyle), + Divider(color: MyTheme.border), getRadio('Good image quality', 'best', quality, setQuality), getRadio('Balanced', 'balanced', quality, setQuality), getRadio('Optimize reaction time', 'low', quality, setQuality), diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 14bdfa833..3e826705f 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -735,6 +735,9 @@ class _RemotePageState extends State { } }(); } else if (value == 'enter_os_password') { + // FIXME: + // null means no session of id + // empty string means no password var password = await bind.getSessionOption(id: id, arg: "os-password"); if (password != null) { bind.sessionInputOsPassword(id: widget.id, value: password); diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index a52947c74..c297141de 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -387,8 +387,9 @@ class ImageModel with ChangeNotifier { void update(ui.Image? image, double tabBarHeight) { if (_image == null && image != null) { - if (isWebDesktop) { + if (isWebDesktop || isDesktop) { parent.target?.canvasModel.updateViewStyle(); + parent.target?.canvasModel.updateScrollStyle(); } else { final size = MediaQueryData.fromWindow(ui.window).size; final canvasWidth = size.width; @@ -432,36 +433,52 @@ class ImageModel with ChangeNotifier { } } +enum ScrollStyle { + scrollbar, + scrollauto, +} + class CanvasModel with ChangeNotifier { + // scroll offset x percent + double _scrollX = 0.0; + // scroll offset y percent + double _scrollY = 0.0; double _x = 0; double _y = 0; double _scale = 1.0; double _tabBarHeight = 0.0; String id = ""; // TODO multi canvas model + ScrollStyle _scrollStyle = ScrollStyle.scrollauto; WeakReference parent; CanvasModel(this.parent); double get x => _x; - double get y => _y; - double get scale => _scale; + ScrollStyle get scrollStyle => _scrollStyle; + + setScrollPercent(double x, double y) { + _scrollX = x; + _scrollY = y; + } + + double get scrollX => _scrollX; + double get scrollY => _scrollY; set tabBarHeight(double h) => _tabBarHeight = h; double get tabBarHeight => _tabBarHeight; void updateViewStyle() async { - final s = await bind.getSessionOption(id: id, arg: 'view-style'); - if (s == null) { + final style = await bind.getSessionOption(id: id, arg: 'view-style'); + if (style == null) { return; } - final size = MediaQueryData.fromWindow(ui.window).size; - final canvasWidth = size.width; - final canvasHeight = size.height - _tabBarHeight; - final s1 = canvasWidth / (parent.target?.ffiModel.display.width ?? 720); - final s2 = canvasHeight / (parent.target?.ffiModel.display.height ?? 1280); + + final s1 = size.width / (parent.target?.ffiModel.display.width ?? 720); + final s2 = size.height / (parent.target?.ffiModel.display.height ?? 1280); + // Closure to perform shrink operation. final shrinkOp = () { final s = s1 < s2 ? s1 : s2; @@ -471,7 +488,7 @@ class CanvasModel with ChangeNotifier { }; // Closure to perform stretch operation. final stretchOp = () { - final s = s1 > s2 ? s1 : s2; + final s = s1 < s2 ? s1 : s2; if (s > 1) { _scale = s; } @@ -480,20 +497,34 @@ class CanvasModel with ChangeNotifier { final defaultOp = () { _scale = 1.0; }; - if (s == 'shrink') { + + // // On desktop, shrink is the default behavior. + // if (isDesktop) { + // shrinkOp(); + // } else { + defaultOp(); + // } + + if (style == 'shrink') { shrinkOp(); - } else if (s == 'stretch') { + } else if (style == 'stretch') { stretchOp(); - } else { - // On desktop, shrink is the default behavior. - if (isDesktop) { - shrinkOp(); - } else { - defaultOp(); - } } - _x = (canvasWidth - getDisplayWidth() * _scale) / 2; - _y = (canvasHeight - getDisplayHeight() * _scale) / 2; + + _x = (size.width - getDisplayWidth() * _scale) / 2; + _y = (size.height - getDisplayHeight() * _scale) / 2; + notifyListeners(); + } + + updateScrollStyle() async { + final style = await bind.getSessionOption(id: id, arg: 'scroll-style'); + if (style == 'scrollbar') { + _scrollStyle = ScrollStyle.scrollbar; + _scrollX = 0.0; + _scrollY = 0.0; + } else { + _scrollStyle = ScrollStyle.scrollauto; + } notifyListeners(); } @@ -512,28 +543,30 @@ class CanvasModel with ChangeNotifier { return parent.target?.ffiModel.display.height ?? 720; } + Size get size { + final size = MediaQueryData.fromWindow(ui.window).size; + return Size(size.width, size.height - _tabBarHeight); + } + void moveDesktopMouse(double x, double y) { // On mobile platforms, move the canvas with the cursor. - if (!isDesktop) { - final size = MediaQueryData.fromWindow(ui.window).size; - final canvasWidth = size.width; - final canvasHeight = size.height - _tabBarHeight; - final dw = getDisplayWidth() * _scale; - final dh = getDisplayHeight() * _scale; - var dxOffset = 0; - var dyOffset = 0; - if (dw > canvasWidth) { - dxOffset = (x - dw * (x / canvasWidth) - _x).toInt(); - } - if (dh > canvasHeight) { - dyOffset = (y - dh * (y / canvasHeight) - _y).toInt(); - } - _x += dxOffset; - _y += dyOffset; - if (dxOffset != 0 || dyOffset != 0) { - notifyListeners(); - } + //if (!isDesktop) { + final dw = getDisplayWidth() * _scale; + final dh = getDisplayHeight() * _scale; + var dxOffset = 0; + var dyOffset = 0; + if (dw > size.width) { + dxOffset = (x - dw * (x / size.width) - _x).toInt(); } + if (dh > size.height) { + dyOffset = (y - dh * (y / size.height) - _y).toInt(); + } + _x += dxOffset; + _y += dyOffset; + if (dxOffset != 0 || dyOffset != 0) { + notifyListeners(); + } + //} parent.target?.cursorModel.moveLocal(x, y); } @@ -1091,8 +1124,24 @@ class FFI { canvasModel.moveDesktopMouse(x, y); } final d = ffiModel.display; - x -= canvasModel.x; - y -= canvasModel.y; + if (canvasModel.scrollStyle == ScrollStyle.scrollbar) { + final imageWidth = d.width * canvasModel.scale; + final imageHeight = d.height * canvasModel.scale; + x += imageWidth * canvasModel.scrollX; + y += imageHeight * canvasModel.scrollY; + + // boxed size is a center widget + if (canvasModel.size.width > imageWidth) { + x -= ((canvasModel.size.width - imageWidth) / 2); + } + if (canvasModel.size.height > imageHeight) { + y -= ((canvasModel.size.height - imageHeight) / 2); + } + } else { + x -= canvasModel.x; + y -= canvasModel.y; + } + if (!isMove && (x < 0 || x > d.width || y < 0 || y > d.height)) { return; } diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index e0a7aa8eb..fcefcca82 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -5,238 +5,238 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "44.0.0" + version: "46.0.0" after_layout: dependency: transitive description: name: after_layout - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "4.4.0" + version: "4.6.0" animations: dependency: transitive description: name: animations - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.3" archive: dependency: transitive description: name: archive - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.3.1" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.1" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.8.2" back_button_interceptor: dependency: "direct main" description: name: back_button_interceptor - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.0.1" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" build: dependency: transitive description: name: build - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.0" build_config: dependency: transitive description: name: build_config - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.0" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.9" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "7.2.3" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "8.4.0" cached_network_image: dependency: transitive description: name: cached_network_image - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.2.0" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.16.0" contextmenu: dependency: "direct main" description: name: contextmenu - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.2" cross_file: dependency: transitive description: name: cross_file - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.3+1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.2" csslib: dependency: transitive description: name: csslib - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.17.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.5" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.3" dash_chat_2: dependency: "direct main" description: name: dash_chat_2 - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.0.12" desktop_multi_window: @@ -252,133 +252,133 @@ packages: dependency: "direct main" description: name: device_info_plus - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "4.0.2" + version: "4.1.0" device_info_plus_linux: dependency: transitive description: name: device_info_plus_linux - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" device_info_plus_macos: dependency: transitive description: name: device_info_plus_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.3" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.0" + version: "2.6.0" device_info_plus_web: dependency: transitive description: name: device_info_plus_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" device_info_plus_windows: dependency: transitive description: name: device_info_plus_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.2" + version: "3.0.3" draggable_float_widget: dependency: "direct main" description: name: draggable_float_widget - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.0.2" event_bus: dependency: transitive description: name: event_bus - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" external_path: dependency: "direct main" description: name: external_path - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0" ffi: dependency: "direct main" description: name: ffi - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.1" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.2" firebase_analytics: dependency: "direct main" description: name: firebase_analytics - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "9.3.0" + version: "9.3.1" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.3.0" + version: "3.3.1" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.4.2" + version: "0.4.2+1" firebase_core: dependency: transitive description: name: firebase_core - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.20.0" + version: "1.20.1" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.5.0" firebase_core_web: dependency: transitive description: name: firebase_core_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.7.1" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" flutter: @@ -390,42 +390,42 @@ packages: dependency: transitive description: name: flutter_blurhash - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.7.0" flutter_breadcrumb: dependency: "direct main" description: name: flutter_breadcrumb - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" flutter_cache_manager: dependency: transitive description: name: flutter_cache_manager - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.3.0" flutter_launcher_icons: dependency: "direct dev" description: name: flutter_launcher_icons - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.3" flutter_parsed_text: dependency: transitive description: name: flutter_parsed_text - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.1" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.7" flutter_rust_bridge: @@ -451,476 +451,476 @@ packages: dependency: "direct dev" description: name: freezed - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0+1" freezed_annotation: dependency: "direct main" description: name: freezed_annotation - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.3" get: dependency: "direct main" description: name: get - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.6.5" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" graphs: dependency: transitive description: name: graphs - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" html: dependency: transitive description: name: html - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.15.0" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.13.5" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.1" image: dependency: "direct main" description: name: image - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.0" image_picker: dependency: "direct main" description: name: image_picker - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.8.5+3" image_picker_android: dependency: transitive description: name: image_picker_android - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.8.5+2" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.8" image_picker_ios: dependency: transitive description: name: image_picker_ios - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.8.5+6" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.6.1" intl: dependency: transitive description: name: intl - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.17.0" io: dependency: transitive description: name: io - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.3" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.6.4" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.6.0" logging: dependency: transitive description: name: logging - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.12.11" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.4" menu_base: dependency: transitive description: name: menu_base - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.7.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" nested: dependency: transitive description: name: nested - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" octo_image: dependency: transitive description: name: octo_image - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" package_info_plus: dependency: "direct main" description: name: package_info_plus - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.4.3" + version: "1.4.3+1" package_info_plus_linux: dependency: transitive description: name: package_info_plus_linux - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.5" package_info_plus_macos: dependency: transitive description: name: package_info_plus_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" package_info_plus_web: dependency: transitive description: name: package_info_plus_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.5" package_info_plus_windows: dependency: transitive description: name: package_info_plus_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.8.1" path_provider: dependency: "direct main" description: name: path_provider - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.11" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.17" + version: "2.0.19" path_provider_ios: dependency: transitive description: name: path_provider_ios - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.11" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.7" path_provider_macos: dependency: transitive description: name: path_provider_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.6" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.4" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" pedantic: dependency: transitive description: name: pedantic - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.11.1" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "5.0.0" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.5.1" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.2.4" provider: dependency: "direct main" description: name: provider - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.0.3" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" qr_code_scanner: dependency: "direct main" description: name: qr_code_scanner - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" quiver: dependency: transitive description: name: quiver - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.0" rxdart: dependency: transitive description: name: rxdart - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.27.5" screen_retriever: dependency: transitive description: name: screen_retriever - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.2" settings_ui: dependency: "direct main" description: name: settings_ui - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.2" shared_preferences: dependency: "direct main" description: name: shared_preferences - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.15" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.12" shared_preferences_ios: dependency: transitive description: name: shared_preferences_ios - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.4" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.4" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.2" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" shortid: dependency: transitive description: name: shortid - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.2" sky_engine: @@ -932,280 +932,280 @@ packages: dependency: transitive description: name: source_gen - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.2" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.8.2" sqflite: dependency: transitive description: name: sqflite - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.3+1" sqflite_common: dependency: transitive description: name: sqflite_common - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.1+1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" synchronized: dependency: transitive description: name: synchronized - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0+2" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.4.9" timing: dependency: transitive description: name: timing - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" toggle_switch: dependency: "direct main" description: name: toggle_switch - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" tray_manager: dependency: "direct main" description: name: tray_manager - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.7" tuple: dependency: "direct main" description: name: tuple - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.1" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.5" url_launcher_android: dependency: transitive description: name: url_launcher_android - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.0.17" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.0.17" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" url_launcher_web: dependency: transitive description: name: url_launcher_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.13" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" uuid: dependency: transitive description: name: uuid - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" video_player: dependency: transitive description: name: video_player - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.6" video_player_android: dependency: transitive description: name: video_player_android - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.8" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.5" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "5.1.4" video_player_web: dependency: transitive description: name: video_player_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.12" visibility_detector: dependency: "direct main" description: name: visibility_detector - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.3" wakelock: dependency: "direct main" description: name: wakelock - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.5.6" wakelock_macos: dependency: transitive description: name: wakelock_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.4.0" wakelock_platform_interface: dependency: transitive description: name: wakelock_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.0" wakelock_web: dependency: transitive description: name: wakelock_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.4.0" wakelock_windows: dependency: transitive description: name: wakelock_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.0" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.7.0" window_manager: @@ -1221,28 +1221,28 @@ packages: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.0+1" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.0" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.1" zxing2: dependency: "direct main" description: name: zxing2 - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.0" sdks: diff --git a/src/lang/cn.rs b/src/lang/cn.rs index df5cfdfd7..730c8be94 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "原始比例"), ("Shrink", "收缩"), ("Stretch", "伸展"), + ("Scrollbar", "滚动条"), + ("ScrollAuto", "自动滚动"), ("Good image quality", "好画质"), ("Balanced", "一般画质"), ("Optimize reaction time", "优化反应时间"), diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 86aada74f..f174850fc 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Původní"), ("Shrink", "Oříznout"), ("Stretch", "Roztáhnout"), + ("Scrollbar", "Posuvník"), + ("ScrollAuto", "Rolovať Auto"), ("Good image quality", "Dobrá kvalita obrazu"), ("Balanced", "Vyvážené"), ("Optimize reaction time", "Optimalizovat pro co nejnižší prodlevu odezvy"), diff --git a/src/lang/da.rs b/src/lang/da.rs index 8f4861c2a..60ebeafbb 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Original"), ("Shrink", "Krymp"), ("Stretch", "Strak"), + ("Scrollbar", "Rullebar"), + ("ScrollAuto", "Rul Auto"), ("Good image quality", "God billedkvalitet"), ("Balanced", "Afbalanceret"), ("Optimize reaction time", "Optimeret responstid"), diff --git a/src/lang/de.rs b/src/lang/de.rs index 6af6841b6..02c73d095 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Original"), ("Shrink", "Verkleinern"), ("Stretch", "Strecken"), + ("Scrollbar", "Scrollleiste"), + ("ScrollAuto", "Automatisch scrollen"), ("Good image quality", "Schöner"), ("Balanced", "Ausgeglichen"), ("Optimize reaction time", "Schneller"), diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 0c68bd569..3ce5c24f9 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Originala rilatumo"), ("Shrink", "Ŝrumpi"), ("Stretch", "Streĉi"), + ("Scrollbar", "Rulumbreto"), + ("ScrollAuto", "Rulumu Aŭtomate"), ("Good image quality", "Bona bilda kvalito"), ("Balanced", "Normala bilda kvalito"), ("Optimize reaction time", "Optimigi reakcia tempo"), diff --git a/src/lang/es.rs b/src/lang/es.rs index 9eef5a5a8..2fa92bac8 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Original"), ("Shrink", "Encogerse"), ("Stretch", "Estirar"), + ("Scrollbar", "Barra de desplazamiento"), + ("ScrollAuto", "Desplazamiento automático"), ("Good image quality", "Buena calidad de imagen"), ("Balanced", "Equilibrado"), ("Optimize reaction time", "Optimizar el tiempo de reacción"), diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 51d079b03..4efc804e1 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Ratio d'origine"), ("Shrink", "Rétrécir"), ("Stretch", "Étirer"), + ("Scrollbar", "Barre de défilement"), + ("ScrollAuto", "Défilement automatique"), ("Good image quality", "Bonne qualité d'image"), ("Balanced", "Qualité d'image normale"), ("Optimize reaction time", "Optimiser le temps de réaction"), diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 5590e0ec9..fee1fc450 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Eredeti"), ("Shrink", "Zsugorított"), ("Stretch", "Nyújtott"), + ("Scrollbar", "Görgetősáv"), + ("ScrollAuto", "Görgessen Auto"), ("Good image quality", "Jó képminőség"), ("Balanced", "Balanszolt"), ("Optimize reaction time", "Válaszidő optimializálása"), diff --git a/src/lang/id.rs b/src/lang/id.rs index ef1078175..b6d9dbd0d 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Original"), ("Shrink", "Susutkan"), ("Stretch", "Regangkan"), + ("Scrollbar", "Scroll bar"), + ("ScrollAuto", "Gulir Otomatis"), ("Good image quality", "Kualitas Gambar Baik"), ("Balanced", "Seimbang"), ("Optimize reaction time", "Optimalkan waktu reaksi"), diff --git a/src/lang/it.rs b/src/lang/it.rs index 2834644eb..f4e2d0bce 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Originale"), ("Shrink", "Restringi"), ("Stretch", "Allarga"), + ("Scrollbar", "Barra di scorrimento"), + ("ScrollAuto", "Scorri automaticamente"), ("Good image quality", "Buona qualità immagine"), ("Balanced", "Bilanciato"), ("Optimize reaction time", "Ottimizza il tempo di reazione"), diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 5c6ba1da7..f4c991690 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "オリジナル"), ("Shrink", "縮小"), ("Stretch", "伸縮"), + ("Scrollbar", "スクロール・バー"), + ("ScrollAuto", "自動スクロール"), ("Good image quality", "画質優先"), ("Balanced", "バランス"), ("Optimize reaction time", "速度優先"), diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 8602d0647..81eaddfaf 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Oryginał"), ("Shrink", "Zmniejsz"), ("Stretch", "Zwiększ"), + ("Scrollbar", "Pasek przewijania"), + ("ScrollAuto", "Przewijanie automatyczne"), ("Good image quality", "Dobra jakość obrazu"), ("Balanced", "Zrównoważony"), ("Optimize reaction time", "Zoptymalizuj czas reakcji"), diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 75d3af784..8d1ffbbcf 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Original"), ("Shrink", "Reduzir"), ("Stretch", "Aumentar"), + ("Scrollbar", "Barra de rolagem"), + ("ScrollAuto", "Rolagem automática"), ("Good image quality", "Qualidade visual boa"), ("Balanced", "Balanceada"), ("Optimize reaction time", "Otimizar tempo de reação"), diff --git a/src/lang/ru.rs b/src/lang/ru.rs index d44751cd8..ade2c7806 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Оригинал"), ("Shrink", "Уменьшить"), ("Stretch", "Растянуть"), + ("Scrollbar", "Полоса прокрутки"), + ("ScrollAuto", "Прокрутка Авто"), ("Good image quality", "Хорошее качество изображения"), ("Balanced", "Сбалансированный"), ("Optimize reaction time", "Оптимизировать время реакции"), diff --git a/src/lang/sk.rs b/src/lang/sk.rs index f94db252b..a887cc34a 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Pôvodný"), ("Shrink", "Zmenšené"), ("Stretch", "Roztiahnuté"), + ("Scrollbar", "Posuvník"), + ("ScrollAuto", "Rolovať Auto"), ("Good image quality", "Dobrá kvalita obrazu"), ("Balanced", "Vyvážené"), ("Optimize reaction time", "Optimalizované pre čas odozvy"), diff --git a/src/lang/template.rs b/src/lang/template.rs index ca64b2ac7..e0b64cdfa 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", ""), ("Shrink", ""), ("Stretch", ""), + ("Scrollbar", ""), + ("ScrollAuto", ""), ("Good image quality", ""), ("Balanced", ""), ("Optimize reaction time", ""), diff --git a/src/lang/tr.rs b/src/lang/tr.rs index cff01dcc8..410d918eb 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Orjinal"), ("Shrink", "Küçült"), ("Stretch", "Uzat"), + ("Scrollbar", "Kaydırma çubuğu"), + ("ScrollAuto", "Otomatik Kaydır"), ("Good image quality", "İyi görüntü kalitesi"), ("Balanced", "Dengelenmiş"), ("Optimize reaction time", "Tepki süresini optimize et"), diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 79435a69c..5f0acdd06 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "原始"), ("Shrink", "縮減"), ("Stretch", "延展"), + ("Scrollbar", "滾動條"), + ("ScrollAuto", "自動滾動"), ("Good image quality", "畫面品質良好"), ("Balanced", "平衡"), ("Optimize reaction time", "回應速度最佳化"), diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 65ffcb61c..5704bf9ee 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Original", "Gốc"), ("Shrink", "Thu nhỏ"), ("Stretch", "Kéo dãn"), + ("Scrollbar", "Thanh cuộn"), + ("ScrollAuto", "Tự động cuộn"), ("Good image quality", "Chất lượng hình ảnh tốt"), ("Balanced", "Cân bằng"), ("Optimize reaction time", "Thời gian phản ứng tối ưu"),