Compare commits
1 Commits
v0.8.88-pr
...
v0.8.88
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed7868282a |
@@ -103,6 +103,9 @@ object State {
|
||||
|
||||
suspend fun startServiceWithEngine() {
|
||||
runLock.withLock {
|
||||
if (serviceFlutterEngine != null || runStateFlow.value == RunState.PENDING || runStateFlow.value == RunState.START) {
|
||||
return
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
serviceFlutterEngine = FlutterEngine(GlobalState.application)
|
||||
serviceFlutterEngine?.plugins?.add(ServicePlugin())
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
android:process=":remote">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="service" />
|
||||
android:value="proxy" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.follow.clash.service.models
|
||||
|
||||
import com.follow.clash.common.GlobalState
|
||||
import com.follow.clash.common.formatBytes
|
||||
import com.follow.clash.core.Core
|
||||
import com.google.gson.Gson
|
||||
@@ -17,7 +18,8 @@ fun Core.getSpeedTrafficText(onlyStatisticsProxy: Boolean): String {
|
||||
val res = getTraffic(onlyStatisticsProxy)
|
||||
val traffic = Gson().fromJson(res, Traffic::class.java)
|
||||
return traffic.speedText
|
||||
} catch (_: Exception) {
|
||||
} catch (e: Exception) {
|
||||
GlobalState.log(e.message + "")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -47,9 +47,6 @@ class NotificationModule(private val service: Service) : Module() {
|
||||
private val scope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
override fun onInstall() {
|
||||
State.notificationParamsFlow.value?.let {
|
||||
update(it.extended)
|
||||
}
|
||||
scope.launch {
|
||||
val screenFlow = service.receiveBroadcastFlow {
|
||||
addAction(Intent.ACTION_SCREEN_ON)
|
||||
@@ -69,6 +66,12 @@ class NotificationModule(private val service: Service) : Module() {
|
||||
.collect { (params, _) ->
|
||||
update(params!!)
|
||||
}
|
||||
|
||||
State.notificationParamsFlow.value?.let {
|
||||
update(it.extended)
|
||||
} ?: run {
|
||||
update(NotificationParams().extended)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,16 +36,25 @@ class Throttler {
|
||||
Function func, {
|
||||
List<dynamic>? args,
|
||||
Duration duration = const Duration(milliseconds: 600),
|
||||
bool fire = false,
|
||||
}) {
|
||||
final timer = _operations[tag];
|
||||
if (timer != null) {
|
||||
return true;
|
||||
}
|
||||
_operations[tag] = Timer(duration, () {
|
||||
_operations[tag]?.cancel();
|
||||
_operations.remove(tag);
|
||||
if (fire) {
|
||||
Function.apply(func, args);
|
||||
});
|
||||
_operations[tag] = Timer(duration, () {
|
||||
_operations[tag]?.cancel();
|
||||
_operations.remove(tag);
|
||||
});
|
||||
} else {
|
||||
_operations[tag] = Timer(duration, () {
|
||||
Function.apply(func, args);
|
||||
_operations[tag]?.cancel();
|
||||
_operations.remove(tag);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -134,11 +134,15 @@ class CommonPageTransition extends StatefulWidget {
|
||||
bool allowSnapshotting,
|
||||
Widget? child,
|
||||
) {
|
||||
final Animation<Offset> delegatedPositionAnimation = CurvedAnimation(
|
||||
final CurvedAnimation animation = CurvedAnimation(
|
||||
parent: secondaryAnimation,
|
||||
curve: Curves.linearToEaseOut,
|
||||
reverseCurve: Curves.easeInToLinear,
|
||||
).drive(_kMiddleLeftTween);
|
||||
);
|
||||
final Animation<Offset> delegatedPositionAnimation = animation.drive(
|
||||
_kMiddleLeftTween,
|
||||
);
|
||||
animation.dispose();
|
||||
|
||||
assert(debugCheckHasDirectionality(context));
|
||||
final TextDirection textDirection = Directionality.of(context);
|
||||
|
||||
@@ -552,7 +552,12 @@ class AppController {
|
||||
|
||||
Future<void> _connectCore() async {
|
||||
_ref.read(coreStatusProvider.notifier).value = CoreStatus.connecting;
|
||||
final message = await coreController.preload();
|
||||
final result = await Future.wait([
|
||||
coreController.preload(),
|
||||
if (!globalState.isService) Future.delayed(Duration(milliseconds: 300)),
|
||||
]);
|
||||
final String message = result[0];
|
||||
await Future.delayed(commonDuration);
|
||||
if (message.isNotEmpty) {
|
||||
_ref.read(coreStatusProvider.notifier).value = CoreStatus.disconnected;
|
||||
if (context.mounted) {
|
||||
|
||||
@@ -24,11 +24,16 @@ class _VpnContainerState extends ConsumerState<VpnManager> {
|
||||
}
|
||||
|
||||
void showTip() {
|
||||
debouncer.call(FunctionTag.vpnTip, () {
|
||||
if (ref.read(isStartProvider)) {
|
||||
globalState.showNotifier(appLocalizations.vpnTip);
|
||||
}
|
||||
});
|
||||
throttler.call(
|
||||
FunctionTag.vpnTip,
|
||||
() {
|
||||
if (ref.read(isStartProvider)) {
|
||||
globalState.showNotifier(appLocalizations.vpnTip);
|
||||
}
|
||||
},
|
||||
duration: const Duration(seconds: 6),
|
||||
fire: true,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -14,7 +14,7 @@ class StartButton extends ConsumerStatefulWidget {
|
||||
|
||||
class _StartButtonState extends ConsumerState<StartButton>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
AnimationController? _controller;
|
||||
late Animation<double> _animation;
|
||||
bool isStart = false;
|
||||
|
||||
@@ -28,7 +28,7 @@ class _StartButtonState extends ConsumerState<StartButton>
|
||||
duration: const Duration(milliseconds: 200),
|
||||
);
|
||||
_animation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
parent: _controller!,
|
||||
curve: Curves.easeOutBack,
|
||||
);
|
||||
ref.listenManual(runTimeProvider.select((state) => state != null), (
|
||||
@@ -44,7 +44,8 @@ class _StartButtonState extends ConsumerState<StartButton>
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
_controller?.dispose();
|
||||
_controller = null;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -59,9 +60,9 @@ class _StartButtonState extends ConsumerState<StartButton>
|
||||
void updateController() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (isStart && mounted) {
|
||||
_controller.forward();
|
||||
_controller?.forward();
|
||||
} else {
|
||||
_controller.reverse();
|
||||
_controller?.reverse();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -80,7 +81,7 @@ class _StartButtonState extends ConsumerState<StartButton>
|
||||
),
|
||||
),
|
||||
child: AnimatedBuilder(
|
||||
animation: _controller.view,
|
||||
animation: _controller!.view,
|
||||
builder: (_, child) {
|
||||
final textWidth =
|
||||
globalState.measure
|
||||
|
||||
@@ -282,7 +282,7 @@ class ListItem<T> extends StatelessWidget {
|
||||
closedBuilder: (_, action) {
|
||||
openAction() {
|
||||
final isMobile = globalState.appState.viewMode == ViewMode.mobile;
|
||||
if (!isMobile || system.isDesktop) {
|
||||
if (!isMobile) {
|
||||
showExtend(
|
||||
context,
|
||||
props: ExtendProps(
|
||||
|
||||
@@ -2,19 +2,15 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
|
||||
typedef CloseContainerActionCallback<S> = void Function({S? returnValue});
|
||||
typedef OpenContainerBuilder<S> = Widget Function(
|
||||
BuildContext context,
|
||||
CloseContainerActionCallback<S> action,
|
||||
);
|
||||
typedef CloseContainerBuilder = Widget Function(
|
||||
BuildContext context,
|
||||
VoidCallback action,
|
||||
);
|
||||
typedef OpenContainerBuilder<S> =
|
||||
Widget Function(
|
||||
BuildContext context,
|
||||
CloseContainerActionCallback<S> action,
|
||||
);
|
||||
typedef CloseContainerBuilder =
|
||||
Widget Function(BuildContext context, VoidCallback action);
|
||||
|
||||
enum ContainerTransitionType {
|
||||
fade,
|
||||
fadeThrough,
|
||||
}
|
||||
enum ContainerTransitionType { fade, fadeThrough }
|
||||
|
||||
typedef ClosedCallback<S> = void Function(S data);
|
||||
|
||||
@@ -56,20 +52,23 @@ class _OpenContainerState<T> extends State<OpenContainer<T?>> {
|
||||
Future<void> openContainer() async {
|
||||
final Color middleColor =
|
||||
widget.middleColor ?? Theme.of(context).canvasColor;
|
||||
final T? data = await Navigator.of(
|
||||
context,
|
||||
rootNavigator: widget.useRootNavigator,
|
||||
).push(_OpenContainerRoute<T>(
|
||||
middleColor: middleColor,
|
||||
closedBuilder: widget.closedBuilder,
|
||||
openBuilder: widget.openBuilder,
|
||||
hideableKey: _hideableKey,
|
||||
closedBuilderKey: _closedBuilderKey,
|
||||
transitionDuration: widget.transitionDuration,
|
||||
transitionType: widget.transitionType,
|
||||
useRootNavigator: widget.useRootNavigator,
|
||||
routeSettings: widget.routeSettings,
|
||||
));
|
||||
final T? data =
|
||||
await Navigator.of(
|
||||
context,
|
||||
rootNavigator: widget.useRootNavigator,
|
||||
).push(
|
||||
_OpenContainerRoute<T>(
|
||||
middleColor: middleColor,
|
||||
closedBuilder: widget.closedBuilder,
|
||||
openBuilder: widget.openBuilder,
|
||||
hideableKey: _hideableKey,
|
||||
closedBuilderKey: _closedBuilderKey,
|
||||
transitionDuration: widget.transitionDuration,
|
||||
transitionType: widget.transitionType,
|
||||
useRootNavigator: widget.useRootNavigator,
|
||||
routeSettings: widget.routeSettings,
|
||||
),
|
||||
);
|
||||
if (widget.onClosed != null) {
|
||||
widget.onClosed!(data);
|
||||
}
|
||||
@@ -97,10 +96,7 @@ class _OpenContainerState<T> extends State<OpenContainer<T?>> {
|
||||
}
|
||||
|
||||
class _Hideable extends StatefulWidget {
|
||||
const _Hideable({
|
||||
super.key,
|
||||
required this.child,
|
||||
});
|
||||
const _Hideable({super.key, required this.child});
|
||||
|
||||
final Widget child;
|
||||
|
||||
@@ -161,9 +157,9 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
|
||||
required this.transitionType,
|
||||
required this.useRootNavigator,
|
||||
required RouteSettings? routeSettings,
|
||||
}) : _closedOpacityTween = _getClosedOpacityTween(transitionType),
|
||||
_openOpacityTween = _getOpenOpacityTween(transitionType),
|
||||
super(settings: routeSettings);
|
||||
}) : _closedOpacityTween = _getClosedOpacityTween(transitionType),
|
||||
_openOpacityTween = _getOpenOpacityTween(transitionType),
|
||||
super(settings: routeSettings);
|
||||
|
||||
static _FlippableTweenSequence<Color?> _getColorTween({
|
||||
required ContainerTransitionType transitionType,
|
||||
@@ -173,99 +169,89 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
|
||||
}) {
|
||||
switch (transitionType) {
|
||||
case ContainerTransitionType.fade:
|
||||
return _FlippableTweenSequence<Color?>(
|
||||
<TweenSequenceItem<Color?>>[
|
||||
TweenSequenceItem<Color>(
|
||||
tween: ConstantTween<Color>(closedColor),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<Color?>(
|
||||
tween: ColorTween(begin: closedColor, end: openColor),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<Color>(
|
||||
tween: ConstantTween<Color>(openColor),
|
||||
weight: 3 / 5,
|
||||
),
|
||||
],
|
||||
);
|
||||
return _FlippableTweenSequence<Color?>(<TweenSequenceItem<Color?>>[
|
||||
TweenSequenceItem<Color>(
|
||||
tween: ConstantTween<Color>(closedColor),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<Color?>(
|
||||
tween: ColorTween(begin: closedColor, end: openColor),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<Color>(
|
||||
tween: ConstantTween<Color>(openColor),
|
||||
weight: 3 / 5,
|
||||
),
|
||||
]);
|
||||
case ContainerTransitionType.fadeThrough:
|
||||
return _FlippableTweenSequence<Color?>(
|
||||
<TweenSequenceItem<Color?>>[
|
||||
TweenSequenceItem<Color?>(
|
||||
tween: ColorTween(begin: closedColor, end: middleColor),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<Color?>(
|
||||
tween: ColorTween(begin: middleColor, end: openColor),
|
||||
weight: 4 / 5,
|
||||
),
|
||||
],
|
||||
);
|
||||
return _FlippableTweenSequence<Color?>(<TweenSequenceItem<Color?>>[
|
||||
TweenSequenceItem<Color?>(
|
||||
tween: ColorTween(begin: closedColor, end: middleColor),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<Color?>(
|
||||
tween: ColorTween(begin: middleColor, end: openColor),
|
||||
weight: 4 / 5,
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
static _FlippableTweenSequence<double> _getClosedOpacityTween(
|
||||
ContainerTransitionType transitionType) {
|
||||
ContainerTransitionType transitionType,
|
||||
) {
|
||||
switch (transitionType) {
|
||||
case ContainerTransitionType.fade:
|
||||
return _FlippableTweenSequence<double>(
|
||||
<TweenSequenceItem<double>>[
|
||||
TweenSequenceItem<double>(
|
||||
tween: ConstantTween<double>(1.0),
|
||||
weight: 1,
|
||||
),
|
||||
],
|
||||
);
|
||||
return _FlippableTweenSequence<double>(<TweenSequenceItem<double>>[
|
||||
TweenSequenceItem<double>(
|
||||
tween: ConstantTween<double>(1.0),
|
||||
weight: 1,
|
||||
),
|
||||
]);
|
||||
case ContainerTransitionType.fadeThrough:
|
||||
return _FlippableTweenSequence<double>(
|
||||
<TweenSequenceItem<double>>[
|
||||
TweenSequenceItem<double>(
|
||||
tween: Tween<double>(begin: 1.0, end: 0.0),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<double>(
|
||||
tween: ConstantTween<double>(0.0),
|
||||
weight: 4 / 5,
|
||||
),
|
||||
],
|
||||
);
|
||||
return _FlippableTweenSequence<double>(<TweenSequenceItem<double>>[
|
||||
TweenSequenceItem<double>(
|
||||
tween: Tween<double>(begin: 1.0, end: 0.0),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<double>(
|
||||
tween: ConstantTween<double>(0.0),
|
||||
weight: 4 / 5,
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
static _FlippableTweenSequence<double> _getOpenOpacityTween(
|
||||
ContainerTransitionType transitionType) {
|
||||
ContainerTransitionType transitionType,
|
||||
) {
|
||||
switch (transitionType) {
|
||||
case ContainerTransitionType.fade:
|
||||
return _FlippableTweenSequence<double>(
|
||||
<TweenSequenceItem<double>>[
|
||||
TweenSequenceItem<double>(
|
||||
tween: ConstantTween<double>(0.0),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<double>(
|
||||
tween: Tween<double>(begin: 0.0, end: 1.0),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<double>(
|
||||
tween: ConstantTween<double>(1.0),
|
||||
weight: 3 / 5,
|
||||
),
|
||||
],
|
||||
);
|
||||
return _FlippableTweenSequence<double>(<TweenSequenceItem<double>>[
|
||||
TweenSequenceItem<double>(
|
||||
tween: ConstantTween<double>(0.0),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<double>(
|
||||
tween: Tween<double>(begin: 0.0, end: 1.0),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<double>(
|
||||
tween: ConstantTween<double>(1.0),
|
||||
weight: 3 / 5,
|
||||
),
|
||||
]);
|
||||
case ContainerTransitionType.fadeThrough:
|
||||
return _FlippableTweenSequence<double>(
|
||||
<TweenSequenceItem<double>>[
|
||||
TweenSequenceItem<double>(
|
||||
tween: ConstantTween<double>(0.0),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<double>(
|
||||
tween: Tween<double>(begin: 0.0, end: 1.0),
|
||||
weight: 4 / 5,
|
||||
),
|
||||
],
|
||||
);
|
||||
return _FlippableTweenSequence<double>(<TweenSequenceItem<double>>[
|
||||
TweenSequenceItem<double>(
|
||||
tween: ConstantTween<double>(0.0),
|
||||
weight: 1 / 5,
|
||||
),
|
||||
TweenSequenceItem<double>(
|
||||
tween: Tween<double>(begin: 0.0, end: 1.0),
|
||||
weight: 4 / 5,
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,8 +311,9 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
|
||||
@override
|
||||
void dispose() {
|
||||
if (hideableKey.currentState?.isVisible == false) {
|
||||
SchedulerBinding.instance
|
||||
.addPostFrameCallback((Duration d) => _toggleHideable(hide: false));
|
||||
SchedulerBinding.instance.addPostFrameCallback(
|
||||
(Duration d) => _toggleHideable(hide: false),
|
||||
);
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
@@ -343,10 +330,12 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
|
||||
required BuildContext navigatorContext,
|
||||
bool delayForSourceRoute = false,
|
||||
}) {
|
||||
final RenderBox navigator = Navigator.of(
|
||||
navigatorContext,
|
||||
rootNavigator: useRootNavigator,
|
||||
).context.findRenderObject()! as RenderBox;
|
||||
final RenderBox navigator =
|
||||
Navigator.of(
|
||||
navigatorContext,
|
||||
rootNavigator: useRootNavigator,
|
||||
).context.findRenderObject()!
|
||||
as RenderBox;
|
||||
final Size navSize = _getSize(navigator);
|
||||
_rectTween.end = Offset.zero & navSize;
|
||||
|
||||
@@ -359,8 +348,9 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
|
||||
}
|
||||
|
||||
if (delayForSourceRoute) {
|
||||
SchedulerBinding.instance
|
||||
.addPostFrameCallback(takeMeasurementsInSourceRoute);
|
||||
SchedulerBinding.instance.addPostFrameCallback(
|
||||
takeMeasurementsInSourceRoute,
|
||||
);
|
||||
} else {
|
||||
takeMeasurementsInSourceRoute();
|
||||
}
|
||||
@@ -451,8 +441,9 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
|
||||
final Animation<double> curvedAnimation = CurvedAnimation(
|
||||
parent: animation,
|
||||
curve: Curves.fastOutSlowIn,
|
||||
reverseCurve:
|
||||
_transitionWasInterrupted ? null : Curves.fastOutSlowIn.flipped,
|
||||
reverseCurve: _transitionWasInterrupted
|
||||
? null
|
||||
: Curves.fastOutSlowIn.flipped,
|
||||
);
|
||||
TweenSequence<Color?>? colorTween;
|
||||
TweenSequence<double>? closedOpacityTween, openOpacityTween;
|
||||
@@ -508,8 +499,9 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
|
||||
child: (hideableKey.currentState?.isInTree ?? false)
|
||||
? null
|
||||
: FadeTransition(
|
||||
opacity:
|
||||
closedOpacityTween!.animate(animation),
|
||||
opacity: closedOpacityTween!.animate(
|
||||
animation,
|
||||
),
|
||||
child: Builder(
|
||||
key: closedBuilderKey,
|
||||
builder: (BuildContext context) {
|
||||
@@ -521,22 +513,18 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Open child fading in.
|
||||
FittedBox(
|
||||
fit: BoxFit.fitWidth,
|
||||
OverflowBox(
|
||||
maxWidth: _rectTween.end!.width,
|
||||
maxHeight: _rectTween.end!.height,
|
||||
alignment: Alignment.topLeft,
|
||||
child: SizedBox(
|
||||
width: _rectTween.end!.width,
|
||||
height: _rectTween.end!.height,
|
||||
child: FadeTransition(
|
||||
opacity: openOpacityTween!.animate(animation),
|
||||
child: Builder(
|
||||
key: _openBuilderKey,
|
||||
builder: (BuildContext context) {
|
||||
return openBuilder(context, closeContainer);
|
||||
},
|
||||
),
|
||||
child: FadeTransition(
|
||||
opacity: openOpacityTween!.animate(animation),
|
||||
child: Builder(
|
||||
key: _openBuilderKey,
|
||||
builder: (BuildContext context) {
|
||||
return openBuilder(context, closeContainer);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -578,10 +566,12 @@ class _FlippableTweenSequence<T> extends TweenSequence<T> {
|
||||
if (_flipped == null) {
|
||||
final List<TweenSequenceItem<T>> newItems = <TweenSequenceItem<T>>[];
|
||||
for (int i = 0; i < _items.length; i++) {
|
||||
newItems.add(TweenSequenceItem<T>(
|
||||
tween: _items[i].tween,
|
||||
weight: _items[_items.length - 1 - i].weight,
|
||||
));
|
||||
newItems.add(
|
||||
TweenSequenceItem<T>(
|
||||
tween: _items[i].tween,
|
||||
weight: _items[_items.length - 1 - i].weight,
|
||||
),
|
||||
);
|
||||
}
|
||||
_flipped = _FlippableTweenSequence<T>(newItems);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ class CommonScaffold extends StatefulWidget {
|
||||
final Widget body;
|
||||
final Color? backgroundColor;
|
||||
final String? title;
|
||||
final Widget? leading;
|
||||
final List<Widget>? actions;
|
||||
final bool? centerTitle;
|
||||
final Widget? floatingActionButton;
|
||||
@@ -31,7 +30,6 @@ class CommonScaffold extends StatefulWidget {
|
||||
this.appBar,
|
||||
required this.body,
|
||||
this.backgroundColor,
|
||||
this.leading,
|
||||
this.title,
|
||||
this.actions,
|
||||
this.centerTitle,
|
||||
@@ -163,7 +161,7 @@ class CommonScaffoldState extends State<CommonScaffold> {
|
||||
_keywordsNotifier.value = keywords;
|
||||
}
|
||||
|
||||
Widget? _buildLeading() {
|
||||
Widget? _buildLeading(VoidCallback? backAction) {
|
||||
if (_isEdit) {
|
||||
return IconButton(
|
||||
onPressed: _appBarState.value.editState?.onExit,
|
||||
@@ -176,7 +174,16 @@ class CommonScaffoldState extends State<CommonScaffold> {
|
||||
icon: Icon(Icons.arrow_back),
|
||||
);
|
||||
}
|
||||
return widget.leading;
|
||||
return backAction != null
|
||||
? BackButton(
|
||||
onPressed: () {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
backAction();
|
||||
},
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
Widget _buildTitle(AppBarSearchState? startState) {
|
||||
@@ -251,7 +258,7 @@ class CommonScaffoldState extends State<CommonScaffold> {
|
||||
);
|
||||
}
|
||||
|
||||
PreferredSizeWidget _buildAppBar() {
|
||||
PreferredSizeWidget _buildAppBar(VoidCallback? backAction) {
|
||||
return PreferredSize(
|
||||
preferredSize: const Size.fromHeight(kToolbarHeight),
|
||||
child: Stack(
|
||||
@@ -263,8 +270,11 @@ class CommonScaffoldState extends State<CommonScaffold> {
|
||||
builder: (_, state, _) {
|
||||
return _buildAppBarWrap(
|
||||
AppBar(
|
||||
automaticallyImplyLeading: backAction != null
|
||||
? false
|
||||
: true,
|
||||
centerTitle: widget.centerTitle ?? false,
|
||||
leading: _buildLeading(),
|
||||
leading: _buildLeading(backAction),
|
||||
title: _buildTitle(state.searchState),
|
||||
actions: _buildActions(
|
||||
state.searchState != null,
|
||||
@@ -285,6 +295,7 @@ class CommonScaffoldState extends State<CommonScaffold> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(widget.appBar != null || widget.title != null);
|
||||
final backActionProvider = CommonScaffoldBackActionProvider.of(context);
|
||||
final body = SafeArea(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -327,7 +338,7 @@ class CommonScaffoldState extends State<CommonScaffold> {
|
||||
),
|
||||
);
|
||||
return Scaffold(
|
||||
appBar: _buildAppBar(),
|
||||
appBar: _buildAppBar(backActionProvider?.backAction),
|
||||
body: body,
|
||||
resizeToAvoidBottomInset: true,
|
||||
backgroundColor: widget.backgroundColor,
|
||||
@@ -349,3 +360,23 @@ List<Widget> genActions(List<Widget> actions, {double? space}) {
|
||||
SizedBox(width: 8),
|
||||
];
|
||||
}
|
||||
|
||||
class CommonScaffoldBackActionProvider extends InheritedWidget {
|
||||
final VoidCallback? backAction;
|
||||
|
||||
const CommonScaffoldBackActionProvider({
|
||||
super.key,
|
||||
required this.backAction,
|
||||
required super.child,
|
||||
});
|
||||
|
||||
static CommonScaffoldBackActionProvider? of(BuildContext context) {
|
||||
return context
|
||||
.dependOnInheritedWidgetOfExactType<CommonScaffoldBackActionProvider>();
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(CommonScaffoldBackActionProvider oldWidget) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: fl_clash
|
||||
description: A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.
|
||||
publish_to: 'none'
|
||||
version: 0.8.88+2025092101
|
||||
version: 0.8.88+2025092301
|
||||
environment:
|
||||
sdk: '>=3.8.0 <4.0.0'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user