kasy-cli 1.19.1 → 1.20.0
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/bin/kasy.js +1 -0
- package/lib/commands/new.js +9 -0
- package/lib/commands/run.js +22 -6
- package/lib/scaffold/backends/firebase/setup-from-scratch.js +91 -2
- package/lib/scaffold/engine.js +5 -0
- package/lib/scaffold/generate.js +4 -0
- package/lib/scaffold/shared/generator-utils.js +38 -1
- package/lib/utils/flutter-run.js +16 -4
- package/lib/utils/i18n/messages-en.js +2 -1
- package/lib/utils/i18n/messages-es.js +2 -1
- package/lib/utils/i18n/messages-pt.js +2 -1
- package/package.json +1 -1
- package/templates/firebase/android/app/src/main/res/drawable/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-night-v21/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/drawable-v21/background.png +0 -0
- package/templates/firebase/android/app/src/main/res/values-night-v31/styles.xml +1 -1
- package/templates/firebase/android/app/src/main/res/values-v31/styles.xml +1 -1
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png +0 -0
- package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png +0 -0
- package/templates/firebase/lib/components/kasy_date_picker.dart +14 -8
- package/templates/firebase/lib/components/kasy_sidebar_pro.dart +1148 -0
- package/templates/firebase/lib/components/kasy_tabs.dart +156 -43
- package/templates/firebase/lib/components/kasy_text_field.dart +39 -29
- package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +90 -69
- package/templates/firebase/lib/core/bottom_menu/bottom_router.dart +30 -7
- package/templates/firebase/lib/core/bottom_menu/kasy_bottom_bar_factory.dart +8 -1
- package/templates/firebase/lib/core/dev_inspector/dev_inspector.dart +439 -232
- package/templates/firebase/lib/core/dev_inspector/dev_inspector_service.dart +198 -83
- package/templates/firebase/lib/core/icons/kasy_icons.dart +1 -0
- package/templates/firebase/lib/core/theme/colors.dart +6 -2
- package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +119 -19
- package/templates/firebase/lib/core/widgets/kasy_hover.dart +68 -27
- package/templates/firebase/lib/features/home/home_components_page.dart +3 -0
- package/templates/firebase/lib/features/home/home_components_preview_registry.dart +202 -79
- package/templates/firebase/lib/features/settings/settings_page.dart +27 -146
- package/templates/firebase/lib/features/settings/ui/components/admin/admin_bottom_sheet.dart +16 -3
- package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +22 -5
- package/templates/firebase/lib/i18n/en.i18n.json +3 -1
- package/templates/firebase/lib/i18n/es.i18n.json +3 -1
- package/templates/firebase/lib/i18n/pt.i18n.json +3 -1
- package/templates/firebase/pubspec.yaml +6 -4
- package/templates/firebase/web/index.html +7 -17
- package/templates/firebase/lib/firebase_options.dart +0 -75
|
@@ -3,30 +3,31 @@ import 'package:bart/bart/bart_bottombar_actions.dart';
|
|
|
3
3
|
import 'package:flutter/foundation.dart';
|
|
4
4
|
import 'package:flutter/material.dart';
|
|
5
5
|
import 'package:flutter/services.dart';
|
|
6
|
+
import 'package:kasy_kit/components/kasy_sidebar_pro.dart';
|
|
6
7
|
import 'package:kasy_kit/core/bottom_menu/bottom_router.dart';
|
|
7
8
|
import 'package:kasy_kit/core/bottom_menu/kasy_bottom_bar_factory.dart';
|
|
8
|
-
import 'package:kasy_kit/core/sidebar/kasy_sidebar.dart';
|
|
9
9
|
import 'package:kasy_kit/core/theme/theme.dart';
|
|
10
10
|
import 'package:kasy_kit/core/widgets/responsive_layout.dart';
|
|
11
11
|
|
|
12
12
|
/// Bottom navigation host powered by Bart (https://pub.dev/packages/bart).
|
|
13
13
|
///
|
|
14
|
-
/// Bart
|
|
15
|
-
///
|
|
16
|
-
/// one of three [bart.BartScaffold]s on every rebuild (breakpoint change,
|
|
17
|
-
/// theme toggle, device-preview resize), that notifier resets to its initial
|
|
18
|
-
/// value and a previously-hidden bar can come back wrong — or, when returning
|
|
19
|
-
/// from a native overlay (FaceID, photo picker, permission dialog), Bart's
|
|
20
|
-
/// internal state ends up out of sync with the visible route.
|
|
14
|
+
/// Bart's [bart.BartScaffold] owns a [ValueNotifier<bool>] for bottom-bar
|
|
15
|
+
/// visibility, created in its constructor. Two issues fall out of that:
|
|
21
16
|
///
|
|
22
|
-
///
|
|
23
|
-
///
|
|
24
|
-
///
|
|
25
|
-
///
|
|
26
|
-
///
|
|
17
|
+
/// 1. [ResponsiveLayout] swaps between three [bart.BartScaffold]s (small /
|
|
18
|
+
/// medium / large). Any rebuild (theme toggle, locale switch,
|
|
19
|
+
/// device-preview resize) instantiates a fresh notifier with the initial
|
|
20
|
+
/// value, dropping whatever visibility we had set.
|
|
21
|
+
/// 2. Bart's [bart.BartScaffold.onRouteChanged] only fires when the active
|
|
22
|
+
/// *tab index* changes — pushing an inner route inside the same tab
|
|
23
|
+
/// (e.g. `home → home/components`) is silent. We can't drive visibility
|
|
24
|
+
/// from that callback alone.
|
|
27
25
|
///
|
|
28
|
-
///
|
|
29
|
-
///
|
|
26
|
+
/// We solve both by treating inner-route presence as the source of truth.
|
|
27
|
+
/// [BottomBarVisibilityScope] exposes a counter; the [HomeInnerRoute] wrapper
|
|
28
|
+
/// increments while mounted and decrements on dispose. This widget reacts to
|
|
29
|
+
/// the counter (and to lifecycle resume + every rebuild) and re-asserts the
|
|
30
|
+
/// matching [BottomBarIntent] on Bart.
|
|
30
31
|
class BottomMenu extends StatefulWidget {
|
|
31
32
|
final String? initialRoute;
|
|
32
33
|
|
|
@@ -38,17 +39,19 @@ class BottomMenu extends StatefulWidget {
|
|
|
38
39
|
|
|
39
40
|
class _BottomMenuState extends State<BottomMenu>
|
|
40
41
|
with WidgetsBindingObserver, BartNotifier {
|
|
41
|
-
|
|
42
|
+
final ValueNotifier<int> _innerRouteDepth = ValueNotifier<int>(0);
|
|
42
43
|
|
|
43
44
|
@override
|
|
44
45
|
void initState() {
|
|
45
46
|
super.initState();
|
|
46
47
|
WidgetsBinding.instance.addObserver(this);
|
|
47
|
-
|
|
48
|
+
_innerRouteDepth.addListener(_scheduleSync);
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
@override
|
|
51
52
|
void dispose() {
|
|
53
|
+
_innerRouteDepth.removeListener(_scheduleSync);
|
|
54
|
+
_innerRouteDepth.dispose();
|
|
52
55
|
WidgetsBinding.instance.removeObserver(this);
|
|
53
56
|
super.dispose();
|
|
54
57
|
}
|
|
@@ -61,77 +64,72 @@ class _BottomMenuState extends State<BottomMenu>
|
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
void _onRouteChanged(bart.BartMenuRoute route) {
|
|
65
|
-
_currentRoutePath = route.path;
|
|
66
|
-
_scheduleSync();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
67
|
void _scheduleSync() {
|
|
70
68
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
71
69
|
if (!mounted) return;
|
|
72
|
-
|
|
70
|
+
if (_innerRouteDepth.value > 0) {
|
|
71
|
+
hideBottomBar(context);
|
|
72
|
+
} else {
|
|
73
|
+
showBottomBar(context);
|
|
74
|
+
}
|
|
73
75
|
});
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
void _applyVisibility() {
|
|
77
|
-
if (_shouldShowBottomBar(_currentRoutePath)) {
|
|
78
|
-
showBottomBar(context);
|
|
79
|
-
} else {
|
|
80
|
-
hideBottomBar(context);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
78
|
@override
|
|
85
79
|
Widget build(BuildContext context) {
|
|
86
|
-
// Re-assert visibility after every rebuild: the
|
|
80
|
+
// Re-assert visibility after every rebuild: the BartScaffold underneath
|
|
87
81
|
// may have been freshly instantiated (see class doc).
|
|
88
82
|
_scheduleSync();
|
|
89
83
|
|
|
90
84
|
final String? resolvedInitialRoute = _resolveInitialRoute(
|
|
91
85
|
widget.initialRoute,
|
|
92
86
|
);
|
|
93
|
-
final bool showBottomBarOnStart =
|
|
87
|
+
final bool showBottomBarOnStart = _shouldShowBottomBarOnStart(
|
|
88
|
+
resolvedInitialRoute,
|
|
89
|
+
);
|
|
94
90
|
final scaffoldOptions = bart.ScaffoldOptions(
|
|
95
91
|
backgroundColor: context.colors.background,
|
|
96
92
|
);
|
|
97
93
|
|
|
98
|
-
return
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// medium (768–1024 px): icon-only collapsed rail
|
|
113
|
-
medium: bart.BartScaffold(
|
|
114
|
-
routesBuilder: subRoutes,
|
|
115
|
-
bottomBar: kasyPaddedSurfaceBottomBar(),
|
|
116
|
-
initialRoute: resolvedInitialRoute,
|
|
117
|
-
showBottomBarOnStart: showBottomBarOnStart,
|
|
118
|
-
scaffoldOptions: scaffoldOptions,
|
|
119
|
-
sideBarOptions: bart.CustomSideBarOptions(
|
|
120
|
-
sideBarBuilder: kasySidebarCollapsedBuilder,
|
|
94
|
+
return BottomBarVisibilityScope(
|
|
95
|
+
innerRouteDepth: _innerRouteDepth,
|
|
96
|
+
child: AnnotatedRegion<SystemUiOverlayStyle>(
|
|
97
|
+
value: switch (Theme.brightnessOf(context)) {
|
|
98
|
+
Brightness.dark => SystemUiOverlayStyle.light,
|
|
99
|
+
Brightness.light => SystemUiOverlayStyle.dark,
|
|
100
|
+
},
|
|
101
|
+
child: ResponsiveLayout(
|
|
102
|
+
small: bart.BartScaffold(
|
|
103
|
+
routesBuilder: subRoutes,
|
|
104
|
+
bottomBar: kasyPaddedSurfaceBottomBar(),
|
|
105
|
+
initialRoute: resolvedInitialRoute,
|
|
106
|
+
showBottomBarOnStart: showBottomBarOnStart,
|
|
107
|
+
scaffoldOptions: scaffoldOptions,
|
|
121
108
|
),
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
109
|
+
// medium (768–1024 px): KasySidebarPro auto-collapses at this width
|
|
110
|
+
medium: bart.BartScaffold(
|
|
111
|
+
routesBuilder: subRoutes,
|
|
112
|
+
bottomBar: kasyPaddedSurfaceBottomBar(),
|
|
113
|
+
initialRoute: resolvedInitialRoute,
|
|
114
|
+
showBottomBarOnStart: showBottomBarOnStart,
|
|
115
|
+
scaffoldOptions: scaffoldOptions,
|
|
116
|
+
sideBarOptions: bart.CustomSideBarOptions(
|
|
117
|
+
sideBarBuilder: (routes, onTap, current) =>
|
|
118
|
+
const KasySidebarPro(),
|
|
119
|
+
),
|
|
120
|
+
),
|
|
121
|
+
// large (1024 px+): full expanded sidebar
|
|
122
|
+
large: bart.BartScaffold(
|
|
123
|
+
routesBuilder: subRoutes,
|
|
124
|
+
bottomBar: kasyPaddedSurfaceBottomBar(),
|
|
125
|
+
initialRoute: resolvedInitialRoute,
|
|
126
|
+
showBottomBarOnStart: showBottomBarOnStart,
|
|
127
|
+
scaffoldOptions: scaffoldOptions,
|
|
128
|
+
sideBarOptions: bart.CustomSideBarOptions(
|
|
129
|
+
sideBarBuilder: (routes, onTap, current) =>
|
|
130
|
+
const KasySidebarPro(),
|
|
131
|
+
),
|
|
133
132
|
),
|
|
134
|
-
onRouteChanged: _onRouteChanged,
|
|
135
133
|
),
|
|
136
134
|
),
|
|
137
135
|
);
|
|
@@ -170,7 +168,7 @@ class _BottomMenuState extends State<BottomMenu>
|
|
|
170
168
|
return path;
|
|
171
169
|
}
|
|
172
170
|
|
|
173
|
-
bool
|
|
171
|
+
bool _shouldShowBottomBarOnStart(String? route) {
|
|
174
172
|
if (route == null) {
|
|
175
173
|
return true;
|
|
176
174
|
}
|
|
@@ -178,3 +176,26 @@ class _BottomMenuState extends State<BottomMenu>
|
|
|
178
176
|
return segments.length < 2;
|
|
179
177
|
}
|
|
180
178
|
}
|
|
179
|
+
|
|
180
|
+
/// Shared counter that inner home routes increment while mounted. The host
|
|
181
|
+
/// [BottomMenu] observes it and toggles Bart's bottom-bar accordingly.
|
|
182
|
+
class BottomBarVisibilityScope extends InheritedWidget {
|
|
183
|
+
final ValueNotifier<int> innerRouteDepth;
|
|
184
|
+
|
|
185
|
+
const BottomBarVisibilityScope({
|
|
186
|
+
super.key,
|
|
187
|
+
required this.innerRouteDepth,
|
|
188
|
+
required super.child,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
static ValueNotifier<int>? maybeOf(BuildContext context) {
|
|
192
|
+
final scope = context
|
|
193
|
+
.getInheritedWidgetOfExactType<BottomBarVisibilityScope>();
|
|
194
|
+
return scope?.innerRouteDepth;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
@override
|
|
198
|
+
bool updateShouldNotify(covariant BottomBarVisibilityScope oldWidget) {
|
|
199
|
+
return innerRouteDepth != oldWidget.innerRouteDepth;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -2,6 +2,7 @@ import 'package:bart/bart.dart';
|
|
|
2
2
|
import 'package:flutter/material.dart';
|
|
3
3
|
import 'package:kasy_kit/components/kasy_app_bar.dart';
|
|
4
4
|
import 'package:kasy_kit/core/bottom_menu/bart_inner_paths.dart';
|
|
5
|
+
import 'package:kasy_kit/core/bottom_menu/bottom_menu.dart';
|
|
5
6
|
import 'package:kasy_kit/core/bottom_menu/notification_bottom_item.dart';
|
|
6
7
|
import 'package:kasy_kit/core/navigation/kasy_navigation_config.dart';
|
|
7
8
|
import 'package:kasy_kit/core/navigation/kasy_route_transition.dart';
|
|
@@ -109,18 +110,40 @@ List<BartMenuRoute> subRoutes() {
|
|
|
109
110
|
];
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
///
|
|
113
|
-
/// [
|
|
114
|
-
///
|
|
115
|
-
///
|
|
116
|
-
|
|
117
|
-
class _HomeInnerRoute extends StatelessWidget {
|
|
113
|
+
/// Wrapper for inner home routes. While mounted, it bumps a shared counter
|
|
114
|
+
/// exposed by [BottomBarVisibilityScope] so [BottomMenu] knows to hide the
|
|
115
|
+
/// bottom bar — covering cases Bart's tab-only `onRouteChanged` misses (e.g.
|
|
116
|
+
/// pushing inside the same tab) and surviving scaffold rebuilds.
|
|
117
|
+
class _HomeInnerRoute extends StatefulWidget {
|
|
118
118
|
final Widget child;
|
|
119
119
|
|
|
120
120
|
const _HomeInnerRoute({required this.child});
|
|
121
121
|
|
|
122
122
|
@override
|
|
123
|
-
|
|
123
|
+
State<_HomeInnerRoute> createState() => _HomeInnerRouteState();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
class _HomeInnerRouteState extends State<_HomeInnerRoute> {
|
|
127
|
+
ValueNotifier<int>? _depth;
|
|
128
|
+
|
|
129
|
+
@override
|
|
130
|
+
void didChangeDependencies() {
|
|
131
|
+
super.didChangeDependencies();
|
|
132
|
+
final next = BottomBarVisibilityScope.maybeOf(context);
|
|
133
|
+
if (identical(_depth, next)) return;
|
|
134
|
+
_depth?.value -= 1;
|
|
135
|
+
_depth = next;
|
|
136
|
+
_depth?.value += 1;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@override
|
|
140
|
+
void dispose() {
|
|
141
|
+
_depth?.value -= 1;
|
|
142
|
+
super.dispose();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
@override
|
|
146
|
+
Widget build(BuildContext context) => widget.child;
|
|
124
147
|
}
|
|
125
148
|
|
|
126
149
|
/// Placeholder page for the wishlist tab.
|
|
@@ -38,6 +38,13 @@ final class KasyPaddedSurfaceBottomBarFactory extends BartBottomBarFactory {
|
|
|
38
38
|
required void Function(int) onTap,
|
|
39
39
|
required int currentIndex,
|
|
40
40
|
}) {
|
|
41
|
+
return TooltipVisibility(
|
|
42
|
+
visible: false,
|
|
43
|
+
child: _build(context),
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Widget _build(BuildContext context) {
|
|
41
48
|
final KasyColors colors = context.colors;
|
|
42
49
|
final MenuRouter menuRouter = MenuRouter.of(context);
|
|
43
50
|
final BorderSide topEdge = BorderSide(
|
|
@@ -72,7 +79,7 @@ final class KasyPaddedSurfaceBottomBarFactory extends BartBottomBarFactory {
|
|
|
72
79
|
),
|
|
73
80
|
),
|
|
74
81
|
BartCupertinoBottomBar(
|
|
75
|
-
routes:
|
|
82
|
+
routes: menuRouter.routesBuilder(),
|
|
76
83
|
theme: CupertinoBottomBarTheme(
|
|
77
84
|
bgColor: colors.surface,
|
|
78
85
|
height: _kBottomBarHeightCupertino - kasyBottomBarTopPadding,
|