المصدر المنشور
تنزيل الشيفرة المصدرية بصيغة ZIP
CH-J SM Mobile
تصفّح الأدلة والملفات الخاصة بإصدار محدد من التطبيق.
CH-J / SM Mobile
175 ملفات
sm-mobile-20261016T185235Z-8e93ecc1b59a
تاريخ الإضافة: · تاريخ البناء:
1
import 'package:flutter/material.dart';3
/// Colors and shapes shared with the CH-J Server Manager desktop app4
/// (app/src/renderer/styles.css), so both products look like one family.5
abstract final class Brand {6
static const background = Color(0xff07111f);7
static const panel = Color(0xff102033);8
static const input = Color(0xff0b1929);9
static const navigation = Color(0xff050e19);10
static const terminal = Color(0xff050b12);11
static const line = Color(0x29b0c4dd); // rgba(151, 176, 205, .16)12
static const text = Color(0xffecf5ff);13
static const muted = Color(0xff8ea5bf);14
static const blue = Color(0xff42a5ff);15
static const green = Color(0xff43d6a0);16
static const violet = Color(0xff9d7bff);17
static const amber = Color(0xffffd082);18
static const red = Color(0xffff9a9a);20
static const lightBackground = Color(0xfff4f7fb);21
static const lightLine = Color(0xffccd8e4);22
static const lightMuted = Color(0xff53687d);24
static const cardRadius = 17.0, fieldRadius = 9.0, buttonRadius = 10.0;25
}27
ThemeData buildTheme(Brightness brightness) {28
final dark = brightness == Brightness.dark;29
final seeded = ColorScheme.fromSeed(30
seedColor: Brand.blue,31
brightness: brightness,32
);33
final scheme = dark34
? seeded.copyWith(35
primary: Brand.blue,36
// White on #42a5ff is 2.6:1; dark navy is 7.25:1 (WCAG AA).37
onPrimary: const Color(0xff04121f),38
secondary: Brand.green,39
tertiary: Brand.violet,40
surface: Brand.background,41
onSurface: Brand.text,42
onSurfaceVariant: Brand.muted,43
surfaceContainerLowest: Brand.terminal,44
surfaceContainerLow: Brand.input,45
surfaceContainer: Brand.panel,46
surfaceContainerHigh: Brand.panel,47
surfaceContainerHighest: const Color(0xff16304a),48
outline: const Color(0x52b0c4dd),49
outlineVariant: Brand.line,50
error: Brand.red,51
)52
: seeded.copyWith(53
// 5.75:1 against white text (WCAG AA).54
primary: const Color(0xff1565c0),55
outlineVariant: Brand.lightLine,56
onSurfaceVariant: Brand.lightMuted,57
);58
final line = dark ? Brand.line : Brand.lightLine;59
OutlineInputBorder field(Color color, [double width = 1]) =>60
OutlineInputBorder(61
borderRadius: BorderRadius.circular(Brand.fieldRadius),62
borderSide: BorderSide(color: color, width: width),63
);64
final buttonShape = RoundedRectangleBorder(65
borderRadius: BorderRadius.circular(Brand.buttonRadius),66
);67
return ThemeData(68
useMaterial3: true,69
brightness: brightness,70
colorScheme: scheme,71
scaffoldBackgroundColor: dark ? Brand.background : Brand.lightBackground,72
dividerTheme: DividerThemeData(color: line, space: 1, thickness: 1),73
appBarTheme: AppBarTheme(74
backgroundColor: dark ? Brand.background : Brand.lightBackground,75
surfaceTintColor: Colors.transparent,76
scrolledUnderElevation: 0,77
shape: Border(bottom: BorderSide(color: line)),78
),79
inputDecorationTheme: InputDecorationTheme(80
filled: true,81
fillColor: dark ? Brand.input : Colors.white,82
border: field(line),83
enabledBorder: field(line),84
focusedBorder: field(scheme.primary.withValues(alpha: .65), 1.5),85
errorBorder: field(scheme.error),86
labelStyle: TextStyle(color: scheme.onSurfaceVariant),87
),88
cardTheme: CardThemeData(89
margin: const EdgeInsets.symmetric(vertical: 5),90
elevation: 0,91
color: dark ? Brand.panel : Colors.white,92
surfaceTintColor: Colors.transparent,93
shape: RoundedRectangleBorder(94
borderRadius: BorderRadius.circular(Brand.cardRadius),95
side: BorderSide(color: line),96
),97
),98
filledButtonTheme: FilledButtonThemeData(99
style: FilledButton.styleFrom(100
shape: buttonShape,101
minimumSize: const Size(48, 48),102
),103
),104
outlinedButtonTheme: OutlinedButtonThemeData(105
style: OutlinedButton.styleFrom(106
shape: buttonShape,107
minimumSize: const Size(48, 48),108
foregroundColor: dark ? const Color(0xffd9eaff) : null,109
backgroundColor: dark ? const Color(0x0bffffff) : null,110
side: BorderSide(111
color: dark ? const Color(0x387a9cbe) : Brand.lightLine,112
),113
),114
),115
segmentedButtonTheme: SegmentedButtonThemeData(116
style: SegmentedButton.styleFrom(117
shape: buttonShape,118
side: BorderSide(color: line),119
selectedBackgroundColor: Brand.blue.withValues(alpha: .18),120
selectedForegroundColor: dark ? Colors.white : null,121
),122
),123
navigationBarTheme: NavigationBarThemeData(124
backgroundColor: dark ? Brand.navigation : null,125
indicatorColor: Brand.blue.withValues(alpha: .2),126
surfaceTintColor: Colors.transparent,127
),128
navigationRailTheme: NavigationRailThemeData(129
backgroundColor: dark ? Brand.navigation : null,130
indicatorColor: Brand.blue.withValues(alpha: .2),131
selectedIconTheme: const IconThemeData(color: Brand.blue),132
),133
bottomSheetTheme: BottomSheetThemeData(134
backgroundColor: dark ? Brand.panel : null,135
surfaceTintColor: Colors.transparent,136
),137
dialogTheme: DialogThemeData(138
backgroundColor: dark ? Brand.panel : null,139
surfaceTintColor: Colors.transparent,140
),141
popupMenuTheme: PopupMenuThemeData(142
color: dark ? Brand.panel : null,143
surfaceTintColor: Colors.transparent,144
),145
progressIndicatorTheme: ProgressIndicatorThemeData(146
color: Brand.blue,147
linearTrackColor: line,148
),149
);150
}152
/// The desktop's page header: a small blue eyebrow above the title.153
class PageTitle extends StatelessWidget {154
final String eyebrow, title;155
const PageTitle(this.eyebrow, this.title, {super.key});156
@override157
Widget build(BuildContext context) => Column(158
crossAxisAlignment: CrossAxisAlignment.start,159
mainAxisSize: MainAxisSize.min,160
children: [161
Text(162
eyebrow.toUpperCase(),163
maxLines: 1,164
overflow: TextOverflow.ellipsis,165
style: TextStyle(166
color: Theme.of(context).colorScheme.primary,167
fontSize: 10,168
fontWeight: FontWeight.w800,169
letterSpacing: 1.8,170
),171
),172
Text(title, maxLines: 1, overflow: TextOverflow.ellipsis),173
],174
);175
}177
/// The desktop's brand mark: a blue gradient tile with the product initials.178
class BrandMark extends StatelessWidget {179
final double size;180
const BrandMark({this.size = 32, super.key});181
@override182
Widget build(BuildContext context) => ExcludeSemantics(183
child: Container(184
width: size,185
height: size,186
alignment: Alignment.center,187
decoration: BoxDecoration(188
borderRadius: BorderRadius.circular(size * .31),189
gradient: const LinearGradient(190
begin: Alignment.topLeft,191
end: Alignment.bottomRight,192
colors: [Color(0xff3ba7ff), Color(0xff315eff)],193
),194
),195
child: Text(196
'SM',197
style: TextStyle(198
color: Colors.white,199
fontWeight: FontWeight.w800,200
fontSize: size * .34,201
),202
),203
),204
);205
}SHA-256
68ebf8dc50c91c031885fd32a8029b4cc8f9a92218854582c23bcd115840ef58CH-J Proprietary Software License 1.14 · تُتاح الشيفرة المصدرية بموجب CH-J Proprietary Software License 1.14. وإتاحتها لا تغيّر شروط الترخيص ولا تمنح حقوقًا إضافية.
SHA-256 للأرشيف
46e427a43e87af091004f36145590bda8fe90086dfb0f631afeb5029fb0b5655