Skip to content

Commit bfa1f45

Browse files
committed
chore: build snap on github
1 parent 1387769 commit bfa1f45

File tree

7 files changed

+133
-72
lines changed

7 files changed

+133
-72
lines changed

.github/workflows/snap.yaml

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Create Snap Package
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
env:
10+
FLUTTER_VERSION: "3.27.4"
11+
12+
jobs:
13+
build_and_release_linux_snap_edge_amd64:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 5
19+
- uses: subosito/flutter-action@v2
20+
with:
21+
channel: "stable"
22+
flutter-version: ${{env.FLUTTER_VERSION}}
23+
- run: sudo apt update
24+
- run: sudo apt install -y clang cmake curl libgtk-3-dev ninja-build pkg-config unzip libunwind-dev libsecret-1-dev
25+
- run: flutter pub get
26+
- run: flutter build linux --release --dart-define=${{ secrets.API_KEY }}
27+
- uses: snapcore/action-build@v1
28+
id: build
29+
- uses: snapcore/action-publish@v1
30+
if: steps.build.outcome == 'success'
31+
env:
32+
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.STORE_LOGIN }}
33+
with:
34+
snap: ${{ steps.build.outputs.snap }}
35+
release: edge
36+
37+
build_and_release_linux_snap_edge_arm64:
38+
runs-on: ubuntu-24.04-arm
39+
steps:
40+
- uses: actions/checkout@v4
41+
with:
42+
fetch-depth: 5
43+
- uses: subosito/flutter-action@v2
44+
with:
45+
channel: "stable"
46+
flutter-version: ${{env.FLUTTER_VERSION}}
47+
- run: sudo apt update
48+
- run: sudo apt install -y clang cmake curl libgtk-3-dev ninja-build pkg-config unzip libunwind-dev libsecret-1-dev
49+
- run: flutter pub get
50+
- run: flutter build linux --release --dart-define=${{ secrets.API_KEY }}
51+
- uses: snapcore/action-build@v1
52+
id: build
53+
- uses: snapcore/action-publish@v1
54+
if: steps.build.outcome == 'success'
55+
env:
56+
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.STORE_LOGIN }}
57+
with:
58+
snap: ${{ steps.build.outputs.snap }}
59+
release: edge

README.md

+15
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@
88

99
Requires an api key from [openweathermap](https://openweathermap.org) which you need to create yourself (free tier) in your own account.
1010

11+
1112
## Build
1213

14+
### Install libsecret
15+
16+
`sudo apt install libsecret-1-dev`
17+
1318
### Install Flutter
1419

1520
<details>
@@ -22,3 +27,13 @@ sudo apt -y install git curl cmake meson make clang libgtk-3-dev pkg-config && m
2227
```
2328

2429
</details>
30+
31+
### Run the app
32+
33+
For the first run or after every `flutter clean`, the app needs to be started with your API_KEY:
34+
35+
`flutter run --dart-define=API_KEY=YOUR_API_KEY_HERE_WITHOUT_QUOTES`
36+
37+
any other times you can use
38+
39+
`flutter run`

lib/app/app.dart

+34-36
Original file line numberDiff line numberDiff line change
@@ -17,43 +17,41 @@ class App extends StatelessWidget {
1717
const App({super.key});
1818

1919
@override
20-
Widget build(BuildContext context) {
21-
return MaterialApp(
22-
localizationsDelegates: AppLocalizations.localizationsDelegates,
23-
supportedLocales: supportedLocales,
24-
onGenerateTitle: (context) => 'MusicPod',
25-
debugShowCheckedModeBanner: false,
26-
theme: yaruLight,
27-
darkTheme: yaruDark.copyWith(
28-
tabBarTheme: TabBarTheme.of(context).copyWith(
29-
labelColor: Colors.white,
30-
unselectedLabelColor: Colors.white.withValues(
31-
alpha: 0.8,
20+
Widget build(BuildContext context) => MaterialApp(
21+
localizationsDelegates: AppLocalizations.localizationsDelegates,
22+
supportedLocales: supportedLocales,
23+
onGenerateTitle: (context) => 'MusicPod',
24+
debugShowCheckedModeBanner: false,
25+
theme: yaruLight,
26+
darkTheme: yaruDark.copyWith(
27+
tabBarTheme: TabBarTheme.of(context).copyWith(
28+
labelColor: Colors.white,
29+
unselectedLabelColor: Colors.white.withValues(
30+
alpha: 0.8,
31+
),
3232
),
3333
),
34-
),
35-
home: const StartPage(),
36-
scrollBehavior: const MaterialScrollBehavior().copyWith(
37-
dragDevices: {
38-
PointerDeviceKind.mouse,
39-
PointerDeviceKind.touch,
40-
PointerDeviceKind.stylus,
41-
PointerDeviceKind.unknown,
42-
PointerDeviceKind.trackpad,
43-
},
44-
),
45-
);
46-
}
34+
home: const _StartPage(),
35+
scrollBehavior: const MaterialScrollBehavior().copyWith(
36+
dragDevices: {
37+
PointerDeviceKind.mouse,
38+
PointerDeviceKind.touch,
39+
PointerDeviceKind.stylus,
40+
PointerDeviceKind.unknown,
41+
PointerDeviceKind.trackpad,
42+
},
43+
),
44+
);
4745
}
4846

49-
class StartPage extends StatefulWidget {
50-
const StartPage({super.key});
47+
class _StartPage extends StatefulWidget {
48+
const _StartPage();
5149

5250
@override
53-
State<StartPage> createState() => _StartPageState();
51+
State<_StartPage> createState() => _StartPageState();
5452
}
5553

56-
class _StartPageState extends State<StartPage> {
54+
class _StartPageState extends State<_StartPage> {
5755
late final Future<void> _allReady;
5856

5957
@override
@@ -66,12 +64,12 @@ class _StartPageState extends State<StartPage> {
6664
Widget build(BuildContext context) => FutureBuilder(
6765
future: _allReady,
6866
builder: (context, snapshot) =>
69-
snapshot.hasData ? const AppPage() : const LoadingPage(),
67+
snapshot.hasData ? const _AppPage() : const _LoadingPage(),
7068
);
7169
}
7270

73-
class LoadingPage extends StatelessWidget {
74-
const LoadingPage({super.key});
71+
class _LoadingPage extends StatelessWidget {
72+
const _LoadingPage();
7573

7674
@override
7775
Widget build(BuildContext context) => const Scaffold(
@@ -85,14 +83,14 @@ class LoadingPage extends StatelessWidget {
8583
);
8684
}
8785

88-
class AppPage extends StatefulWidget with WatchItStatefulWidgetMixin {
89-
const AppPage({super.key});
86+
class _AppPage extends StatefulWidget with WatchItStatefulWidgetMixin {
87+
const _AppPage();
9088

9189
@override
92-
State<AppPage> createState() => _AppPageState();
90+
State<_AppPage> createState() => _AppPageState();
9391
}
9492

95-
class _AppPageState extends State<AppPage> {
93+
class _AppPageState extends State<_AppPage> {
9694
@override
9795
void initState() {
9896
di<WeatherModel>().loadWeather();

lib/locations/locations_service.dart

-14
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,6 @@ class LocationsService {
88
}) : _settingsService = settingsService;
99
final SettingsService _settingsService;
1010

11-
String? _apiKey;
12-
String? get apiKey => _apiKey;
13-
void setApiKey(String? value) {
14-
_settingsService.setString(
15-
key: SettingKeys.apiKey,
16-
value: value ?? '',
17-
secure: true,
18-
);
19-
}
20-
2111
String? get lastLocation =>
2212
_settingsService.getString(key: SettingKeys.lastLocation);
2313
void setLastLocation(String? value) {
@@ -53,8 +43,4 @@ class LocationsService {
5343
}
5444

5545
Stream<bool> get propertiesChanged => _settingsService.propertiesChanged;
56-
57-
Future<void> init() async {
58-
_apiKey = await _settingsService.getStringSecure(key: SettingKeys.apiKey);
59-
}
6046
}

lib/register_dependencies.dart

+23-19
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,19 @@ import 'weather/weather_model.dart';
1010

1111
void registerDependencies() {
1212
di
13-
..registerSingleton<FlutterSecureStorage>(
14-
const FlutterSecureStorage(
15-
aOptions: AndroidOptions(encryptedSharedPreferences: true),
16-
),
13+
..registerSingletonAsync<FlutterSecureStorage>(
14+
() async {
15+
const flutterSecureStorage = FlutterSecureStorage(
16+
aOptions: AndroidOptions(encryptedSharedPreferences: true),
17+
);
18+
19+
const apiKey = String.fromEnvironment('API_KEY', defaultValue: '');
20+
21+
if (apiKey.isNotEmpty) {
22+
flutterSecureStorage.write(key: SettingKeys.apiKey, value: apiKey);
23+
}
24+
return flutterSecureStorage;
25+
},
1726
)
1827
..registerSingletonAsync<SharedPreferences>(
1928
() async => SharedPreferences.getInstance(),
@@ -23,26 +32,21 @@ void registerDependencies() {
2332
sharedPreferences: di<SharedPreferences>(),
2433
flutterSecureStorage: di<FlutterSecureStorage>(),
2534
),
26-
dependsOn: [SharedPreferences],
35+
dependsOn: [FlutterSecureStorage, SharedPreferences],
2736
dispose: (s) => s.dispose(),
2837
)
29-
..registerSingletonAsync<LocationsService>(
30-
() async {
31-
final locationsService = LocationsService(
32-
settingsService: di<SettingsService>(),
33-
);
34-
await locationsService.init();
35-
return locationsService;
36-
},
38+
..registerSingletonWithDependencies<LocationsService>(
39+
() => LocationsService(
40+
settingsService: di<SettingsService>(),
41+
),
3742
dependsOn: [SettingsService],
3843
)
3944
..registerSingletonAsync<OpenWeather>(
40-
() async {
41-
final apiKey = (await di<SettingsService>()
42-
.getStringSecure(key: SettingKeys.apiKey)) ??
43-
'';
44-
return OpenWeather(apiKey: apiKey);
45-
},
45+
() async => OpenWeather(
46+
apiKey:
47+
await di<FlutterSecureStorage>().read(key: SettingKeys.apiKey) ??
48+
'',
49+
),
4650
dependsOn: [SettingsService],
4751
)
4852
..registerSingletonWithDependencies(

lib/weather/weather_model.dart

-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ class WeatherModel extends SafeChangeNotifier {
2222

2323
OpenWeather _openWeather;
2424
void setApiKeyAndLoadWeather(String apiKey) {
25-
_locationsService.setApiKey(apiKey);
26-
2725
di
2826
..unregister<OpenWeather>()
2927
..registerSingleton<OpenWeather>(OpenWeather(apiKey: apiKey));

snap/snapcraft.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ architectures:
2121
parts:
2222
flutter-git:
2323
source: https://github.com/flutter/flutter.git
24-
source-tag: 3.19.5
24+
source-tag: 3.27.4
2525
plugin: nil
2626
override-build: |
2727
mkdir -p $CRAFT_PART_INSTALL/usr/bin
@@ -36,6 +36,7 @@ parts:
3636
- unzip
3737
- xz-utils
3838
- zip
39+
- libsecret-1-dev
3940
prime:
4041
- -*
4142

0 commit comments

Comments
 (0)