Skip to content

chore: update flutter, remove custom settings, build snap on github #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 10, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ on:
branches: [master]

env:
FLUTTER_VERSION: '3.19.x'
FLUTTER_VERSION: '3.27.4'

jobs:
analyze:
@@ -49,6 +49,6 @@ jobs:
channel: 'stable'
flutter-version: ${{env.FLUTTER_VERSION}}
- run: sudo apt update
- run: sudo apt install -y clang cmake curl libgtk-3-dev ninja-build pkg-config unzip libunwind-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libmpv-dev
- run: sudo apt install -y clang cmake curl libgtk-3-dev ninja-build pkg-config unzip libunwind-dev libsecret-1-dev
- run: flutter pub get
- run: flutter build linux -v
59 changes: 59 additions & 0 deletions .github/workflows/snap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Create Snap Package

on:
push:
branches:
- main
workflow_dispatch:

env:
FLUTTER_VERSION: "3.27.4"

jobs:
build_and_release_linux_snap_edge_amd64:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 5
- uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{env.FLUTTER_VERSION}}
- run: sudo apt update
- run: sudo apt install -y clang cmake curl libgtk-3-dev ninja-build pkg-config unzip libunwind-dev libsecret-1-dev
- run: flutter pub get
- run: flutter build linux --release --dart-define=${{ secrets.API_KEY }}
- uses: snapcore/action-build@v1
id: build
- uses: snapcore/action-publish@v1
if: steps.build.outcome == 'success'
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.STORE_LOGIN }}
with:
snap: ${{ steps.build.outputs.snap }}
release: edge

build_and_release_linux_snap_edge_arm64:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 5
- uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{env.FLUTTER_VERSION}}
- run: sudo apt update
- run: sudo apt install -y clang cmake curl libgtk-3-dev ninja-build pkg-config unzip libunwind-dev libsecret-1-dev
- run: flutter pub get
- run: flutter build linux --release --dart-define=${{ secrets.API_KEY }}
- uses: snapcore/action-build@v1
id: build
- uses: snapcore/action-publish@v1
if: steps.build.outcome == 'success'
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.STORE_LOGIN }}
with:
snap: ${{ steps.build.outputs.snap }}
release: edge
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -8,8 +8,13 @@

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


## Build

### Install libsecret

`sudo apt install libsecret-1-dev`

### Install Flutter

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

</details>

### Run the app

For the first run or after every `flutter clean`, the app needs to be started with your API_KEY:

`flutter run --dart-define=API_KEY=YOUR_API_KEY_HERE_WITHOUT_QUOTES`

any other times you can use

`flutter run`
7 changes: 6 additions & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -10,4 +10,9 @@ linter:
require_trailing_commas: true
use_super_parameters: true
close_sinks: true
prefer_relative_imports: true
prefer_relative_imports: true
sort_pub_dependencies: true
unnecessary_parenthesis: true
unnecessary_await_in_return: true
unnecessary_late: true
unnecessary_breaks: true
2 changes: 1 addition & 1 deletion l10n.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
arb-dir: lib/src/l10n
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
nullable-getter: false
133 changes: 133 additions & 0 deletions lib/app/app.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import 'dart:io';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter_weather_bg_null_safety/bg/weather_bg.dart';
import 'package:watch_it/watch_it.dart';
import 'package:yaru/yaru.dart';

import '../constants.dart';
import '../weather.dart';
import '../extensions/build_context_x.dart';
import '../l10n/l10n.dart';
import '../weather/weather_model.dart';
import 'side_bar.dart';

class App extends StatelessWidget {
const App({super.key});

@override
Widget build(BuildContext context) => MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: supportedLocales,
onGenerateTitle: (context) => 'MusicPod',
debugShowCheckedModeBanner: false,
theme: yaruLight,
darkTheme: yaruDark.copyWith(
tabBarTheme: TabBarTheme.of(context).copyWith(
labelColor: Colors.white,
unselectedLabelColor: Colors.white.withValues(
alpha: 0.8,
),
),
),
home: const _StartPage(),
scrollBehavior: const MaterialScrollBehavior().copyWith(
dragDevices: {
PointerDeviceKind.mouse,
PointerDeviceKind.touch,
PointerDeviceKind.stylus,
PointerDeviceKind.unknown,
PointerDeviceKind.trackpad,
},
),
);
}

class _StartPage extends StatefulWidget {
const _StartPage();

@override
State<_StartPage> createState() => _StartPageState();
}

class _StartPageState extends State<_StartPage> {
late final Future<void> _allReady;

@override
void initState() {
super.initState();
_allReady = di.allReady();
}

@override
Widget build(BuildContext context) => FutureBuilder(
future: _allReady,
builder: (context, snapshot) =>
snapshot.hasData ? const _AppPage() : const _LoadingPage(),
);
}

class _LoadingPage extends StatelessWidget {
const _LoadingPage();

@override
Widget build(BuildContext context) => const Scaffold(
appBar: YaruWindowTitleBar(
border: BorderSide.none,
backgroundColor: Colors.transparent,
),
body: Center(
child: YaruCircularProgressIndicator(),
),
);
}

class _AppPage extends StatefulWidget with WatchItStatefulWidgetMixin {
const _AppPage();

@override
State<_AppPage> createState() => _AppPageState();
}

class _AppPageState extends State<_AppPage> {
@override
void initState() {
di<WeatherModel>().loadWeather();
super.initState();
}

@override
Widget build(BuildContext context) {
final weatherType = watchPropertyValue((WeatherModel m) => m.weatherType);

return LayoutBuilder(
builder: (context, constraints) {
var list = [
if (constraints.maxWidth > kBreakPoint) const SideBar(),
Expanded(
child: WeatherPage(
showDrawer: constraints.maxWidth < kBreakPoint,
),
),
];
return Stack(
alignment: Alignment.center,
children: [
Opacity(
opacity: Platform.isMacOS ? (context.light ? 1 : 0.6) : 0.7,
child: WeatherBg(
weatherType: weatherType,
width: constraints.maxWidth,
height: constraints.maxHeight,
),
),
Row(
children: Platform.isMacOS ? list.reversed.toList() : list,
),
],
);
},
);
}
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:yaru/yaru.dart';

import '../build_context_x.dart';
import '../extensions/build_context_x.dart';
import '../l10n/l10n.dart';

class OfflinePage extends StatelessWidget {
6 changes: 3 additions & 3 deletions lib/src/app/side_bar.dart → lib/app/side_bar.dart
Original file line number Diff line number Diff line change
@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:watch_it/watch_it.dart';
import 'package:yaru/yaru.dart';

import '../../constants.dart';
import '../build_context_x.dart';
import '../constants.dart';
import '../extensions/build_context_x.dart';
import '../weather/view/city_search_field.dart';
import '../weather/weather_model.dart';

@@ -66,7 +66,7 @@ class SideBar extends StatelessWidget with WatchItMixin {
);

return Material(
color: theme.colorScheme.surface.withOpacity(0.4),
color: theme.colorScheme.surface.withValues(alpha: 0.4),
child: SizedBox(
width: kPaneWidth,
child: Column(
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
46 changes: 46 additions & 0 deletions lib/locations/locations_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'dart:async';

import '../settings/settings_service.dart';

class LocationsService {
LocationsService({
required SettingsService settingsService,
}) : _settingsService = settingsService;
final SettingsService _settingsService;

String? get lastLocation =>
_settingsService.getString(key: SettingKeys.lastLocation);
void setLastLocation(String? value) {
if (value == null) return;
_settingsService.setString(key: SettingKeys.lastLocation, value: value);
}

Set<String> get favLocations =>
_settingsService
.getStrings(key: SettingKeys.favoriteLocations)
?.toSet() ??
{};
bool isFavLocation(String value) => favLocations.contains(value);

void addFavLocation(String name) {
if (favLocations.contains(name)) return;
final favs = Set<String>.from(favLocations);
favs.add(name);
_settingsService.setStrings(
key: SettingKeys.favoriteLocations,
value: favs.toList(),
);
}

Future<void> removeFavLocation(String name) async {
if (!favLocations.contains(name)) return;
final favs = Set<String>.from(favLocations);
favs.remove(name);
_settingsService.setStrings(
key: SettingKeys.favoriteLocations,
value: favs.toList(),
);
}

Stream<bool> get propertiesChanged => _settingsService.propertiesChanged;
}
24 changes: 3 additions & 21 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,31 +1,13 @@
import 'package:flutter/material.dart';
import 'package:open_weather_client/open_weather.dart';
import 'package:watch_it/watch_it.dart';
import 'package:yaru/yaru.dart';

import 'src/app/app.dart';
import 'src/app/app_model.dart';
import 'src/locations/locations_service.dart';
import 'src/weather/weather_model.dart';
import 'app/app.dart';
import 'register_dependencies.dart';

Future<void> main() async {
await YaruWindowTitleBar.ensureInitialized();

final locationsService = LocationsService();
await locationsService.init();
di.registerSingleton<LocationsService>(
locationsService,
dispose: (s) => s.dispose(),
);
di.registerSingleton(AppModel());

di.registerLazySingleton(
() => WeatherModel(
locationsService: locationsService,
openWeather: OpenWeather(apiKey: locationsService.apiKey ?? ''),
),
dispose: (s) => s.dispose(),
);
registerDependencies();

runApp(const App());
}
Loading