Files
MWClash/lib/views/dashboard/widgets/start_button.dart
chen08209 4370df6a61 Add sqlite store
Optimize android quick action

Optimize backup and restore

Optimize more details
2026-01-26 18:51:44 +08:00

139 lines
4.0 KiB
Dart

import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/controller.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/providers/database.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 {
AnimationController? _controller;
late Animation<double> _animation;
bool isStart = false;
@override
void initState() {
super.initState();
isStart = ref.read(isStartProvider);
_controller = AnimationController(
vsync: this,
value: isStart ? 1 : 0,
duration: const Duration(milliseconds: 200),
);
_animation = CurvedAnimation(
parent: _controller!,
curve: Curves.easeOutBack,
);
ref.listenManual(isStartProvider, (prev, next) {
if (next != isStart) {
isStart = next;
updateController();
}
}, fireImmediately: true);
}
@override
void dispose() {
_controller?.dispose();
_controller = null;
super.dispose();
}
void handleSwitchStart() {
isStart = !isStart;
updateController();
debouncer.call(FunctionTag.updateStatus, () {
appController.updateStatus(isStart, isInit: !ref.read(initProvider));
}, duration: commonDuration);
}
void updateController() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (isStart && mounted) {
_controller?.forward();
} else {
_controller?.reverse();
}
});
}
@override
Widget build(BuildContext context) {
final hasProfile = ref.watch(
profilesProvider.select((state) => state.isNotEmpty),
);
final isInit = ref.watch(coreInitProvider);
if (!hasProfile || !isInit) {
return Container();
}
return Theme(
data: Theme.of(context).copyWith(
floatingActionButtonTheme: Theme.of(context).floatingActionButtonTheme
.copyWith(
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),
);
},
),
),
);
}
}