ops-console v1.0.2 (versionCode 8) 源码入库

This commit is contained in:
txh
2026-09-03 18:01:05 +08:00
commit 685fff27c8
170 changed files with 53049 additions and 0 deletions

355
lib/app/router.dart Normal file
View File

@@ -0,0 +1,355 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../providers/auth_provider.dart';
import '../utils/permissions.dart';
import '../screens/admin/admin_hub_page.dart';
import '../screens/admin/app/app_version_page.dart';
import '../screens/admin/app/tv_app_page.dart';
import '../screens/admin/channel/channel_management_page.dart';
import '../screens/admin/intro/intro_category_page.dart';
import '../screens/admin/intro/intro_store_content_page.dart';
import '../screens/admin/intro/intro_store_list_page.dart';
import '../screens/admin/marquee/marquee_management_page.dart';
import '../screens/admin/media/media_list_page.dart';
import '../screens/admin/media/media_rank_page.dart';
import '../screens/admin/sys/config_page.dart';
import '../screens/admin/sys/log_page.dart';
import '../screens/admin/sys/menu_page.dart';
import '../screens/admin/sys/role_page.dart';
import '../screens/admin/sys/schedule_page.dart';
import '../screens/admin/sys/user_page.dart';
import '../screens/device/device_activation_page.dart';
import '../screens/device/device_group_page.dart';
import '../screens/device/device_scan_page.dart';
import '../screens/device/store_config_page.dart';
import '../screens/home/device_detail_page.dart';
import '../screens/home/device_list_page.dart';
import '../screens/home/home_page.dart';
import '../screens/login/login_page.dart';
import '../models/store_info.dart';
import '../screens/profile/settings_page.dart';
import '../screens/store/org_tree_page.dart';
import '../screens/store/store_detail_page.dart';
import '../screens/store/store_list_page.dart';
import '../widgets/app_bottom_nav.dart';
/// 全局路由配置。
///
/// 路由表:
/// - `/login` 登录页(未登录时重定向到此)
/// - `/` 首页仪表盘(底部导航第 1 个 tab)
/// - `/device` 设备列表(底部导航第 2 个 tab)
/// - `/device/:id` 设备详情
/// - `/device/group` 设备分组
/// - `/device/activation` 激活码管理
/// - `/device/store-config` 门店配置
/// - `/store` 门店管理(底部导航第 3 个 tab)
/// - `/store/org-tree` 组织架构
/// - `/store/:id` 门店详情
/// - `/admin` 管理中心(底部导航第 4 个 tab)
/// - `/admin/sys/*` 系统管理子模块
/// - `/admin/app/*` 应用管理子模块
/// - `/admin/media/*` 媒资管理子模块
/// - `/admin/intro/*` 公司介绍子模块
/// - `/profile` 我的(底部导航第 5 个 tab)
/// - `/profile/settings` 设置
final appRouterProvider = Provider<GoRouter>((ref) {
// 登录态变化时触发路由重定向刷新,而不重建整个 GoRouter。
final refreshNotifier = ValueNotifier<int>(0);
ref
..onDispose(refreshNotifier.dispose)
..listen(authProvider, (_, __) => refreshNotifier.value++);
return GoRouter(
initialLocation: '/',
refreshListenable: refreshNotifier,
redirect: (context, state) {
final auth = ref.read(authProvider);
final loggedIn = auth.isLoggedIn;
final isLoginRoute = state.matchedLocation == '/login';
if (!loggedIn && !isLoginRoute) {
return '/login';
}
if (loggedIn && isLoginRoute) {
return '/';
}
// 功能模块按账号权限收敛(菜单可见性与此处路由可达性由同一套
// [SessionPermissions] 谓词驱动,确保一致):
// - 系统管理中仅 /admin/sys/user(用户管理)对所有已登录账号开放;
// 其余 /admin/sys/*(角色/菜单/配置/日志/定时任务)仅管理员可访问;
// - 媒资 /admin/media/*、应用 /admin/app/*、公司介绍(分类维度)
// /admin/intro/category 仅管理员可见/可访问;
// - 渠道商管理 /admin/channel 对管理员与渠道商开放,代理商不可访问;
// 非管理员(受限账号)即使通过深链/返回键进入上述受限路由也重定向回
// 管理首页,作为入口收敛的兜底,防止越权查看/操作跨组织数据。
// 注:公司介绍门店维度入口(/admin/intro/store-list、/admin/intro/
// store-content/*)按门店维度展示、数据已由 getMyStores 收敛,对所有账号开放。
final loc = state.matchedLocation;
final user = ref.read(authProvider).user;
final cat = SessionPermissions.category(user);
if (cat != AccountCategory.admin) {
final isUserManagement =
loc == '/admin/sys/user' || loc.startsWith('/admin/sys/user/');
final isSysModule = loc.startsWith('/admin/sys') && !isUserManagement;
if (isSysModule ||
loc.startsWith('/admin/media') ||
loc.startsWith('/admin/app') ||
loc.startsWith('/admin/intro/category')) {
return '/admin';
}
// 代理商(非渠道商)访问渠道商管理 → 弹回(其菜单中本就隐藏该入口)。
if (loc.startsWith('/admin/channel') &&
cat != AccountCategory.channelMerchant) {
return '/admin';
}
}
return null;
},
routes: [
GoRoute(
path: '/login',
name: 'login',
builder: (context, state) => const LoginPage(),
),
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) =>
AppBottomNav(shell: navigationShell),
branches: [
// 首页(仪表盘)
StatefulShellBranch(
routes: [
GoRoute(
path: '/',
name: 'home',
builder: (context, state) => const HomePage(),
),
],
),
// 设备
StatefulShellBranch(
routes: [
GoRoute(
path: '/device',
name: 'device',
builder: (context, state) => const DeviceListPage(),
routes: [
// 具名子路由(group/activation/store-config/scan)必须放在参数路由 :id 之前,
// 否则 `/device/scan` 会被 `:id` 匹配成设备 ID="scan",导致进入错误的详情页。
GoRoute(
path: 'group',
name: 'deviceGroup',
builder: (context, state) => const DeviceGroupPage(),
),
GoRoute(
path: 'activation',
name: 'deviceActivation',
builder: (context, state) =>
const DeviceActivationPage(),
),
GoRoute(
path: 'store-config',
name: 'storeConfig',
builder: (context, state) => const StoreConfigPage(),
),
GoRoute(
path: 'scan',
name: 'deviceScan',
builder: (context, state) {
final mode =
state.uri.queryParameters['mode'] ?? 'query';
final deviceId =
state.uri.queryParameters['deviceId'];
final storeId =
state.uri.queryParameters['storeId'];
final storeName =
state.uri.queryParameters['storeName'];
final groupId =
state.uri.queryParameters['groupId'];
return DeviceScanPage(
mode: mode,
deviceId: deviceId,
storeId: storeId,
storeName: storeName,
groupId: groupId,
);
},
),
GoRoute(
path: ':id',
name: 'deviceDetail',
builder: (context, state) {
final id = state.pathParameters['id'] ?? '';
return DeviceDetailPage(deviceId: id);
},
),
],
),
],
),
// 门店
StatefulShellBranch(
routes: [
GoRoute(
path: '/store',
name: 'store',
builder: (context, state) => const StoreListPage(),
routes: [
GoRoute(
path: 'org-tree',
name: 'orgTree',
builder: (context, state) => const OrgTreePage(),
),
GoRoute(
path: ':id',
name: 'storeDetail',
builder: (context, state) {
final id = state.pathParameters['id'] ?? '';
return StoreDetailPage(storeId: id);
},
),
],
),
],
),
// 管理
StatefulShellBranch(
routes: [
GoRoute(
path: '/admin',
name: 'admin',
builder: (context, state) => const AdminHubPage(),
routes: [
// 管理模块内的设备/激活码别名路由:复用设备分支的页面组件,
// 但在 /admin 分支栈下 push,使底部导航仍停留「管理」tab,
// 返回键可正常 pop 回管理首页,避免此前 push 到 /device 分支栈导致的返回键异常。
GoRoute(
path: 'device',
name: 'adminDevice',
builder: (context, state) => const DeviceListPage(),
),
GoRoute(
path: 'activation',
name: 'adminActivation',
builder: (context, state) =>
const DeviceActivationPage(),
),
// 系统管理
GoRoute(
path: 'sys/user',
name: 'sysUser',
builder: (context, state) => const UserPage(),
),
GoRoute(
path: 'sys/role',
name: 'sysRole',
builder: (context, state) => const RolePage(),
),
GoRoute(
path: 'sys/menu',
name: 'sysMenu',
builder: (context, state) => const MenuPage(),
),
GoRoute(
path: 'sys/config',
name: 'sysConfig',
builder: (context, state) => const ConfigPage(),
),
GoRoute(
path: 'sys/log',
name: 'sysLog',
builder: (context, state) => const LogPage(),
),
GoRoute(
path: 'sys/schedule',
name: 'sysSchedule',
builder: (context, state) => const SchedulePage(),
),
// 应用管理
GoRoute(
path: 'app/version',
name: 'appVersion',
builder: (context, state) => const AppVersionPage(),
),
GoRoute(
path: 'app/tv-app',
name: 'tvApp',
builder: (context, state) => const TvAppPage(),
),
// 滚动字幕管理
GoRoute(
path: 'marquee',
name: 'marqueeManagement',
builder: (context, state) => const MarqueeManagementPage(),
),
// 渠道商管理
GoRoute(
path: 'channel',
name: 'channelManagement',
builder: (context, state) => const ChannelManagementPage(),
),
// 媒资管理
GoRoute(
path: 'media/list',
name: 'mediaList',
builder: (context, state) => const MediaListPage(),
),
GoRoute(
path: 'media/rank',
name: 'mediaRank',
builder: (context, state) => const MediaRankPage(),
),
// 公司介绍(门店维度)
GoRoute(
path: 'intro/store-list',
name: 'introStoreList',
builder: (context, state) => const IntroStoreListPage(),
),
GoRoute(
path: 'intro/store-content/:storeId',
name: 'introStoreContent',
builder: (context, state) {
final storeId = state.pathParameters['storeId'] ?? '';
final store = state.extra is StoreInfo
? state.extra as StoreInfo
: null;
return IntroStoreContentPage(
storeId: storeId,
store: store,
);
},
),
// 公司介绍(原分类维度,保留作为管理备用入口)
GoRoute(
path: 'intro/category',
name: 'introCategory',
builder: (context, state) => const IntroCategoryPage(),
),
],
),
],
),
// 我的
StatefulShellBranch(
routes: [
GoRoute(
path: '/profile',
name: 'profile',
builder: (context, state) => const SettingsPage(),
routes: [
GoRoute(
path: 'settings',
name: 'profileSettings',
builder: (context, state) => const SettingsPage(),
),
],
),
],
),
],
),
],
);
});

423
lib/app/theme.dart Normal file
View File

@@ -0,0 +1,423 @@
import 'package:flutter/material.dart';
/// 应用主题:橙白「双橙策略」,回归并与旧版「云端手机端」视觉延续。
///
/// 设计依据:docs/手机端UI优化方案-v2.md
/// - 行动色 [brandPrimary] (#C2410C) 承载白字(对比度 5.18 ✅),用于主按钮 / 导航选中 / 可点文字。
/// - 品牌亮橙 [brandOrange] (#FF914D) 仅用于大色块 / 渐变 / 图表,绝不配白字(对比度仅 2.23 ❌)。
/// - 辅金 [accentGold] (#FFBE58) 用于高亮 / 星级 / 推荐位。
class AppTheme {
AppTheme._();
/// 行动色(主色)。
static const Color brandPrimary = Color(0xFFC2410C);
/// 品牌亮橙(仅大色块 / 渐变 / 图表)。
static const Color brandOrange = Color(0xFFFF914D);
/// 辅金。
static const Color accentGold = Color(0xFFFFBE58);
static const ColorScheme _light = ColorScheme(
brightness: Brightness.light,
primary: Color(0xFFC2410C),
onPrimary: Color(0xFFFFFFFF),
primaryContainer: Color(0xFFFFD3B3),
onPrimaryContainer: Color(0xFF4A1D00),
secondary: Color(0xFF8A5A3A),
onSecondary: Color(0xFFFFFFFF),
secondaryContainer: Color(0xFFF5DFCB),
onSecondaryContainer: Color(0xFF5A3A22),
tertiary: Color(0xFF9A6000),
onTertiary: Color(0xFFFFFFFF),
tertiaryContainer: Color(0xFFFFE0A3),
onTertiaryContainer: Color(0xFF5C3D00),
error: Color(0xFFB02A20),
onError: Color(0xFFFFFFFF),
errorContainer: Color(0xFFFFDDD8),
onErrorContainer: Color(0xFF7A2A22),
surface: Color(0xFFFCFAF8),
onSurface: Color(0xFF1A1614),
onSurfaceVariant: Color(0xFF6E655C),
surfaceContainerLowest: Color(0xFFFFFFFF),
surfaceContainerLow: Color(0xFFF7F3EF),
surfaceContainer: Color(0xFFF2EDE8),
surfaceContainerHigh: Color(0xFFECE5DF),
surfaceContainerHighest: Color(0xFFE5DED7),
outline: Color(0xFF8A8178),
outlineVariant: Color(0xFFDCCFC2),
shadow: Color(0xFF5C2E12),
scrim: Color(0xFF1A1614),
inverseSurface: Color(0xFF2E2823),
onInverseSurface: Color(0xFFF7EFE9),
inversePrimary: Color(0xFFFFB487),
surfaceTint: Color(0xFFC2410C),
);
static const ColorScheme _dark = ColorScheme(
brightness: Brightness.dark,
primary: Color(0xFFFFB487),
onPrimary: Color(0xFF542000),
primaryContainer: Color(0xFF63300D),
onPrimaryContainer: Color(0xFFFFDCC2),
secondary: Color(0xFFE8C39B),
onSecondary: Color(0xFF542000),
secondaryContainer: Color(0xFF5A3A22),
onSecondaryContainer: Color(0xFFFFDCC2),
tertiary: Color(0xFFF2BE62),
onTertiary: Color(0xFF542000),
tertiaryContainer: Color(0xFF5C3D00),
onTertiaryContainer: Color(0xFFFFDCC2),
error: Color(0xFFFF8474),
onError: Color(0xFF5A1610),
errorContainer: Color(0xFF7A2A22),
onErrorContainer: Color(0xFFFFC9C2),
surface: Color(0xFF16130F),
onSurface: Color(0xFFF3E9E2),
onSurfaceVariant: Color(0xFFC4B8AE),
surfaceContainerLowest: Color(0xFF0F0D0A),
surfaceContainerLow: Color(0xFF1E1A16),
surfaceContainer: Color(0xFF23201B),
surfaceContainerHigh: Color(0xFF2D2924),
surfaceContainerHighest: Color(0xFF38332D),
outline: Color(0xFF7A7068),
outlineVariant: Color(0xFF453F39),
shadow: Color(0xFF000000),
scrim: Color(0xFF0F0D0A),
inverseSurface: Color(0xFFF3E9E2),
onInverseSurface: Color(0xFF2E2823),
inversePrimary: Color(0xFFC2410C),
surfaceTint: Color(0xFFFFB487),
);
/// 浅色主题(橙白品牌主场)。
static ThemeData light() => _base(_light).copyWith(
extensions: const <ThemeExtension<dynamic>>[AppSemanticColors.light],
);
/// 深色主题(暖化 surface,主色提亮为 #FFB487)。
static ThemeData dark() => _base(_dark).copyWith(
extensions: const <ThemeExtension<dynamic>>[AppSemanticColors.dark],
);
static ThemeData _base(ColorScheme scheme) {
return ThemeData(
useMaterial3: true,
brightness: scheme.brightness,
colorScheme: scheme,
scaffoldBackgroundColor: scheme.surface,
// 暖棕低透明阴影,替代默认偏硬的黑色阴影(云感)。
shadowColor: const Color(0x245C2E12),
materialTapTargetSize: MaterialTapTargetSize.padded,
visualDensity: VisualDensity.standard,
extensions: const <ThemeExtension<dynamic>>[],
iconTheme: IconThemeData(
size: AppIconSize.regular,
color: scheme.onSurfaceVariant,
),
appBarTheme: AppBarTheme(
centerTitle: true,
backgroundColor: scheme.surface,
foregroundColor: scheme.onSurface,
elevation: 0,
// 滚动后轻微浮起,呼应云影。
scrolledUnderElevation: 3,
shadowColor: const Color(0x245C2E12),
),
cardTheme: CardTheme(
elevation: 0,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.lg),
),
),
chipTheme: ChipThemeData(
backgroundColor: scheme.surfaceContainerHighest,
labelStyle: TextStyle(color: scheme.onSurface),
selectedColor: scheme.primaryContainer,
checkmarkColor: scheme.onPrimaryContainer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.full),
),
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppRadius.md),
),
filled: true,
fillColor: scheme.surfaceContainerHighest,
labelStyle: TextStyle(color: scheme.onSurfaceVariant),
hintStyle: TextStyle(color: scheme.onSurfaceVariant),
errorStyle: TextStyle(color: scheme.error),
contentPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
snackBarTheme: const SnackBarThemeData(
behavior: SnackBarBehavior.floating,
),
// 全局兜底:30 处 showModalBottomSheet 一次性拿到把手 / 安全区 / 顶部圆角 / 限宽。
bottomSheetTheme: BottomSheetThemeData(
showDragHandle: true,
backgroundColor: scheme.surface,
surfaceTintColor: scheme.surfaceTint,
modalBackgroundColor: scheme.surface,
elevation: 0,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(borderRadius: AppRadius.sheetTop),
constraints: const BoxConstraints(maxWidth: 640),
),
navigationBarTheme: NavigationBarThemeData(
height: 72,
elevation: 0,
backgroundColor: scheme.surfaceContainer,
surfaceTintColor: scheme.surfaceTint,
indicatorColor: scheme.secondaryContainer,
indicatorShape: const StadiumBorder(),
labelBehavior: NavigationDestinationLabelBehavior.alwaysShow,
iconTheme: WidgetStateProperty.resolveWith((states) => IconThemeData(
size: 24,
color: states.contains(WidgetState.selected)
? scheme.onSecondaryContainer
: scheme.onSurfaceVariant,
)),
labelTextStyle: WidgetStateProperty.resolveWith((states) => TextStyle(
fontSize: 12,
fontWeight: states.contains(WidgetState.selected)
? FontWeight.w600
: FontWeight.w500,
color: states.contains(WidgetState.selected)
? scheme.onSurface
: scheme.onSurfaceVariant,
)),
),
navigationRailTheme: NavigationRailThemeData(
backgroundColor: scheme.surfaceContainer,
elevation: 0,
indicatorColor: scheme.secondaryContainer,
indicatorShape: const StadiumBorder(),
minWidth: 72,
groupAlignment: -0.2,
labelType: NavigationRailLabelType.all,
selectedIconTheme:
IconThemeData(size: 24, color: scheme.onSecondaryContainer),
unselectedIconTheme:
IconThemeData(size: 24, color: scheme.onSurfaceVariant),
selectedLabelTextStyle: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: scheme.onSurface,
),
unselectedLabelTextStyle: TextStyle(
fontSize: 12,
color: scheme.onSurfaceVariant,
),
),
dialogTheme: DialogThemeData(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.xxl),
),
backgroundColor: scheme.surfaceContainerLow,
surfaceTintColor: scheme.surfaceTint,
),
iconButtonTheme: IconButtonThemeData(
style: IconButton.styleFrom(
minimumSize: const Size(48, 48),
tapTargetSize: MaterialTapTargetSize.padded,
padding: EdgeInsets.zero,
),
),
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
minimumSize: const Size(64, 52),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.lg),
),
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
minimumSize: const Size(64, 52),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.lg),
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
minimumSize: const Size(64, 52),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.lg),
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.lg),
),
),
),
);
}
}
/// 圆角梯度:非胶囊、四角一致、克制感(呼应 logo ≈3% 圆角)。
class AppRadius {
static const double xs = 4; // 进度条、缩略图角
static const double sm = 8; // Chip、SnackBar、小标签
static const double md = 12; // 输入框(沿用现值,保持手感连续)
static const double lg = 16; // ★ 标准卡片、按钮(主力值)
static const double xl = 20; // 分组容器、大 Banner 卡
static const double xxl = 28; // ★ 底部弹窗顶部两角(云朵弧线核心表达)
static const double full = 999; // 仅状态 Chip / 头像 / pill
/// 底部弹窗顶部两角大圆角、底部直角(云朵上缘多弧、下缘平缓)。
static const BorderRadius sheetTop =
BorderRadius.vertical(top: Radius.circular(xxl));
AppRadius._();
}
/// 云感暖阴影:模糊:偏移 ≈4:1,暖棕而非纯黑。
class AppShadows {
static const List<BoxShadow> xs = [
BoxShadow(
color: Color(0x0F5C2E12),
blurRadius: 8,
offset: Offset(0, 2),
spreadRadius: -1,
),
];
static const List<BoxShadow> sm = [
BoxShadow(
color: Color(0x145C2E12),
blurRadius: 12,
offset: Offset(0, 4),
spreadRadius: -2,
),
];
static const List<BoxShadow> md = [
BoxShadow(
color: Color(0x1A5C2E12),
blurRadius: 20,
offset: Offset(0, 8),
spreadRadius: -4,
),
];
static const List<BoxShadow> lg = [
BoxShadow(
color: Color(0x245C2E12),
blurRadius: 32,
offset: Offset(0, 12),
spreadRadius: -6,
),
];
static const List<BoxShadow> xl = [
BoxShadow(
color: Color(0x245C2E12),
blurRadius: 48,
offset: Offset(0, 20),
spreadRadius: -8,
),
];
/// 深色:暖色阴影在暗底不可见,改用纯黑 + 描边。
static const List<BoxShadow> dark = [
BoxShadow(
color: Color(0x66000000),
blurRadius: 24,
offset: Offset(0, 8),
spreadRadius: -4,
),
];
AppShadows._();
}
/// 图标尺寸栅格(24dp 为默认)。
class AppIconSize {
static const double inline = 16; // 正文行内
static const double dense = 20; // 密集信息行
static const double regular = 24; // ★ 默认:列表 leading、按钮内、AppBar actions
static const double medium = 28; // 卡片强调图标
static const double large = 32; // 列表主 leading
static const double display = 48; // 空状态 / 结果页
static const double hero = 64; // 关于页 logo、引导页
AppIconSize._();
}
/// 品牌视觉常量:logo 云朵橙→金渐变。
class AppBrand {
static const Color cloud = Color(0xFFFF914D); // logo 主色
static const Color cloudGold = Color(0xFFFFBE58); // logo 金黄
static const Color onCloud = Color(0xFF3D1A00); // 亮橙底上的深棕文字(6.99 ✅)
/// logo 橙→金渐变(云朵受光)。
static const LinearGradient cloudGradient = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0xFFFF914D), Color(0xFFFFBE58)],
);
AppBrand._();
}
/// 语义色(成功 / 警告 / 错误 / 信息),通过 ThemeExtension 暴露。
///
/// 警告用琥珀黄而非橙,避免与品牌橙语义打架。
class AppSemanticColors extends ThemeExtension<AppSemanticColors> {
const AppSemanticColors({
required this.success,
required this.successContainer,
required this.onSuccessContainer,
required this.warning,
required this.warningContainer,
required this.onWarningContainer,
required this.info,
required this.infoContainer,
required this.onInfoContainer,
});
final Color success;
final Color successContainer;
final Color onSuccessContainer;
final Color warning;
final Color warningContainer;
final Color onWarningContainer;
final Color info;
final Color infoContainer;
final Color onInfoContainer;
static const light = AppSemanticColors(
success: Color(0xFF1E7A4E),
successContainer: Color(0xFFD3EDDD),
onSuccessContainer: Color(0xFF1E5138),
warning: Color(0xFF8A5C00),
warningContainer: Color(0xFFFFE9B8),
onWarningContainer: Color(0xFF5C4100),
info: Color(0xFF0B6397),
infoContainer: Color(0xFFD7E9FA),
onInfoContainer: Color(0xFF1A4763),
);
static const dark = AppSemanticColors(
success: Color(0xFF5FD398),
successContainer: Color(0xFF1E5138),
onSuccessContainer: Color(0xFFA8E6C4),
warning: Color(0xFFF0BE4E),
warningContainer: Color(0xFF5C4100),
onWarningContainer: Color(0xFFFFDCA8),
info: Color(0xFF7FC4F0),
infoContainer: Color(0xFF1A4763),
onInfoContainer: Color(0xFFB8DCF5),
);
@override
ThemeExtension<AppSemanticColors> copyWith() => this;
@override
ThemeExtension<AppSemanticColors> lerp(
covariant ThemeExtension<AppSemanticColors>? other, double t) =>
other ?? this;
}