dev
dart 200 lines 9.22 KB
Raw
1 import 'package:cake_wallet/generated/i18n.dart';
2 import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
3 import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
4 import 'package:cake_wallet/themes/core/material_base_theme.dart';
5 import 'package:cake_wallet/themes/theme_classes/black_theme.dart';
6 import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
7 import 'package:flutter/material.dart';
8 import 'package:flutter_mobx/flutter_mobx.dart';
9
10 class SettingsThemeChoicesCell extends StatelessWidget {
11 SettingsThemeChoicesCell(this._displaySettingsViewModel);
12
13 final DisplaySettingsViewModel _displaySettingsViewModel;
14
15 final double cellHeight = 12;
16 final double cellWidth = 12;
17 final double cellRadius = 18;
18
19 @override
20 Widget build(BuildContext context) {
21 return Observer(
22 builder: (context) {
23 final availableThemes = _displaySettingsViewModel.availableThemes;
24 final currentTheme = _displaySettingsViewModel.currentTheme;
25 final availableAccentColors = _displaySettingsViewModel.availableAccentColors;
26 final screenHeight = MediaQuery.of(context).size.height;
27
28 final previewHeight = _getResponsivePreviewHeight(screenHeight);
29 final previewWidth = previewHeight * 0.6;
30
31 return AnimatedContainer(
32 duration: const Duration(milliseconds: 350),
33 curve: Curves.easeInOut,
34 height: getHeight(context, currentTheme, currentTheme.hasAccentColors),
35 padding: EdgeInsets.all(14),
36 child: Column(
37 mainAxisSize: MainAxisSize.min,
38 crossAxisAlignment: CrossAxisAlignment.start,
39 children: [
40 SizedBox(
41 height: previewHeight,
42 child: ListView.builder(
43 itemCount: availableThemes.length,
44 scrollDirection: Axis.horizontal,
45 itemBuilder: (context, index) {
46 final MaterialThemeBase theme = availableThemes[index];
47 final isSelected = _displaySettingsViewModel.isThemeSelected(theme);
48
49 return Semantics(
50 label: theme.toString(),
51 selected: isSelected,
52 child: GestureDetector(
53 onTap: () {
54 _displaySettingsViewModel.onThemeSelected(theme);
55 },
56 child: AnimatedContainer(
57 duration: const Duration(milliseconds: 350),
58 curve: Curves.easeInOut,
59 margin: EdgeInsets.only(right: 24),
60 decoration: ShapeDecoration(
61 shape: RoundedSuperellipseBorder(
62 borderRadius: BorderRadius.circular(cellRadius),
63 side: BorderSide(
64 color: isSelected
65 ? Theme.of(context).colorScheme.primary
66 : Colors.transparent,
67 strokeAlign: BorderSide.strokeAlignOutside))),
68 child: ClipRRect(
69 borderRadius: BorderRadius.circular(cellRadius),
70 child: CakeImageWidget(
71 imageUrl: _displaySettingsViewModel.getImageForTheme(theme),
72 fit: BoxFit.cover,
73 height: previewHeight,
74 width: previewWidth,
75 ),
76 ),
77 ),
78 ),
79 );
80 },
81 ),
82 ),
83 AnimatedSwitcher(
84 duration: const Duration(milliseconds: 350),
85 switchInCurve: Curves.easeOut,
86 switchOutCurve: Curves.easeIn,
87 transitionBuilder: (child, animation) => FadeTransition(
88 opacity: animation,
89 child: SizeTransition(
90 sizeFactor: animation,
91 axisAlignment: -1,
92 child: child,
93 ),
94 ),
95 child: _displaySettingsViewModel.currentTheme.hasAccentColors
96 ? Column(
97 key: const ValueKey('accent'),
98 mainAxisSize: MainAxisSize.min,
99 children: [
100 Padding(
101 padding: EdgeInsets.only(top: 14),
102 child: Container(
103 height: 1, color: Theme.of(context).colorScheme.outlineVariant)),
104 SizedBox(height: cellHeight),
105 Row(
106 mainAxisAlignment: MainAxisAlignment.spaceBetween,
107 children: [
108 Text(
109 S.of(context).accent_color,
110 style: Theme.of(context).textTheme.bodyMedium,
111 ),
112 Row(
113 spacing: 4,
114 children: availableAccentColors.map((accentColor) {
115 final isSelected = _displaySettingsViewModel
116 .isAccentColorSelected(accentColor.name.toLowerCase());
117 return GestureDetector(
118 onTap: () {
119 _displaySettingsViewModel
120 .onAccentColorSelected(accentColor.name.toLowerCase());
121 },
122 child: Stack(
123 children: [
124 AnimatedOpacity(
125 duration: Duration(milliseconds: 350),
126 opacity: isSelected ? 1 : 0,
127 child: Container(
128 width: 28,
129 height: 28,
130 decoration: BoxDecoration(
131 borderRadius: BorderRadius.circular(99999999),
132 border: Border.all(
133 color: Theme.of(context)
134 .colorScheme
135 .onSurface))),
136 ),
137 AnimatedScale(
138 duration: Duration(milliseconds: 350),
139 scale: isSelected ? 0.8 : 1,
140 child: Container(
141 width: 28,
142 height: 28,
143 decoration: BoxDecoration(
144 borderRadius: BorderRadius.circular(99999999),
145 color: accentColor.color),
146 ),
147 ),
148 ],
149 ),
150 );
151 }).toList(),
152 ),
153 ],
154 ),
155 ],
156 )
157 : const SizedBox.shrink(key: ValueKey('no-accent')),
158 ),
159 if (_displaySettingsViewModel.currentTheme is BlackTheme)
160 Padding(
161 padding: EdgeInsets.only(top: 12, bottom: 4),
162 child:
163 Container(height: 1, color: Theme.of(context).colorScheme.outlineVariant)),
164 if (_displaySettingsViewModel.currentTheme is BlackTheme)
165 SettingsSwitcherCell(
166 height: 40,
167 title: S.current.oled_mode,
168 value: _displaySettingsViewModel.isBlackThemeOledEnabled,
169 onValueChange: (_, bool value) {
170 _displaySettingsViewModel.setBlackThemeOled(value);
171 },
172 padding: EdgeInsets.zero,
173 switchBackgroundColor: currentTheme.colorScheme.secondaryContainer,
174 ),
175 ],
176 ),
177 );
178 },
179 );
180 }
181
182 double getHeight(BuildContext context, MaterialThemeBase theme, bool hasAccentColors) {
183 final screenHeight = MediaQuery.of(context).size.height;
184
185 double baseHeight = (screenHeight * 0.253).clamp(150.0, screenHeight * 0.5);
186
187 if (hasAccentColors) {
188 baseHeight += (screenHeight * 0.60).clamp(35.0, 60.0);
189 }
190
191 if (theme is BlackTheme) {
192 baseHeight += (screenHeight * 0.059).clamp(48.0, 96.0);
193 }
194
195 return baseHeight;
196 }
197
198 double _getResponsivePreviewHeight(double screenHeight) =>
199 (screenHeight * 0.22).clamp(160.0, 240.0);
200 }