Files
MWClash/lib/views/dashboard/widgets/start_button.dart
chen08209 bf017cd557 Add android separates the core process
Support core status check and force restart

Optimize proxies page and access page

Update flutter and pub dependencies

Optimize more details
2025-09-19 11:22:47 +08:00

135 lines
3.8 KiB
Dart

import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/providers/providers.dart';
import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class StartButton extends ConsumerStatefulWidget {
const StartButton({super.key});
@override
ConsumerState<StartButton> createState() => _StartButtonState();
}
class _StartButtonState extends ConsumerState<StartButton>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
bool isStart = false;
@override
void initState() {
super.initState();
isStart = globalState.appState.runTime != null;
_controller = AnimationController(
vsync: this,
value: isStart ? 1 : 0,
duration: const Duration(milliseconds: 200),
);
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeOutBack,
);
ref.listenManual(runTimeProvider.select((state) => state != null), (
prev,
next,
) {
if (next != isStart) {
isStart = next;
updateController();
}
}, fireImmediately: true);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void handleSwitchStart() {
isStart = !isStart;
updateController();
debouncer.call(FunctionTag.updateStatus, () {
globalState.appController.updateStatus(isStart);
}, duration: commonDuration);
}
void updateController() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (isStart && mounted) {
_controller.forward();
} else {
_controller.reverse();
}
});
}
@override
Widget build(BuildContext context) {
final state = ref.watch(startButtonSelectorStateProvider);
if (!state.isInit || !state.hasProfile) {
return Container();
}
return Theme(
data: Theme.of(context).copyWith(
floatingActionButtonTheme: FloatingActionButtonThemeData(
sizeConstraints: BoxConstraints(minWidth: 56, maxWidth: 200),
),
),
child: AnimatedBuilder(
animation: _controller.view,
builder: (_, child) {
final textWidth =
globalState.measure
.computeTextSize(
Text(
utils.getTimeDifference(DateTime.now()),
style: context.textTheme.titleMedium?.toSoftBold,
),
)
.width +
16;
return FloatingActionButton(
clipBehavior: Clip.antiAlias,
materialTapTargetSize: MaterialTapTargetSize.padded,
heroTag: null,
onPressed: () {
handleSwitchStart();
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 56,
width: 56,
alignment: Alignment.center,
child: AnimatedIcon(
icon: AnimatedIcons.play_pause,
progress: _animation,
),
),
SizedBox(width: textWidth * _animation.value, child: child!),
],
),
);
},
child: Consumer(
builder: (_, ref, _) {
final runTime = ref.watch(runTimeProvider);
final text = utils.getTimeText(runTime);
return Text(
text,
maxLines: 1,
overflow: TextOverflow.visible,
style: Theme.of(context).textTheme.titleMedium?.toSoftBold
.copyWith(color: context.colorScheme.onPrimaryContainer),
);
},
),
),
);
}
}