mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-04-20 03:06:59 +08:00
122 lines
3.9 KiB
Dart
122 lines
3.9 KiB
Dart
import 'dart:async' show scheduleMicrotask;
|
|
import 'dart:collection' show Queue;
|
|
import 'dart:ui' show PointerDataPacket;
|
|
|
|
import 'package:flutter/gestures.dart' show PointerEventConverter;
|
|
import 'package:flutter/rendering.dart' show RenderView, ViewConfiguration;
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
/// ref https://github.com/LastMonopoly/scaled_app
|
|
|
|
/// Adapted from [WidgetsFlutterBinding]
|
|
///
|
|
class ScaledWidgetsFlutterBinding extends WidgetsFlutterBinding {
|
|
ScaledWidgetsFlutterBinding._({double scaleFactor = 1.0})
|
|
: _scaleFactor = scaleFactor;
|
|
|
|
/// Calculate scale factor from device size.
|
|
double _scaleFactor;
|
|
|
|
/// Update scaleFactor callback, then rebuild layout
|
|
set scaleFactor(double scaleFactor) {
|
|
if (_scaleFactor == scaleFactor) return;
|
|
_scaleFactor = scaleFactor;
|
|
handleMetricsChanged();
|
|
}
|
|
|
|
double devicePixelRatioScaled = 0;
|
|
|
|
static ScaledWidgetsFlutterBinding? _binding;
|
|
|
|
static ScaledWidgetsFlutterBinding get instance => _binding!;
|
|
|
|
/// Scaling will be applied based on [scaleFactor] callback.
|
|
///
|
|
static WidgetsBinding ensureInitialized({double scaleFactor = 1.0}) =>
|
|
_binding ??= ScaledWidgetsFlutterBinding._(scaleFactor: scaleFactor);
|
|
|
|
/// Override the method from [RendererBinding.createViewConfiguration] to
|
|
/// change what size or device pixel ratio the [RenderView] will use.
|
|
///
|
|
/// See more:
|
|
/// * [RendererBinding.createViewConfiguration]
|
|
/// * [TestWidgetsFlutterBinding.createViewConfiguration]
|
|
@override
|
|
ViewConfiguration createViewConfigurationFor(RenderView renderView) {
|
|
final view = renderView.flutterView;
|
|
final devicePixelRatio = view.devicePixelRatio;
|
|
devicePixelRatioScaled = devicePixelRatio * _scaleFactor;
|
|
final BoxConstraints physicalConstraints =
|
|
BoxConstraints.fromViewConstraints(view.physicalConstraints);
|
|
return ViewConfiguration(
|
|
physicalConstraints: physicalConstraints,
|
|
logicalConstraints: physicalConstraints / devicePixelRatioScaled,
|
|
devicePixelRatio: devicePixelRatioScaled,
|
|
);
|
|
}
|
|
|
|
/// Adapted from [GestureBinding.initInstances]
|
|
@override
|
|
void initInstances() {
|
|
super.initInstances();
|
|
platformDispatcher.onPointerDataPacket = _handlePointerDataPacket;
|
|
}
|
|
|
|
@override
|
|
void unlocked() {
|
|
super.unlocked();
|
|
_flushPointerEventQueue();
|
|
}
|
|
|
|
final Queue<PointerEvent> _pendingPointerEvents = Queue<PointerEvent>();
|
|
|
|
/// When we scale UI using [ViewConfiguration], [ui.window] stays the same.
|
|
///
|
|
/// [GestureBinding] uses [platformDispatcher.implicitView.devicePixelRatio] for calculations,
|
|
/// so we override corresponding methods.
|
|
///
|
|
void _handlePointerDataPacket(PointerDataPacket packet) {
|
|
// We convert pointer data to logical pixels so that e.g. the touch slop can be
|
|
// defined in a device-independent manner.
|
|
try {
|
|
_pendingPointerEvents.addAll(
|
|
PointerEventConverter.expand(packet.data, _devicePixelRatioForView),
|
|
);
|
|
if (!locked) {
|
|
_flushPointerEventQueue();
|
|
}
|
|
} catch (error, stack) {
|
|
FlutterError.reportError(
|
|
FlutterErrorDetails(
|
|
exception: error,
|
|
stack: stack,
|
|
library: 'gestures library',
|
|
context: ErrorDescription('while handling a pointer data packet'),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
double _devicePixelRatioForView(int viewId) => devicePixelRatioScaled;
|
|
|
|
/// Dispatch a [PointerCancelEvent] for the given pointer soon.
|
|
///
|
|
/// The pointer event will be dispatched before the next pointer event and
|
|
/// before the end of the microtask but not within this function call.
|
|
@override
|
|
void cancelPointer(int pointer) {
|
|
if (_pendingPointerEvents.isEmpty && !locked) {
|
|
scheduleMicrotask(_flushPointerEventQueue);
|
|
}
|
|
_pendingPointerEvents.addFirst(PointerCancelEvent(pointer: pointer));
|
|
}
|
|
|
|
void _flushPointerEventQueue() {
|
|
assert(!locked);
|
|
|
|
while (_pendingPointerEvents.isNotEmpty) {
|
|
handlePointerEvent(_pendingPointerEvents.removeFirst());
|
|
}
|
|
}
|
|
}
|