Skip to content
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

feat: fake realtime weather #8

Merged
merged 8 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
Binary file removed assets/thunder.png
Binary file not shown.
Binary file added assets/weather/clear.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/weather/cloudy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/weather/rainy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/weather/thunderstorms.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions lib/app/view/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:just_audio/just_audio.dart';
import 'package:music_repository/music_repository.dart';
import 'package:weather_repository/weather_repository.dart';

class App extends StatelessWidget {
const App({super.key});
Expand All @@ -13,6 +14,9 @@ class App extends StatelessWidget {
Widget build(BuildContext context) {
return MultiRepositoryProvider(
providers: [
RepositoryProvider(
create: (context) => WeatherRepository(),
),
RepositoryProvider(
create: (context) => MusicRepository(),
),
Expand Down
30 changes: 29 additions & 1 deletion lib/generated/assets.gen.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions lib/l10n/arb/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@
"welcomeMessage": "Welcome on board",
"welcomeSubtitle": "Lunch will be served in\n10 minutes",
"assistButton": "ASSIST",
"clear": "Clear",
"cloudy": "Cloudy",
"rainy": "Rainy",
"thunderstorms": "Thunderstorms"
}
1 change: 1 addition & 0 deletions lib/overview/cubit/cubit.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'overview_cubit.dart';
34 changes: 34 additions & 0 deletions lib/overview/cubit/overview_cubit.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:weather_repository/weather_repository.dart';

part 'overview_state.dart';

class OverviewCubit extends Cubit<OverviewState> {
OverviewCubit({
required WeatherRepository weatherRepository,
}) : _weatherRepository = weatherRepository,
super(const OverviewState()) {
_weatherSubscription =
_weatherRepository.weatherStream.listen(_onWeatherInfo);
}

final WeatherRepository _weatherRepository;
late final StreamSubscription<WeatherInfo> _weatherSubscription;

void _onWeatherInfo(WeatherInfo weatherInfo) {
emit(OverviewState(weatherInfo: weatherInfo));
}

void initialize() {
_onWeatherInfo(_weatherRepository.weather);
}

@override
Future<void> close() {
_weatherSubscription.cancel();
return super.close();
}
}
10 changes: 10 additions & 0 deletions lib/overview/cubit/overview_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
part of 'overview_cubit.dart';

class OverviewState extends Equatable {
const OverviewState({this.weatherInfo});

final WeatherInfo? weatherInfo;

@override
List<Object?> get props => [weatherInfo];
}
1 change: 1 addition & 0 deletions lib/overview/overview.dart
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export 'cubit/cubit.dart';
export 'view/view.dart';
export 'widgets/widgets.dart';
39 changes: 25 additions & 14 deletions lib/overview/view/overview_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:aes_ui/aes_ui.dart';
import 'package:airplane_entertainment_system/l10n/l10n.dart';
import 'package:airplane_entertainment_system/overview/overview.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class OverviewPage extends StatelessWidget {
const OverviewPage({super.key});
Expand All @@ -10,10 +11,17 @@ class OverviewPage extends StatelessWidget {
Widget build(BuildContext context) {
final layout = AesLayout.of(context);

return switch (layout) {
AesLayoutData.small => const _SmallOverviewPage(),
AesLayoutData.medium || AesLayoutData.large => const _LargeOverviewPage(),
};
return BlocProvider(
jneschisi marked this conversation as resolved.
Show resolved Hide resolved
create: (_) => OverviewCubit(
weatherRepository: context.read(),
)..initialize(),
child: switch (layout) {
AesLayoutData.small => const _SmallOverviewPage(),
AesLayoutData.medium ||
AesLayoutData.large =>
const _LargeOverviewPage(),
},
);
}
}

Expand Down Expand Up @@ -64,18 +72,21 @@ class DashBoard extends StatelessWidget {

@override
Widget build(BuildContext context) {
final weatherInfo =
context.select((OverviewCubit cubit) => cubit.state.weatherInfo);

return ListView(
padding: padding,
children: const [
WelcomeCopy(),
SizedBox(height: 40),
FlightTrackingCard(),
SizedBox(height: 20),
WeatherCard(),
SizedBox(height: 20),
MusicCard(),
SizedBox(height: 20),
MovieCard(),
children: [
const WelcomeCopy(),
const SizedBox(height: 40),
const FlightTrackingCard(),
const SizedBox(height: 20),
WeatherCard(info: weatherInfo),
const SizedBox(height: 20),
const MusicCard(),
const SizedBox(height: 20),
const MovieCard(),
],
);
}
Expand Down
155 changes: 100 additions & 55 deletions lib/overview/widgets/weather_card.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import 'dart:ui';

import 'package:airplane_entertainment_system/generated/assets.gen.dart';
import 'package:airplane_entertainment_system/l10n/l10n.dart';
import 'package:flutter/material.dart';
import 'package:weather_repository/weather_repository.dart';

class WeatherCard extends StatelessWidget {
const WeatherCard({super.key});
const WeatherCard({required this.info, super.key});

final WeatherInfo? info;

@override
Widget build(BuildContext context) {
final l10n = context.l10n;
final temperature = info?.temperature.toString() ?? '--';
final label = info?.conditionLabel(l10n) ?? '';
final gradient = info?.gradient ?? _clearWeatherGradient;
final imageAsset = info?.imageAsset;

return SizedBox(
height: 200,
child: Card(
Expand All @@ -21,18 +27,18 @@ class WeatherCard extends StatelessWidget {
padding: const EdgeInsets.all(20),
child: Column(
children: [
const Text(
'62°',
style: TextStyle(
Text(
'$temperature°',
style: const TextStyle(
fontSize: 80,
height: 0.8,
),
textHeightBehavior: TextHeightBehavior(
textHeightBehavior: const TextHeightBehavior(
applyHeightToFirstAscent: false,
),
),
Text(
l10n.thunderstorms,
label,
style: const TextStyle(fontWeight: FontWeight.bold),
textHeightBehavior: const TextHeightBehavior(
applyHeightToFirstAscent: false,
Expand All @@ -43,59 +49,48 @@ class WeatherCard extends StatelessWidget {
),
const Spacer(),
SizedBox(
width: 168,
width: 148,
height: 200,
child: Stack(
alignment: Alignment.centerRight,
fit: StackFit.expand,
clipBehavior: Clip.none,
children: [
const Positioned(
left: 20,
top: 0,
bottom: 0,
right: 0,
child: ClipRRect(
borderRadius: BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10),
),
child: DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xff0a6cba),
Color(0xff6ab9f7),
],
begin: Alignment.bottomRight,
end: Alignment.topLeft,
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
child: Stack(
key: UniqueKey(),
alignment: Alignment.centerRight,
fit: StackFit.expand,
clipBehavior: Clip.none,
children: [
Positioned(
left: 0,
top: 0,
bottom: 0,
right: 0,
child: ClipRRect(
borderRadius: const BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10),
),
child: DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: gradient,
begin: Alignment.bottomRight,
end: Alignment.topLeft,
),
),
),
),
),
),
Positioned(
right: 20,
left: 0,
child: ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: 60, sigmaY: 60),
child: Assets.thunder.image(
width: 140,
color: const Color(0x55003366),
colorBlendMode: BlendMode.srcIn,
fit: BoxFit.contain,
if (imageAsset != null)
Positioned(
left: 10,
right: 10,
child: imageAsset.image(
width: 140,
fit: BoxFit.contain,
),
),
),
),
Positioned(
right: 20,
left: 0,
child: Assets.thunder.image(
width: 140,
fit: BoxFit.contain,
),
),
],
],
),
),
),
],
Expand All @@ -104,3 +99,53 @@ class WeatherCard extends StatelessWidget {
);
}
}

const _clearWeatherGradient = [
Color.fromARGB(255, 17, 204, 251),
Color.fromARGB(255, 151, 210, 255),
];

const _cloudyWeatherGradient = [
Color.fromARGB(255, 48, 137, 209),
Color.fromARGB(255, 152, 201, 239),
];

const _rainyWeatherGradient = [
Color.fromARGB(255, 92, 134, 169),
Color.fromARGB(255, 170, 205, 233),
];

const _thunderstormsWeatherGradient = [
Color.fromARGB(255, 53, 76, 95),
Color.fromARGB(255, 179, 193, 203),
];

@visibleForTesting
extension WeatherUI on WeatherInfo {
String conditionLabel(AppLocalizations l10n) {
return switch (condition) {
WeatherCondition.clear => l10n.clear,
WeatherCondition.cloudy => l10n.cloudy,
WeatherCondition.rainy => l10n.rainy,
WeatherCondition.thunderstorms => l10n.thunderstorms,
};
}

AssetGenImage get imageAsset {
return switch (condition) {
WeatherCondition.clear => Assets.weather.clear,
WeatherCondition.cloudy => Assets.weather.cloudy,
WeatherCondition.rainy => Assets.weather.rainy,
WeatherCondition.thunderstorms => Assets.weather.thunderstorms,
};
}

List<Color> get gradient {
return switch (condition) {
WeatherCondition.clear => _clearWeatherGradient,
WeatherCondition.cloudy => _cloudyWeatherGradient,
WeatherCondition.rainy => _rainyWeatherGradient,
WeatherCondition.thunderstorms => _thunderstormsWeatherGradient,
};
}
}
Loading