aves/plugins/aves_magnifier/lib/src/controller/controller.dart
2024-02-15 23:23:05 +01:00

143 lines
4.7 KiB
Dart

import 'dart:async';
import 'package:aves_magnifier/src/controller/state.dart';
import 'package:aves_magnifier/src/scale/scale_boundaries.dart';
import 'package:aves_magnifier/src/scale/scale_level.dart';
import 'package:aves_magnifier/src/scale/state.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
class AvesMagnifierController {
final StreamController<MagnifierState> _stateStreamController = StreamController.broadcast();
final StreamController<ScaleBoundaries> _scaleBoundariesStreamController = StreamController.broadcast();
final StreamController<ScaleStateChange> _scaleStateChangeStreamController = StreamController.broadcast();
bool _disposed = false;
late MagnifierState _currentState, initial, previousState;
ScaleBoundaries? _scaleBoundaries;
late ScaleStateChange _currentScaleState, previousScaleState;
AvesMagnifierController({
MagnifierState? initialState,
}) : super() {
if (kFlutterMemoryAllocationsEnabled) {
FlutterMemoryAllocations.instance.dispatchObjectCreated(
library: 'aves',
className: '$AvesMagnifierController',
object: this,
);
}
const source = ChangeSource.internal;
initial = initialState ?? const MagnifierState(position: Offset.zero, scale: null, source: source);
previousState = initial;
_currentState = initial;
_setState(initial);
const _initialScaleState = ScaleStateChange(state: ScaleState.initial, source: source);
previousScaleState = _initialScaleState;
_currentScaleState = _initialScaleState;
_setScaleState(_initialScaleState);
}
void dispose() {
if (kFlutterMemoryAllocationsEnabled) {
FlutterMemoryAllocations.instance.dispatchObjectDisposed(object: this);
}
_disposed = true;
_stateStreamController.close();
_scaleBoundariesStreamController.close();
_scaleStateChangeStreamController.close();
}
Stream<MagnifierState> get stateStream => _stateStreamController.stream;
Stream<ScaleBoundaries> get scaleBoundariesStream => _scaleBoundariesStreamController.stream;
Stream<ScaleStateChange> get scaleStateChangeStream => _scaleStateChangeStreamController.stream;
MagnifierState get currentState => _currentState;
Offset get position => currentState.position;
double? get scale => currentState.scale;
ScaleBoundaries? get scaleBoundaries => _scaleBoundaries;
ScaleStateChange get scaleState => _currentScaleState;
bool get hasScaleSateChanged => previousScaleState != scaleState;
bool get isZooming => scaleState.state == ScaleState.zoomedIn || scaleState.state == ScaleState.zoomedOut;
void update({
Offset? position,
double? scale,
required ChangeSource source,
}) {
position = position ?? this.position;
scale = scale ?? this.scale;
if (this.position == position && this.scale == scale) return;
assert((scale ?? 0) >= 0);
previousState = currentState;
_setState(MagnifierState(
position: position,
scale: scale,
source: source,
));
}
void setScaleState(ScaleState newValue, ChangeSource source, {Offset? childFocalPoint}) {
if (_disposed || _currentScaleState.state == newValue) return;
previousScaleState = _currentScaleState;
_currentScaleState = ScaleStateChange(state: newValue, source: source, childFocalPoint: childFocalPoint);
_scaleStateChangeStreamController.add(scaleState);
}
void _setState(MagnifierState state) {
if (_disposed || _currentState == state) return;
_currentState = state;
_stateStreamController.add(state);
}
void setScaleBoundaries(ScaleBoundaries scaleBoundaries) {
if (_disposed || _scaleBoundaries == scaleBoundaries) return;
_scaleBoundaries = scaleBoundaries;
_scaleBoundariesStreamController.add(scaleBoundaries);
if (!isZooming) {
update(
scale: getScaleForScaleState(_currentScaleState.state),
source: ChangeSource.internal,
);
}
}
void _setScaleState(ScaleStateChange scaleState) {
if (_disposed || _currentScaleState == scaleState) return;
_currentScaleState = scaleState;
_scaleStateChangeStreamController.add(_currentScaleState);
}
double? getScaleForScaleState(ScaleState scaleState) {
final boundaries = scaleBoundaries;
if (boundaries == null) return null;
switch (scaleState) {
case ScaleState.initial:
case ScaleState.zoomedIn:
case ScaleState.zoomedOut:
return boundaries.clampScale(boundaries.initialScale);
case ScaleState.covering:
return boundaries.clampScale(ScaleLevel.scaleForCovering(boundaries.viewportSize, boundaries.contentSize));
case ScaleState.originalSize:
return boundaries.clampScale(boundaries.originalScale);
default:
return null;
}
}
}