diff --git a/lib/data/location/mapper/location_mapper.dart b/lib/data/location/mapper/location_mapper.dart index 42886a3..f99418a 100644 --- a/lib/data/location/mapper/location_mapper.dart +++ b/lib/data/location/mapper/location_mapper.dart @@ -8,6 +8,8 @@ class LocationMapper { longitude: dto.longitude, country: dto.country, city: dto.city, + coordinate: null, + cityName: '', ); } } diff --git a/lib/domain/entity/location.dart b/lib/domain/entity/location.dart index a9193b0..30457fe 100644 --- a/lib/domain/entity/location.dart +++ b/lib/domain/entity/location.dart @@ -7,7 +7,9 @@ class Location { Location({ required this.latitude, required this.longitude, - required this.country, + required this.country , required this.city, + required coordinate, + required String cityName, }); } diff --git a/lib/ui/components/hourly_weather_card.dart b/lib/ui/components/hourly_weather_card.dart index 9d1f4e4..620f4ef 100644 --- a/lib/ui/components/hourly_weather_card.dart +++ b/lib/ui/components/hourly_weather_card.dart @@ -1,20 +1,20 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../domain/model/temperature.dart'; import '../cubit/theme/theme_cubit.dart'; class HourlyWeatherCard extends StatelessWidget { - final String weatherImage; - final String degree; - final String hour; + final int hour; + final Temperature temperature; + final int weatherCode; const HourlyWeatherCard({ super.key, - required this.weatherImage, - required this.degree, + required this.weatherCode, + required this.temperature, required this.hour, }); - @override @override Widget build(BuildContext context) { final theme = context.watch().state; @@ -37,11 +37,10 @@ class HourlyWeatherCard extends StatelessWidget { child: Padding( padding: const EdgeInsets.only(bottom: 16), child: Column( - spacing: 4, mainAxisAlignment: MainAxisAlignment.end, children: [ Text( - degree, + '${temperature.temperature.round()}°${temperature.unit.name.substring(0, 1).toUpperCase()}', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, @@ -49,8 +48,9 @@ class HourlyWeatherCard extends StatelessWidget { color: theme.colors.text87, ), ), + const SizedBox(height: 4), Text( - hour, + "$hour:00", style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, @@ -63,64 +63,275 @@ class HourlyWeatherCard extends StatelessWidget { ), ), ), - Image.asset(weatherImage, height: 58, fit: BoxFit.cover), + Image.asset( + getWeatherImagePathByCode(weatherCode), + height: 58, + ), ], ), ); } } -var weatherDate = [ - HourlyWeatherData( - weatherImage: 'assets/images/day_rain_shower_violent.png', - degree: '25°C', - hour: '11:00 ', - ), - HourlyWeatherData( - weatherImage: 'assets/images/day_clear_sky.png', - degree: '21°C', - hour: '12:00 ', - ), - HourlyWeatherData( - weatherImage: 'assets/images/day_snow_fall_moderate.png', - degree: '19°C', - hour: '01:00 ', - ), - HourlyWeatherData( - weatherImage: 'assets/images/day_rain_intensity.png', - degree: '21°C', - hour: '02:00 ', - ), - HourlyWeatherData( - weatherImage: 'assets/images/day_mainly_clear.png', - degree: '25°C', - hour: '04:00 ', - ), - HourlyWeatherData( - weatherImage: 'assets/images/day_clear_sky.png', - degree: '25°C', - hour: '05:00 ', - ), - HourlyWeatherData( - weatherImage: 'assets/images/day_clear_sky.png', - degree: '25°C', - hour: '06:00 ', - ), - HourlyWeatherData( - weatherImage: 'assets/images/day_freezing_heavy.png', - degree: '3', - hour: '07:00 ', - ), -]; +String getWeatherImagePathByCode(int weatherCode, {bool isDay = true}) { + final condition = getWeatherConditionByCode(weatherCode); + return isDay ? condition.dayImagePath : condition.nightImagePath; +} -class HourlyWeatherData { - final String weatherImage; - final String degree; - final String hour; +WeatherCondition getWeatherConditionByCode(int code) { + return WeatherCondition.values.firstWhere( + (condition) => condition.weatherCode == code, + orElse: () => WeatherCondition.unknownWeatherForecast, + ); +} - const HourlyWeatherData({ - required this.weatherImage, - required this.degree, - required this.hour, - }); +enum WeatherCondition { + clearSky( + 0, + "Clear Sky", + "assets/images/day_clear_sky.png", + "assets/images/night_clear_sky.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + mainlyClear( + 1, + "Mainly Clear", + "assets/images/day_mainly_clear.png", + "assets/images/night_mainly_clear.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + partlyCloudy( + 2, + "Partly Cloudy", + "assets/images/day_partly_cloudy.png", + "assets/images/night_partly_cloudy.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + overcast( + 3, + "Overcast", + "assets/images/day_overcast.png", + "assets/images/night_overcast.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + fog( + 45, + "Fog", + "assets/images/day_fog.png", + "assets/images/night_fog.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + depositingRimeFog( + 48, + "Depositing Rime Fog", + "assets/images/day_fog.png", + "assets/images/night_fog.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + drizzleLight( + 51, + "Light Drizzle", + "assets/images/day_drizzle_light.png", + "assets/images/night_drizzle_light.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + drizzleModerate( + 53, + "Moderate Drizzle", + "assets/images/day_drizzle_moderate.png", + "assets/images/night_drizzle_moderate.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + drizzleHigh( + 55, + "High Drizzle", + "assets/images/day_drizzle_intensity.png", + "assets/images/night_drizzle_intensity.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + freezingDrizzleLight( + 56, + "Light Freezing Drizzle", + "assets/images/day_drizzle_light.png", + "assets/images/night_drizzle_light.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + freezingDrizzleHigh( + 57, + "High Freezing Drizzle", + "assets/images/day_freezing_drizzle_intensity.png", + "assets/images/night_freezing_drizzle_intensity.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + rainLight( + 61, + "Light Rain", + "assets/images/day_rain_slight.png", + "assets/images/night_rain_slight.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + rainModerate( + 63, + "Moderate Rain", + "assets/images/day_rain_moderate.png", + "assets/images/night_rain_moderate.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + rainHeavy( + 65, + "Heavy Rain", + "assets/images/day_rain_intensity.png", + "assets/images/night_rain_intensity.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + freezingRainLight( + 66, + "Light Freezing Rain", + "assets/images/day_freezing_light.png", + "assets/images/night_freezing_light.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + freezingRainHigh( + 67, + "High Freezing Rain", + "assets/images/day_freezing_heavy.png", + "assets/images/night_freezing_heavy.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + snowLight( + 71, + "Light Snow", + "assets/images/day_snow_fall_light.png", + "assets/images/night_snow_fall_light.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + snowModerate( + 73, + "Moderate Snow", + "assets/images/day_snow_fall_moderate.png", + "assets/images/night_snow_fall_moderate.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + snowHeavy( + 75, + "Heavy Snow", + "assets/images/day_snow_fall_intensity.png", + "assets/images/night_snow_fall_intensity.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + snowGrains( + 77, + "Grains Snow", + "assets/images/day_snow_grains.png", + "assets/images/night_snow_grains.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + rainShowerLight( + 80, + "Light Rain Shower", + "assets/images/day_rain_shower_slight.png", + "assets/images/night_rain_shower_slight.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + rainShowerModerate( + 81, + "Moderate Rain Shower", + "assets/images/day_rain_shower_moderate.png", + "assets/images/night_rain_shower_moderate.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + rainShowerHeavy( + 82, + "Heavy Rain Shower", + "assets/images/day_rain_shower_violent.png", + "assets/images/night_rain_shower_violent.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + snowShowerLight( + 85, + "Light Snow Shower", + "assets/images/day_snow_shower_slight.png", + "assets/images/night_snow_shower_slight.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + snowShowerHeavy( + 86, + "Heavy Snow Shower", + "assets/images/day_snow_shower_heavy.png", + "assets/images/night_snow_shower_heavy.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + thunderStorm( + 95, + "Thunderstorm", + "assets/images/day_thunderstrom_slight_or_moderate.png", + "assets/images/night_thunderstrom_slight_or_moderate.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + thunderStormHailLight( + 96, + "Thunderstorm with Light Hail", + "assets/images/day_thunderstrom_with_slight_hail.png", + "assets/images/night_thunderstrom_with_slight_hail.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + thunderStormHailHeavy( + 99, + "Thunderstorm with Heavy Hail", + "assets/images/day_thunderstrom_with_heavy_hail.png", + "assets/images/night_thunderstrom_with_heavy_hail.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ), + unknownWeatherForecast( + -1, + "Unknown Weather Forecast", + "assets/images/day_clear_sky.png", + "assets/images/night_clear_sky.png", + Color(0xFFFFC701), + Color(0xFF7E2FFF), + ); + + const WeatherCondition( + this.weatherCode, + this.stateName, + this.dayImagePath, + this.nightImagePath, + this.dayShadowColor, + this.nightShadowColor, + ); + + final int weatherCode; + final String stateName; + final String dayImagePath; + final String nightImagePath; + final Color dayShadowColor; + final Color nightShadowColor; } diff --git a/lib/ui/components/hourly_weather_row.dart b/lib/ui/components/hourly_weather_row.dart new file mode 100644 index 0000000..cc1039a --- /dev/null +++ b/lib/ui/components/hourly_weather_row.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:weather_app/domain/model/hourly_status.dart'; +import 'package:weather_app/ui/components/hourly_weather_card.dart'; + +class HourlyWeatherDetails extends StatelessWidget { + final List hourlyWeather; + + const HourlyWeatherDetails({super.key, required this.hourlyWeather}); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 132, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: hourlyWeather.length, + itemBuilder: (context, index) { + final item = hourlyWeather[index]; + return HourlyWeatherCard( + weatherCode: item.weatherCode, + temperature: item.temperature, + hour: item.hour, + ); + }, + separatorBuilder: (context, index) => const SizedBox(width: 12), + ), + ); + } +} diff --git a/lib/ui/screen/weather_screen.dart b/lib/ui/screen/weather_screen.dart index e44e092..b80065d 100644 --- a/lib/ui/screen/weather_screen.dart +++ b/lib/ui/screen/weather_screen.dart @@ -7,6 +7,7 @@ import 'package:weather_app/ui/cubit/location/location_cubit.dart'; import 'package:weather_app/ui/cubit/weather/weather_cubit.dart'; import '../components/current_weather_card.dart'; +import '../components/hourly_weather_row.dart'; import '../components/location_row.dart'; import '../components/weather_details.dart'; import '../cubit/theme/theme_cubit.dart'; @@ -34,19 +35,19 @@ class WeatherScreen extends StatelessWidget { listener: (context, state) { if (state is LocationLoaded) { context.read().getWeather( - locationCoordinate: LocationCoordinate( - latitude: state.location.latitude, - longitude: state.location.longitude, - ), - ); + locationCoordinate: LocationCoordinate( + latitude: state.location.latitude, + longitude: state.location.longitude, + ), + ); } }, child: BlocConsumer( listener: (context, state) { if (state is WeatherLoaded) { context.read().updateTheme( - state.weather.isDaytime, - ); + state.weather.isDaytime, + ); } }, builder: (context, state) { @@ -54,8 +55,8 @@ class WeatherScreen extends StatelessWidget { WeatherInitial() => _CustomLoading(), WeatherLoading() => _CustomLoading(), WeatherLoaded() => _WeatherScreenContent( - weather: state.weather, - ), + weather: state.weather, + ), WeatherError() => _CustomLoading(), }; }, @@ -83,6 +84,8 @@ class _WeatherScreenContent extends StatelessWidget { @override Widget build(BuildContext context) { + final theme = context.watch().state; + return Padding( padding: EdgeInsets.only( top: MediaQuery.of(context).padding.top, @@ -144,6 +147,23 @@ class _WeatherScreenContent extends StatelessWidget { ], ), ), + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.only(left: 12.0,top: 24.0, bottom: 12.0), + child: Text( + 'Today', + style: TextStyle( + color: theme.colors.text, + fontSize: 20, + letterSpacing: 0.25, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + SliverToBoxAdapter( + child: HourlyWeatherDetails(hourlyWeather: weather.hourlyStatus), + ), ], ), );