Skip to content

Commit eb029ef

Browse files
Responsive UI (#152)
* feat: separated mobile and desktop wrapper ui * feat: navigation rail! * feat: improved image loading indicator * fix: tabbar looking weird when scrolling * fix: tabbar fixes cont * Update packages/app/lib/src/features/home/presentation/home/post.dart Co-authored-by: Eli <[email protected]> Signed-off-by: Matthew Wasser <[email protected]> * fix: image wrapping and post view overflow * fix: fix mobile appbar color changing * fix: added back routing logic :) * feat: min and max window size for desktop * feat: separate login page into mobile and desktop * feat: optimized mobile login ui * wip: responsive posting ui * feat: responsive mobile post ui * fix: not passing in _onResult * chore: revert window * chore: typo * ci: update actions/cache * ci: actually cache stuff * fix: lints --------- Signed-off-by: Matthew Wasser <[email protected]> Co-authored-by: Eli <[email protected]>
1 parent 45b3fc6 commit eb029ef

File tree

15 files changed

+429
-73
lines changed

15 files changed

+429
-73
lines changed

.github/workflows/ci.yaml

Lines changed: 32 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,17 @@ jobs:
4949
- name: 🌐 Disable analytics
5050
run: flutter --disable-analytics
5151
- name: ⚙️ Cache generated files
52-
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2
52+
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
5353
with:
5454
path: |
5555
.dart_tool/
56-
lib/src/gen/*.gen.dart
57-
lib/src/features/**/*.g.dart
58-
lib/src/features/**/*.freezed.dart
59-
lib/src/utils/*.g.dart
60-
lib/src/utils/*.freezed.dart
61-
lib/src/app/*.gr.dart
62-
lib/src/app/*.gm.dart
63-
lib/src/l10n/app_localizations.dart
64-
lib/src/l10n/app_localizations_*.dart
56+
packages/*/lib/src/gen/*.gen.dart
57+
packages/*/lib/src/**/*.g.dart
58+
packages/*/lib/src/**/*.freezed.dart
59+
packages/*/lib/src/app/*.gr.dart
60+
packages/*/lib/src/app/*.gm.dart
61+
packages/*/lib/src/l10n/app_localizations.dart
62+
packages/*/lib/src/l10n/app_localizations_*.dart
6563
key: ${{ runner.os }}-${{ steps.flutter.outputs.CHANNEL }}-dart-${{ hashFiles('**/build.yaml') }}
6664
- name: 📦 Install dependencies
6765
uses: bluefireteam/melos-action@c7dcb921b23cc520cace360b95d02b37bf09cdaa # v3
@@ -130,19 +128,17 @@ jobs:
130128
- name: 🌐 Disable analytics
131129
run: flutter --disable-analytics
132130
- name: ⚙️ Cache generated files
133-
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2
131+
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
134132
with:
135133
path: |
136134
.dart_tool/
137-
lib/src/gen/*.gen.dart
138-
lib/src/features/**/*.g.dart
139-
lib/src/features/**/*.freezed.dart
140-
lib/src/utils/*.g.dart
141-
lib/src/utils/*.freezed.dart
142-
lib/src/app/*.gr.dart
143-
lib/src/app/*.gm.dart
144-
lib/src/l10n/app_localizations.dart
145-
lib/src/l10n/app_localizations_*.dart
135+
packages/*/lib/src/gen/*.gen.dart
136+
packages/*/lib/src/**/*.g.dart
137+
packages/*/lib/src/**/*.freezed.dart
138+
packages/*/lib/src/app/*.gr.dart
139+
packages/*/lib/src/app/*.gm.dart
140+
packages/*/lib/src/l10n/app_localizations.dart
141+
packages/*/lib/src/l10n/app_localizations_*.dart
146142
key: ${{ runner.os }}-${{ steps.flutter.outputs.CHANNEL }}-dart-${{ hashFiles('**/build.yaml') }}
147143
- name: 📦 Install dependencies
148144
uses: bluefireteam/melos-action@c7dcb921b23cc520cace360b95d02b37bf09cdaa # v3
@@ -185,19 +181,17 @@ jobs:
185181
- name: 🌐 Disable analytics
186182
run: flutter --disable-analytics
187183
- name: ⚙️ Cache generated files
188-
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2
184+
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
189185
with:
190186
path: |
191187
.dart_tool/
192-
lib/src/gen/*.gen.dart
193-
lib/src/features/**/*.g.dart
194-
lib/src/features/**/*.freezed.dart
195-
lib/src/utils/*.g.dart
196-
lib/src/utils/*.freezed.dart
197-
lib/src/app/*.gr.dart
198-
lib/src/app/*.gm.dart
199-
lib/src/l10n/app_localizations.dart
200-
lib/src/l10n/app_localizations_*.dart
188+
packages/*/lib/src/gen/*.gen.dart
189+
packages/*/lib/src/**/*.g.dart
190+
packages/*/lib/src/**/*.freezed.dart
191+
packages/*/lib/src/app/*.gr.dart
192+
packages/*/lib/src/app/*.gm.dart
193+
packages/*/lib/src/l10n/app_localizations.dart
194+
packages/*/lib/src/l10n/app_localizations_*.dart
201195
key: ${{ runner.os }}-${{ steps.flutter.outputs.CHANNEL }}-dart-${{ hashFiles('**/build.yaml') }}
202196
- name: 📦 Install dependencies
203197
uses: bluefireteam/melos-action@c7dcb921b23cc520cace360b95d02b37bf09cdaa # v3
@@ -233,19 +227,17 @@ jobs:
233227
- name: 🌐 Disable analytics
234228
run: flutter --disable-analytics
235229
- name: ⚙️ Cache generated files
236-
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2
230+
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
237231
with:
238232
path: |
239233
.dart_tool/
240-
lib/src/gen/*.gen.dart
241-
lib/src/features/**/*.g.dart
242-
lib/src/features/**/*.freezed.dart
243-
lib/src/utils/*.g.dart
244-
lib/src/utils/*.freezed.dart
245-
lib/src/app/*.gr.dart
246-
lib/src/app/*.gm.dart
247-
lib/src/l10n/app_localizations.dart
248-
lib/src/l10n/app_localizations_*.dart
234+
packages/*/lib/src/gen/*.gen.dart
235+
packages/*/lib/src/**/*.g.dart
236+
packages/*/lib/src/**/*.freezed.dart
237+
packages/*/lib/src/app/*.gr.dart
238+
packages/*/lib/src/app/*.gm.dart
239+
packages/*/lib/src/l10n/app_localizations.dart
240+
packages/*/lib/src/l10n/app_localizations_*.dart
249241
key: ${{ runner.os }}-${{ steps.flutter.outputs.CHANNEL }}-dart-${{ hashFiles('**/build.yaml') }}
250242
restore-keys: |
251243
${{ runner.os }}-${{ steps.flutter.outputs.CHANNEL }}-dart-

packages/app/lib/main.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
/// This library contains the app's primary entrypoint.
22
library;
33

4+
import 'dart:io';
5+
46
import 'package:flutter/widgets.dart';
57
import 'package:shared_preferences/shared_preferences.dart';
8+
import 'package:window_manager/window_manager.dart';
69

710
import 'src/app/app.dart';
811
import 'src/app/bootstrap.dart';
@@ -11,6 +14,16 @@ import 'src/app/bootstrap.dart';
1114
///
1215
/// This uses [Bootstrap] to launch [App].
1316
Future<void> main() async {
17+
//Set minimum window size for desktop
18+
WidgetsFlutterBinding.ensureInitialized();
19+
20+
// Only initialize window manager on desktop platforms
21+
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
22+
await windowManager.ensureInitialized();
23+
await WindowManager.instance.setMinimumSize(const Size(1200, 600));
24+
await WindowManager.instance.setMaximumSize(const Size(1920, 1080));
25+
}
26+
1427
await const App().bootstrap((
1528
runApp: runApp,
1629
getSharedPreferences: SharedPreferencesWithCache.create,

packages/app/lib/src/app/wrapper_page.dart

Lines changed: 136 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,106 @@ class WrapperPage extends ConsumerWidget {
3232
/// Construct a new [WrapperPage] widget.
3333
const WrapperPage({super.key});
3434

35+
@override
36+
Widget build(BuildContext context, WidgetRef ref) {
37+
return LayoutBuilder(
38+
builder: (context, constraints) {
39+
if (constraints.maxWidth > 680) {
40+
return const _DesktopWrapper();
41+
} else {
42+
return const _MobileWrapper();
43+
}
44+
},
45+
);
46+
}
47+
}
48+
49+
class _DesktopWrapper extends ConsumerWidget {
50+
const _DesktopWrapper({super.key});
51+
52+
@override
53+
Widget build(BuildContext context, WidgetRef ref) {
54+
return AutoTabsRouter(
55+
routes: const [
56+
FeedRoutingRoute(),
57+
MapRoute(),
58+
SettingsRoute(), // Make a new feed route page that has an app bar that routes between local and world
59+
],
60+
builder: (context, child) {
61+
final autoRouter = AutoTabsRouter.of(context);
62+
return Scaffold(
63+
body: Row(
64+
children: [
65+
NavigationRail(
66+
selectedIndex: autoRouter.activeIndex,
67+
onDestinationSelected: autoRouter.setActiveIndex,
68+
extended:
69+
MediaQuery.sizeOf(context).width >=
70+
800, // Might need to change to constraints
71+
minExtendedWidth: 200,
72+
destinations: const [
73+
// TODO(MattsAttack): increase size of tabs
74+
NavigationRailDestination(
75+
icon: Icon(Icons.feed),
76+
label: Text('Feeds'),
77+
),
78+
NavigationRailDestination(
79+
icon: Icon(Icons.map_outlined),
80+
label: Text('Discover'),
81+
),
82+
NavigationRailDestination(
83+
icon: Icon(Icons.settings),
84+
label: Text('Settings'),
85+
),
86+
],
87+
),
88+
Expanded(child: child),
89+
],
90+
), // Implement rail here similar to google article
91+
appBar: AppBar(
92+
elevation: 0,
93+
// backgroundColor: Theme.of(context).colorScheme.primary,
94+
shadowColor: Theme.of(context).colorScheme.surface,
95+
backgroundColor: Theme.of(context).colorScheme.surface,
96+
scrolledUnderElevation: 0,
97+
title: Text(autoRouter.current.title(context)),
98+
automaticallyImplyLeading: false,
99+
// bottom: switch (autoRouter.current.path) {
100+
// '/' => TabBar(
101+
// onTap: autoRouter.setActiveIndex,
102+
// automaticIndicatorColorAdjustment: false,
103+
// overlayColor: WidgetStateProperty.all(
104+
// Theme.of(context).colorScheme.surface,
105+
// ),
106+
107+
// // labelColor: Colors.blue,
108+
// // unselectedLabelColor: Colors.blue,
109+
// // indicatorColor: Colors.blue,
110+
// tabs: const [
111+
// Tab(icon: Icon(Icons.my_location), text: 'Local'),
112+
// Tab(icon: Icon(Icons.public), text: 'World'),
113+
// ],
114+
// ),
115+
// _ => null,
116+
// },
117+
),
118+
floatingActionButton: FloatingActionButton(
119+
onPressed:
120+
() async => showDialog<void>(
121+
context: context,
122+
builder: (context) => const _Dialog(),
123+
),
124+
child: const Icon(Icons.create),
125+
), // Change to form on top of feed for desktop
126+
);
127+
},
128+
);
129+
}
130+
}
131+
132+
class _MobileWrapper extends ConsumerWidget {
133+
const _MobileWrapper({super.key});
134+
35135
@override
36136
Widget build(BuildContext context, WidgetRef ref) {
37137
return AutoTabsScaffold(
@@ -51,6 +151,9 @@ class WrapperPage extends ConsumerWidget {
51151
appBarBuilder: (context, autoRouter) {
52152
return AppBar(
53153
title: Text(autoRouter.current.title(context)),
154+
shadowColor: Theme.of(context).colorScheme.surface,
155+
backgroundColor: Theme.of(context).colorScheme.surface,
156+
scrolledUnderElevation: 0,
54157
automaticallyImplyLeading: false,
55158
bottom: switch (autoRouter.current.path) {
56159
// FIXME(lishaduck): This needs some work.
@@ -143,21 +246,44 @@ class _Dialog extends HookConsumerWidget {
143246
context,
144247
).showSnackBar(const SnackBar(content: Text('Post Created!')));
145248
}, [formKey]);
146-
249+
final responsivePadding =
250+
MediaQuery.sizeOf(context).width > 680 ? 16.0 : 0.0;
147251
return Dialog(
148-
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
252+
shape: RoundedRectangleBorder(
253+
borderRadius: BorderRadius.circular(responsivePadding),
254+
),
255+
insetPadding: EdgeInsets.symmetric(
256+
horizontal: responsivePadding * 4,
257+
vertical: responsivePadding * 3,
258+
),
149259
child: Padding(
150-
padding: const EdgeInsets.all(16),
260+
padding: EdgeInsets.all(responsivePadding),
151261
child: Form(
152262
key: formKey,
153263
child: Padding(
154264
padding: const EdgeInsets.all(16),
155265
child: Column(
156266
children: [
157-
Text(
158-
'Create a new post',
159-
style: Theme.of(context).textTheme.headlineSmall,
160-
),
267+
if (responsivePadding == 0)
268+
Row(
269+
children: [
270+
IconButton(
271+
onPressed: () async {
272+
await context.router.maybePop();
273+
},
274+
icon: const Icon(Icons.close),
275+
),
276+
Text(
277+
'Create a new post',
278+
style: Theme.of(context).textTheme.headlineSmall,
279+
),
280+
],
281+
)
282+
else
283+
Text(
284+
'Create a new post',
285+
style: Theme.of(context).textTheme.headlineSmall,
286+
),
161287
const SizedBox(height: 16),
162288

163289
// TODO(MattsAttack): guard against creating empty posts.
@@ -232,6 +358,8 @@ class _Dialog extends HookConsumerWidget {
232358
),
233359
),
234360
),
361+
// );
362+
// },
235363
);
236364
}
237365
}
@@ -244,7 +372,7 @@ class _UploadedImagesView extends HookConsumerWidget {
244372
final uploadedImages = ref.watch(uploadedImagesServiceProvider);
245373

246374
return SizedBox(
247-
height: 150,
375+
height: 200,
248376
child: ListView.builder(
249377
scrollDirection: Axis.horizontal,
250378
padding: const EdgeInsets.all(8),

0 commit comments

Comments
 (0)