Skip to content

Commit eba5da2

Browse files
committed
- Updated readme
-Added screenshots - Finished up Mac folder
1 parent e7183b2 commit eba5da2

18 files changed

+679
-54
lines changed

README.md

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,52 @@
11
# flutter_days_app
2+
A Flutter project that was created for a Flutter Days 2022 talk, **"Desktop Development isn't Dead: Flutter Desktop"**.
23

3-
A new Flutter project.
4+
This project goes into showing how a developer is able to using the same dart language for mobile develop apps that are capable of developing for Windows and MacOS.
45

5-
## Getting Started
6+
This project is developed using Flutter Version **2.10.2**(Stable Channel) and Dart version **2.16.1**.
7+
#
8+
## Screenshots
69

7-
This project is a starting point for a Flutter application.
10+
<!-- |Dark Mode (Mac) |Light Mode(Mac) |Light Mode (Windows) |
11+
|---|---|---|
12+
|![macos_dark_mode](screenshots/macos_dark.png) |![macos_light_mode](screenshots/macos_light.png) |![windows_light_mode](screenshots/windows_light.png) | -->
813

9-
A few resources to get you started if this is your first Flutter project:
14+
MacOS Screenshots
15+
16+
Dark Mode
17+
![macos_dark_mode](screenshots/macos_dark.png)
18+
19+
Light Mode
20+
![macos_light_mode](screenshots/macos_light.png)
21+
22+
Windows Screenshot
23+
24+
![windows_light_mode](screenshots/windows_light.png)
25+
26+
___I did not have a Windows machine at the time of capturing this screenshot hence it is bound to look slightly different when run on an actual Windows machine___
27+
28+
## Overview
29+
This project made use primarily of two distinct packages, [macos_ui](https://pub.dev/packages/macos_ui) and [fluent_ui](https://pub.dev/packages/fluent_ui) to deliver the native look and feel of the respective platforms it was developed for.
30+
31+
There is no claim for a 100% native platform look but this project attempts to get there.
32+
33+
Furthermore, it made use of data from a GraphQL backend provided by myself in order to deliver the content into the apps.
34+
35+
### Notes
36+
- There will be continued effort to add comments in the code to help those trying to understand what the code is doing and how it was written.
37+
- This app was just a starting point to show how desktop development is possible. As such there is alot that can be improved/refactored to showcase better data handling, reduce repetitive code and also to merge similar files under one.
38+
39+
All that is work that can be iterated upon later.
40+
- I do not claim copyright for any and all images used in the app.
41+
42+
## Suggested Further Reading
43+
There is alot more that can be done with Flutter Desktop to not only expand on this project but also to increase your knowledge on the area.
44+
45+
46+
- [Setting up Flutter for desktop development](https://docs.flutter.dev/desktop)
47+
- Understand the requirements needed to set up your environment for desktop development.
48+
- [Write a Flutter desktop application Codelab](https://codelabs.developers.google.com/codelabs/flutter-github-client?hl=en#4)
49+
- Walk through a tutorial to develop your first desktop application.
50+
- Ready to package and distribute your Windows app, use the [msix package](https://pub.dev/packages/msix) to create an installer for your application
1051

11-
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
12-
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
1352

14-
For help getting started with Flutter, view our
15-
[online documentation](https://flutter.dev/docs), which offers tutorials,
16-
samples, guidance on mobile development, and a full API reference.

lib/graph_objects/graph_queries.dart

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,49 @@ const String getDessertsMenu = """
6868
}
6969
}
7070
""";
71+
72+
const String getBreakFastByID = """
73+
query getBreakByID(\$menuID: Int!) {
74+
Breakfast_by_pk(id: \$menuID) {
75+
id
76+
name
77+
description
78+
image
79+
price
80+
}
81+
}
82+
""";
83+
84+
const String getMealsByID = """
85+
query getMealByID(\$menuID: Int!) {
86+
Meals_by_pk(id: \$menuID) {
87+
id
88+
image
89+
name
90+
price
91+
description
92+
}
93+
}
94+
""";
95+
96+
const String getDessertByID = """
97+
query getDessertByID(\$menuID: Int!) {
98+
Desserts_by_pk(id: \$menuID) {
99+
id
100+
image
101+
name
102+
price
103+
description
104+
}
105+
}""";
106+
107+
const String getDrinksById = """
108+
query getDrinksByID (\$menuID: Int!) {
109+
Drinks_by_pk(id: \$menuID) {
110+
id
111+
image
112+
name
113+
price
114+
description
115+
}
116+
}""";

lib/macintosh/pages/locations_page.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class LocationsPage extends StatelessWidget {
7575
cardTitle: location['location_name'],
7676
cardSubtitle: location['location_contact1'],
7777
//contact2: '',
78+
onPressed: () {},
7879
);
7980
},
8081
);
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import 'package:flutter/cupertino.dart';
2+
import 'package:flutter_days_app/macintosh/pages/menu/menu_details.dart';
3+
import 'package:flutter_days_app/widgets/mac_card.dart';
4+
import 'package:graphql_flutter/graphql_flutter.dart';
5+
import 'package:macos_ui/macos_ui.dart';
6+
7+
import '../../../graph_objects/graph_queries.dart';
8+
9+
class BreakfastMenu extends StatefulWidget {
10+
const BreakfastMenu({Key? key}) : super(key: key);
11+
12+
@override
13+
State<BreakfastMenu> createState() => _BreakfastMenuState();
14+
}
15+
16+
class _BreakfastMenuState extends State<BreakfastMenu>
17+
with AutomaticKeepAliveClientMixin<BreakfastMenu> {
18+
@override
19+
Widget build(BuildContext context) {
20+
super.build(context);
21+
return Query(
22+
options: QueryOptions(document: gql(getBreakfastMenu)),
23+
builder: (QueryResult result,
24+
{VoidCallback? refetch, FetchMore? fetchMore}) {
25+
if (result.isLoading) {
26+
return const Center(
27+
child: ProgressCircle(),
28+
);
29+
}
30+
31+
if (result.data == null) {
32+
return Center(
33+
child: Column(
34+
children: [
35+
const Icon(CupertinoIcons.exclamationmark, size: 60),
36+
const SizedBox(height: 20),
37+
Text(
38+
'No breakfast available',
39+
style: MacosTheme.of(context).typography.subheadline,
40+
),
41+
],
42+
),
43+
);
44+
}
45+
46+
if (result.exception != null) {
47+
showMacosAlertDialog(
48+
context: context,
49+
builder: (_) {
50+
return MacosAlertDialog(
51+
appIcon: const Icon(CupertinoIcons.exclamationmark_triangle,
52+
size: 56, color: MacosColors.systemRedColor),
53+
title: const Text('Error'),
54+
message: Text(
55+
'Error returned the following exception: ${result.exception}'),
56+
primaryButton: PushButton(
57+
child: const Text('OK'),
58+
buttonSize: ButtonSize.large,
59+
onPressed: () {
60+
refetch!();
61+
Navigator.of(context, rootNavigator: true).pop();
62+
}),
63+
);
64+
});
65+
}
66+
List<dynamic> breakMenu = result.data!['Breakfast'];
67+
68+
return GridView.builder(
69+
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
70+
crossAxisCount: 3,
71+
mainAxisExtent: 300,
72+
mainAxisSpacing: 50,
73+
crossAxisSpacing: 20),
74+
shrinkWrap: true,
75+
itemCount: breakMenu.length,
76+
padding: const EdgeInsets.symmetric(
77+
horizontal: 20,
78+
vertical: 20,
79+
),
80+
itemBuilder: (BuildContext context, int index) {
81+
final breakfast = breakMenu[index];
82+
return MacCard(
83+
cardImage: breakfast['image'],
84+
cardTitle: breakfast['name'],
85+
cardSubtitle: 'UGX${breakfast['price']}',
86+
onPressed: () {
87+
Navigator.of(context).push(
88+
CupertinoPageRoute(
89+
builder: (builder) => MenuDetails(
90+
menuID: breakfast['id'],
91+
detailQuery: getBreakFastByID,
92+
resultKey: 'Breakfast_by_pk',
93+
),
94+
),
95+
);
96+
},
97+
);
98+
},
99+
);
100+
});
101+
}
102+
103+
@override
104+
bool get wantKeepAlive => true;
105+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import 'package:flutter/cupertino.dart';
2+
import 'package:flutter_days_app/widgets/mac_card.dart';
3+
import 'package:graphql_flutter/graphql_flutter.dart';
4+
import 'package:macos_ui/macos_ui.dart';
5+
6+
import '../../../graph_objects/graph_queries.dart';
7+
8+
class DessertMenu extends StatelessWidget {
9+
const DessertMenu({Key? key}) : super(key: key);
10+
11+
@override
12+
Widget build(BuildContext context) {
13+
return Query(
14+
options: QueryOptions(document: gql(getDessertsMenu)),
15+
builder: (QueryResult result,
16+
{VoidCallback? refetch, FetchMore? fetchMore}) {
17+
if (result.isLoading) {
18+
return const Center(
19+
child: ProgressCircle(),
20+
);
21+
}
22+
23+
if (result.data == null) {
24+
return Center(
25+
child: Column(
26+
children: [
27+
const Icon(CupertinoIcons.exclamationmark, size: 60),
28+
const SizedBox(height: 20),
29+
Text(
30+
'No desserts available',
31+
style: MacosTheme.of(context).typography.subheadline,
32+
),
33+
],
34+
),
35+
);
36+
}
37+
38+
if (result.exception != null) {
39+
showMacosAlertDialog(
40+
context: context,
41+
builder: (_) {
42+
return MacosAlertDialog(
43+
appIcon: const Icon(CupertinoIcons.exclamationmark_triangle,
44+
size: 56, color: MacosColors.systemRedColor),
45+
title: const Text('Error'),
46+
message: Text(
47+
'Error returned the following exception: ${result.exception}'),
48+
primaryButton: PushButton(
49+
child: const Text('OK'),
50+
buttonSize: ButtonSize.large,
51+
onPressed: () {
52+
refetch!();
53+
Navigator.of(context, rootNavigator: true).pop();
54+
}),
55+
);
56+
});
57+
}
58+
List<dynamic> dessertMenu = result.data!['Desserts'];
59+
60+
return GridView.builder(
61+
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
62+
crossAxisCount: 3,
63+
mainAxisExtent: 300,
64+
mainAxisSpacing: 50,
65+
crossAxisSpacing: 20),
66+
shrinkWrap: true,
67+
itemCount: dessertMenu.length,
68+
padding: const EdgeInsets.symmetric(
69+
horizontal: 20,
70+
vertical: 20,
71+
),
72+
itemBuilder: (BuildContext context, int index) {
73+
final dessert = dessertMenu[index];
74+
return MacCard(
75+
cardImage: dessert['image'],
76+
cardTitle: dessert['name'],
77+
cardSubtitle: 'UGX${dessert['price']}',
78+
onPressed: () {},
79+
);
80+
},
81+
);
82+
});
83+
}
84+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import 'package:flutter/cupertino.dart';
2+
import 'package:flutter_days_app/widgets/mac_card.dart';
3+
import 'package:graphql_flutter/graphql_flutter.dart';
4+
import 'package:macos_ui/macos_ui.dart';
5+
6+
import '../../../graph_objects/graph_queries.dart';
7+
8+
class DrinksMenu extends StatelessWidget {
9+
const DrinksMenu({Key? key}) : super(key: key);
10+
11+
@override
12+
Widget build(BuildContext context) {
13+
return Query(
14+
options: QueryOptions(document: gql(getDrinks)),
15+
builder: (QueryResult result,
16+
{VoidCallback? refetch, FetchMore? fetchMore}) {
17+
if (result.isLoading) {
18+
return const Center(
19+
child: ProgressCircle(),
20+
);
21+
}
22+
23+
if (result.data == null) {
24+
return Center(
25+
child: Column(
26+
children: [
27+
const Icon(CupertinoIcons.exclamationmark, size: 60),
28+
const SizedBox(height: 20),
29+
Text(
30+
'No drinks available',
31+
style: MacosTheme.of(context).typography.subheadline,
32+
),
33+
],
34+
),
35+
);
36+
}
37+
38+
if (result.exception != null) {
39+
showMacosAlertDialog(
40+
context: context,
41+
builder: (_) {
42+
return MacosAlertDialog(
43+
appIcon: const Icon(CupertinoIcons.exclamationmark_triangle,
44+
size: 56, color: MacosColors.systemRedColor),
45+
title: const Text('Error'),
46+
message: Text(
47+
'Error returned the following exception: ${result.exception}'),
48+
primaryButton: PushButton(
49+
child: const Text('OK'),
50+
buttonSize: ButtonSize.large,
51+
onPressed: () {
52+
refetch!();
53+
Navigator.of(context, rootNavigator: true).pop();
54+
}),
55+
);
56+
});
57+
}
58+
List<dynamic> drinksMenu = result.data!['Drinks'];
59+
60+
return GridView.builder(
61+
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
62+
crossAxisCount: 3,
63+
mainAxisExtent: 300,
64+
mainAxisSpacing: 50,
65+
crossAxisSpacing: 20),
66+
shrinkWrap: true,
67+
itemCount: drinksMenu.length,
68+
padding: const EdgeInsets.symmetric(
69+
horizontal: 20,
70+
vertical: 20,
71+
),
72+
itemBuilder: (BuildContext context, int index) {
73+
final drink = drinksMenu[index];
74+
return MacCard(
75+
cardImage: drink['image'],
76+
cardTitle: drink['name'],
77+
cardSubtitle: 'UGX${drink['price']}',
78+
onPressed: () {},
79+
);
80+
},
81+
);
82+
});
83+
}
84+
}

0 commit comments

Comments
 (0)