Files
MWClash/lib/widgets/card.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

243 lines
6.6 KiB
Dart

import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/widgets/fade_box.dart';
import 'package:flutter/material.dart';
import 'text.dart';
class Info {
final String label;
final IconData? iconData;
const Info({required this.label, this.iconData});
}
class InfoHeader extends StatelessWidget {
final Info info;
final List<Widget> actions;
final EdgeInsetsGeometry? padding;
const InfoHeader({
super.key,
required this.info,
this.padding,
List<Widget>? actions,
}) : actions = actions ?? const [];
@override
Widget build(BuildContext context) {
return Padding(
padding: padding ?? baseInfoEdgeInsets,
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 1,
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
if (info.iconData != null) ...[
Icon(
info.iconData,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
const SizedBox(width: 8),
],
Flexible(
flex: 1,
child: TooltipText(
text: Text(
info.label,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.titleSmall?.copyWith(
color: context.colorScheme.onSurfaceVariant,
),
),
),
),
],
),
),
const SizedBox(width: 8),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [...actions],
),
],
),
);
}
}
class CommonCard extends StatelessWidget {
const CommonCard({
super.key,
bool? isSelected,
this.type = CommonCardType.plain,
this.onPressed,
this.selectWidget,
this.radius = 12,
required this.child,
this.padding,
this.enterAnimated = false,
this.info,
}) : isSelected = isSelected ?? false;
final bool enterAnimated;
final bool isSelected;
final void Function()? onPressed;
final Widget? selectWidget;
final Widget child;
final EdgeInsets? padding;
final Info? info;
final CommonCardType type;
final double radius;
// final WidgetStateProperty<Color?>? backgroundColor;
// final WidgetStateProperty<BorderSide?>? borderSide;
BorderSide getBorderSide(BuildContext context, Set<WidgetState> states) {
final colorScheme = context.colorScheme;
if (type == CommonCardType.filled) {
return BorderSide.none;
}
final hoverColor = isSelected
? colorScheme.primary.opacity80
: colorScheme.primary.opacity60;
if (states.contains(WidgetState.hovered) ||
states.contains(WidgetState.focused) ||
states.contains(WidgetState.pressed)) {
return BorderSide(color: hoverColor);
}
return BorderSide(
color: isSelected
? colorScheme.primary
: colorScheme.surfaceContainerHighest,
);
}
Color? getBackgroundColor(BuildContext context, Set<WidgetState> states) {
final colorScheme = context.colorScheme;
if (type == CommonCardType.filled) {
if (isSelected) {
return colorScheme.secondaryContainer.opacity80;
}
return colorScheme.surfaceContainerHigh;
}
if (isSelected) {
return colorScheme.secondaryContainer;
}
return colorScheme.surfaceContainerLow;
}
Color? getForegroundColor(BuildContext context, Set<WidgetState> states) {
final colorScheme = context.colorScheme;
if (type == CommonCardType.filled) {
if (isSelected) {
return colorScheme.onSecondaryContainer;
}
return colorScheme.onSurfaceVariant;
}
if (isSelected) {
return colorScheme.onSecondaryContainer;
}
return colorScheme.onSurfaceVariant;
}
@override
Widget build(BuildContext context) {
var childWidget = child;
if (info != null) {
childWidget = Column(
mainAxisSize: MainAxisSize.min,
children: [
InfoHeader(
padding: baseInfoEdgeInsets.copyWith(bottom: 0),
info: info!,
),
Flexible(flex: 1, child: child),
],
);
}
if (selectWidget != null && isSelected) {
final List<Widget> children = [];
children.add(childWidget);
children.add(Positioned.fill(child: selectWidget!));
childWidget = Stack(children: children);
}
final card = OutlinedButton(
onLongPress: null,
clipBehavior: Clip.antiAlias,
style: ButtonStyle(
padding: const WidgetStatePropertyAll(EdgeInsets.zero),
shape: WidgetStatePropertyAll(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(radius)),
),
iconColor: WidgetStatePropertyAll(context.colorScheme.primary),
iconSize: WidgetStateProperty.all(20),
backgroundColor: WidgetStateProperty.resolveWith(
(states) => getBackgroundColor(context, states),
),
foregroundColor: WidgetStateProperty.resolveWith(
(states) => getForegroundColor(context, states),
),
side: WidgetStateProperty.resolveWith(
(states) => getBorderSide(context, states),
),
),
onPressed: onPressed,
child: childWidget,
);
return switch (enterAnimated) {
true => FadeScaleEnterBox(child: card),
false => card,
};
}
}
class SelectIcon extends StatelessWidget {
const SelectIcon({super.key});
@override
Widget build(BuildContext context) {
return Material(
color: Theme.of(context).colorScheme.inversePrimary,
shape: const CircleBorder(),
child: Container(
padding: const EdgeInsets.all(4),
child: const Icon(Icons.check, size: 16),
),
);
}
}
class SettingsBlock extends StatelessWidget {
final String title;
final List<Widget> settings;
const SettingsBlock({super.key, required this.title, required this.settings});
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(8),
child: Column(
children: [
InfoHeader(info: Info(label: title)),
Card(
color: context.colorScheme.surfaceContainer,
child: Column(children: settings),
),
],
),
);
}
}