kasy-cli 1.39.1 → 1.40.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/scaffold/CHANGELOG.json +23 -0
- package/package.json +1 -1
- package/templates/firebase/.firebase/hosting.YnVpbGQvd2Vi.cache +27 -27
- package/templates/firebase/lib/components/components.dart +2 -0
- package/templates/firebase/lib/components/kasy_accordion.dart +4 -1
- package/templates/firebase/lib/components/kasy_alert.dart +5 -2
- package/templates/firebase/lib/components/kasy_bottom_sheet.dart +25 -7
- package/templates/firebase/lib/components/kasy_dialog.dart +3 -1
- package/templates/firebase/lib/components/kasy_menu.dart +926 -0
- package/templates/firebase/lib/components/kasy_popover.dart +267 -0
- package/templates/firebase/lib/components/kasy_sidebar.dart +20 -10
- package/templates/firebase/lib/core/navigation/kasy_route_observer.dart +8 -0
- package/templates/firebase/lib/features/home/home_components_page.dart +23 -4
- package/templates/firebase/lib/features/home/home_components_preview_registry.dart +320 -0
- package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +38 -94
- package/templates/firebase/lib/features/settings/ui/components/language_switcher.dart +32 -107
- package/templates/firebase/lib/features/subscriptions/ui/widgets/comparison_table.dart +21 -21
- package/templates/firebase/lib/features/subscriptions/ui/widgets/premium_close_button.dart +35 -27
- package/templates/firebase/lib/features/subscriptions/ui/widgets/selectable_col.dart +22 -17
- package/templates/firebase/lib/features/subscriptions/ui/widgets/selectable_row.dart +12 -7
- package/templates/firebase/lib/router.dart +2 -0
- package/templates/firebase/pubspec.yaml +1 -1
- package/templates/firebase/lib/features/subscriptions/ui/widgets/premium_banner.dart +0 -81
|
@@ -137,30 +137,30 @@ class _ComparisonTable extends StatelessWidget {
|
|
|
137
137
|
return const SizedBox.shrink();
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
// Flat bordered surface (no elevation), clipped to the rounded shape so the
|
|
141
|
+
// tinted header corners follow the radius. No Material wrapper: the Container
|
|
142
|
+
// paints the surface, border and radius itself.
|
|
143
|
+
return ClipRRect(
|
|
141
144
|
borderRadius: KasyRadius.lgBorderRadius,
|
|
142
|
-
child:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
border: Border.all(
|
|
149
|
-
color: context.colors.onBackground.withValues(alpha: 0.3),
|
|
150
|
-
),
|
|
145
|
+
child: Container(
|
|
146
|
+
decoration: BoxDecoration(
|
|
147
|
+
color: context.colors.surface,
|
|
148
|
+
borderRadius: KasyRadius.lgBorderRadius,
|
|
149
|
+
border: Border.all(
|
|
150
|
+
color: context.colors.onBackground.withValues(alpha: 0.3),
|
|
151
151
|
),
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
152
|
+
),
|
|
153
|
+
child: Column(
|
|
154
|
+
children: [
|
|
155
|
+
_buildHeader(context),
|
|
156
|
+
...rows.asMap().entries.map(
|
|
157
|
+
(entry) => _buildRow(
|
|
158
|
+
context,
|
|
159
|
+
entry.value,
|
|
160
|
+
isLast: entry.key == rows.length - 1,
|
|
161
161
|
),
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
),
|
|
163
|
+
],
|
|
164
164
|
),
|
|
165
165
|
),
|
|
166
166
|
);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import 'package:flutter/material.dart';
|
|
2
2
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
3
3
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
4
|
-
import 'package:kasy_kit/core/widgets/
|
|
4
|
+
import 'package:kasy_kit/core/widgets/kasy_pressable_depth.dart';
|
|
5
|
+
import 'package:kasy_kit/i18n/translations.g.dart';
|
|
5
6
|
|
|
6
7
|
class AppCloseButtonComponent extends ConsumerWidget {
|
|
7
8
|
final ValueNotifier<bool> showCloseBtn;
|
|
@@ -36,34 +37,41 @@ class AppCloseButton extends StatelessWidget {
|
|
|
36
37
|
@override
|
|
37
38
|
Widget build(BuildContext context) {
|
|
38
39
|
final VoidCallback? onClose = onTap;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
decoration: BoxDecoration(
|
|
54
|
-
shape: BoxShape.circle,
|
|
55
|
-
color: context.colors.onBackground.withValues(alpha: 0.6),
|
|
56
|
-
),
|
|
57
|
-
child: Center(
|
|
58
|
-
child: Icon(
|
|
59
|
-
KasyIcons.close,
|
|
60
|
-
color: context.colors.background,
|
|
61
|
-
size: KasyIconSize.lg,
|
|
62
|
-
),
|
|
63
|
-
),
|
|
64
|
-
),
|
|
40
|
+
|
|
41
|
+
// Dark translucent scrim keeps the glyph readable over any hero image.
|
|
42
|
+
final Widget circle = Container(
|
|
43
|
+
width: 32,
|
|
44
|
+
height: 32,
|
|
45
|
+
decoration: BoxDecoration(
|
|
46
|
+
shape: BoxShape.circle,
|
|
47
|
+
color: context.colors.onBackground.withValues(alpha: 0.6),
|
|
48
|
+
),
|
|
49
|
+
child: Center(
|
|
50
|
+
child: Icon(
|
|
51
|
+
KasyIcons.close,
|
|
52
|
+
color: context.colors.background,
|
|
53
|
+
size: KasyIconSize.lg,
|
|
65
54
|
),
|
|
66
55
|
),
|
|
67
56
|
);
|
|
57
|
+
|
|
58
|
+
// Disabled (no handler): render the inert scrim, no interaction.
|
|
59
|
+
if (onClose == null) {
|
|
60
|
+
return circle;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// KasyPressableDepth gives the kit's press-in depth, a web hover highlight
|
|
64
|
+
// and a keyboard focus ring (no Material ripple), plus a 44x44 tap target
|
|
65
|
+
// around the 32px visual. A light veil lifts the dark scrim on hover/press.
|
|
66
|
+
final BorderRadius pill = BorderRadius.circular(999);
|
|
67
|
+
return KasyPressableDepth(
|
|
68
|
+
onPressed: onClose,
|
|
69
|
+
semanticLabel: t.common.close,
|
|
70
|
+
focusable: true,
|
|
71
|
+
clipBorderRadius: pill,
|
|
72
|
+
focusBorderRadius: pill,
|
|
73
|
+
pressOverlayColor: context.colors.background.withValues(alpha: 0.2),
|
|
74
|
+
child: circle,
|
|
75
|
+
);
|
|
68
76
|
}
|
|
69
77
|
}
|
|
@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
|
|
4
4
|
import 'package:flutter_animate/flutter_animate.dart';
|
|
5
5
|
import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
|
|
6
6
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
7
|
-
import 'package:kasy_kit/core/widgets/
|
|
7
|
+
import 'package:kasy_kit/core/widgets/kasy_hover.dart';
|
|
8
8
|
import 'package:kasy_kit/features/subscriptions/ui/widgets/selectable_row.dart';
|
|
9
9
|
|
|
10
10
|
|
|
@@ -65,24 +65,29 @@ class _SelectableColGroupState<T> extends State<SelectableColGroup<T>> {
|
|
|
65
65
|
children: [
|
|
66
66
|
for (var i = 0; i < widget.items.length; i++)
|
|
67
67
|
Expanded(
|
|
68
|
-
child:
|
|
69
|
-
|
|
68
|
+
child: KasyHover(
|
|
69
|
+
onTap: () => _selectIndex(i),
|
|
70
|
+
focusable: true,
|
|
70
71
|
borderRadius: KasyRadius.lgBorderRadius,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
selected: selectedIndex == i,
|
|
84
|
-
brightness: widget.brightness,
|
|
72
|
+
// The card paints its own animated selection border, so suppress
|
|
73
|
+
// the hover/press fill: KasyHover only adds the web click cursor
|
|
74
|
+
// and the keyboard focus ring. The heavy selection haptic is
|
|
75
|
+
// fired by _selectIndex, so opt out of the default tap haptic.
|
|
76
|
+
hapticEnabled: false,
|
|
77
|
+
hoverEnabled: false,
|
|
78
|
+
pressEnabled: false,
|
|
79
|
+
child: Animate(
|
|
80
|
+
effects: [
|
|
81
|
+
FadeEffect(
|
|
82
|
+
delay: Duration(milliseconds: 100 + 100 * i),
|
|
83
|
+
duration: const Duration(milliseconds: 500),
|
|
85
84
|
),
|
|
85
|
+
],
|
|
86
|
+
child: SelectableCol.fromOption(
|
|
87
|
+
key: ValueKey('item_$i'),
|
|
88
|
+
widget.items[i],
|
|
89
|
+
selected: selectedIndex == i,
|
|
90
|
+
brightness: widget.brightness,
|
|
86
91
|
),
|
|
87
92
|
),
|
|
88
93
|
),
|
|
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|
|
2
2
|
import 'package:flutter_animate/flutter_animate.dart';
|
|
3
3
|
import 'package:kasy_kit/core/haptics/kasy_haptics.dart';
|
|
4
4
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
5
|
-
import 'package:kasy_kit/core/widgets/
|
|
5
|
+
import 'package:kasy_kit/core/widgets/kasy_hover.dart';
|
|
6
6
|
|
|
7
7
|
typedef OnSelectItem<T> = void Function(T data);
|
|
8
8
|
|
|
@@ -51,12 +51,18 @@ class _SelectableRowGroupState<T> extends State<SelectableRowGroup<T>> {
|
|
|
51
51
|
return Column(
|
|
52
52
|
children: [
|
|
53
53
|
for (var i = 0; i < widget.items.length; i++)
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
KasyHover(
|
|
55
|
+
onTap: () => _selectIndex(i),
|
|
56
|
+
focusable: true,
|
|
56
57
|
borderRadius: KasyRadius.mdBorderRadius,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
// The card paints its own animated selection border, so suppress the
|
|
59
|
+
// hover/press fill: KasyHover only contributes the web click cursor
|
|
60
|
+
// and the keyboard focus ring. The heavy selection haptic is fired
|
|
61
|
+
// by _selectIndex, so opt out of the default tap haptic.
|
|
62
|
+
hapticEnabled: false,
|
|
63
|
+
hoverEnabled: false,
|
|
64
|
+
pressEnabled: false,
|
|
65
|
+
child: Padding(
|
|
60
66
|
padding: EdgeInsets.only(
|
|
61
67
|
bottom: i == widget.items.length - 1 ? 0 : KasySpacing.sm,
|
|
62
68
|
),
|
|
@@ -75,7 +81,6 @@ class _SelectableRowGroupState<T> extends State<SelectableRowGroup<T>> {
|
|
|
75
81
|
),
|
|
76
82
|
),
|
|
77
83
|
),
|
|
78
|
-
),
|
|
79
84
|
),
|
|
80
85
|
],
|
|
81
86
|
);
|
|
@@ -9,6 +9,7 @@ import 'package:kasy_kit/core/data/api/analytics_api.dart';
|
|
|
9
9
|
import 'package:kasy_kit/core/data/models/user.dart';
|
|
10
10
|
import 'package:kasy_kit/core/navigation/kasy_navigation_config.dart';
|
|
11
11
|
import 'package:kasy_kit/core/navigation/kasy_page_transition.dart';
|
|
12
|
+
import 'package:kasy_kit/core/navigation/kasy_route_observer.dart';
|
|
12
13
|
import 'package:kasy_kit/core/security/biometric_guard.dart';
|
|
13
14
|
import 'package:kasy_kit/core/shared_preferences/shared_preferences.dart';
|
|
14
15
|
import 'package:kasy_kit/core/states/user_state_notifier.dart';
|
|
@@ -156,6 +157,7 @@ GoRouter generateRouter({
|
|
|
156
157
|
observers: [
|
|
157
158
|
AnalyticsObserver(analyticsApi: MixpanelAnalyticsApi.instance()),
|
|
158
159
|
KasyChromeVisibilityObserver(),
|
|
160
|
+
kasyRouteObserver,
|
|
159
161
|
|
|
160
162
|
...?observers,
|
|
161
163
|
],
|
|
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|
|
16
16
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
|
17
17
|
# In Windows, build-name is used as the major, minor, and patch parts
|
|
18
18
|
# of the product and file versions while build-number is used as the build suffix.
|
|
19
|
-
version: 1.0.0+
|
|
19
|
+
version: 1.0.0+70
|
|
20
20
|
|
|
21
21
|
environment:
|
|
22
22
|
sdk: ^3.11.0
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import 'package:flutter/material.dart';
|
|
2
|
-
import 'package:kasy_kit/core/theme/theme.dart';
|
|
3
|
-
import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
|
|
4
|
-
|
|
5
|
-
typedef PremiumWideBannerOnTap = void Function();
|
|
6
|
-
|
|
7
|
-
class PremiumWideBanner extends StatelessWidget {
|
|
8
|
-
final Color bgColor;
|
|
9
|
-
final String imagePath;
|
|
10
|
-
final String smallText;
|
|
11
|
-
final String title;
|
|
12
|
-
final PremiumWideBannerOnTap onTap;
|
|
13
|
-
|
|
14
|
-
const PremiumWideBanner({
|
|
15
|
-
super.key,
|
|
16
|
-
required this.bgColor,
|
|
17
|
-
required this.imagePath,
|
|
18
|
-
required this.smallText,
|
|
19
|
-
required this.title,
|
|
20
|
-
required this.onTap,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
@override
|
|
24
|
-
Widget build(BuildContext context) {
|
|
25
|
-
return LayoutBuilder(builder: (context, constraints) {
|
|
26
|
-
return Material(
|
|
27
|
-
color: Colors.transparent,
|
|
28
|
-
child: Ink(
|
|
29
|
-
// height: 116,
|
|
30
|
-
width: constraints.maxWidth,
|
|
31
|
-
decoration: BoxDecoration(
|
|
32
|
-
color: bgColor,
|
|
33
|
-
// border: Border.all(color: borderColor),
|
|
34
|
-
),
|
|
35
|
-
child: KasyFocusRing(
|
|
36
|
-
onActivate: () => onTap(),
|
|
37
|
-
borderRadius: BorderRadius.zero,
|
|
38
|
-
child: InkWell(
|
|
39
|
-
canRequestFocus: false,
|
|
40
|
-
onTap: () => onTap(),
|
|
41
|
-
child: Row(
|
|
42
|
-
children: [
|
|
43
|
-
Image.asset(
|
|
44
|
-
imagePath,
|
|
45
|
-
width: constraints.maxWidth * 0.32,
|
|
46
|
-
// height: 116,
|
|
47
|
-
fit: BoxFit.cover,
|
|
48
|
-
),
|
|
49
|
-
const SizedBox(width: KasySpacing.lg),
|
|
50
|
-
Expanded(
|
|
51
|
-
child: Column(
|
|
52
|
-
crossAxisAlignment: CrossAxisAlignment.start,
|
|
53
|
-
mainAxisAlignment: MainAxisAlignment.center,
|
|
54
|
-
children: [
|
|
55
|
-
Text(
|
|
56
|
-
smallText.toUpperCase(),
|
|
57
|
-
style: context.kasyTextTheme.sectionLabel.copyWith(
|
|
58
|
-
color: context.colors.premiumBannerText,
|
|
59
|
-
),
|
|
60
|
-
),
|
|
61
|
-
const SizedBox(height: KasySpacing.sm),
|
|
62
|
-
Text(
|
|
63
|
-
title,
|
|
64
|
-
style: context.textTheme.titleLarge?.copyWith(
|
|
65
|
-
color: context.colors.onPrimary,
|
|
66
|
-
),
|
|
67
|
-
overflow: TextOverflow.clip,
|
|
68
|
-
),
|
|
69
|
-
],
|
|
70
|
-
),
|
|
71
|
-
),
|
|
72
|
-
const SizedBox(width: KasySpacing.lg),
|
|
73
|
-
],
|
|
74
|
-
),
|
|
75
|
-
),
|
|
76
|
-
),
|
|
77
|
-
),
|
|
78
|
-
);
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|