Skip to content
This repository has been archived by the owner on Aug 26, 2023. It is now read-only.

Commit

Permalink
Add support for imperial units (#242)
Browse files Browse the repository at this point in the history
Co-authored-by: mhmdanas <triallax@tutanota.com>
  • Loading branch information
prestosole and triallax authored Jan 23, 2022
1 parent f3139c6 commit a652d03
Show file tree
Hide file tree
Showing 22 changed files with 772 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import 'package:clima_core/either.dart';
import 'package:clima_core/failure.dart';
import 'package:clima_data/models/unit_system_model.dart';
import 'package:clima_data/providers.dart';
import 'package:riverpod/riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';

const _prefsKey = 'unit_system';

class UnitSystemLocalDataSource {
UnitSystemLocalDataSource(this._prefs);

final SharedPreferences _prefs;

Future<Either<Failure, UnitSystemModel?>> getUnitSystem() async {
final string = _prefs.getString(_prefsKey);

if (string == null) return const Right(null);

return Right(UnitSystemModel.parse(string));
}

Future<Either<Failure, void>> setUnitSystem(UnitSystemModel model) async {
await _prefs.setString(_prefsKey, model.toString());

return const Right(null);
}
}

final unitSystemLocalDataSourceProvider = Provider(
(ref) => UnitSystemLocalDataSource(ref.watch(sharedPreferencesProvider)),
);
5 changes: 5 additions & 0 deletions packages/clima_data/lib/models/full_weather_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:clima_domain/entities/city.dart';
import 'package:clima_domain/entities/daily_forecast.dart';
import 'package:clima_domain/entities/full_weather.dart';
import 'package:clima_domain/entities/hourly_forecast.dart';
import 'package:clima_domain/entities/unit_system.dart';
import 'package:clima_domain/entities/weather.dart';
import 'package:equatable/equatable.dart';

Expand All @@ -26,8 +27,10 @@ class FullWeatherModel extends Equatable {
return FullWeatherModel(
FullWeather(
city: city,
unitSystem: UnitSystem.metric,
timeZoneOffset: Duration(seconds: json['timezone_offset'] as int),
currentWeather: Weather(
unitSystem: UnitSystem.metric,
temperature: (currentWeatherJson['temp'] as num).toDouble(),
tempFeel: (currentWeatherJson['feels_like'] as num).toDouble(),
// We multiply by 3.6 to convert from m/s to km/h.
Expand All @@ -46,6 +49,7 @@ class FullWeatherModel extends Equatable {
dailyForecasts: (json['daily'] as List)
.map(
(forecastJson) => DailyForecast(
unitSystem: UnitSystem.metric,
maxTemperature: (forecastJson['temp']['max'] as num).toDouble(),
minTemperature: (forecastJson['temp']['min'] as num).toDouble(),
date:
Expand All @@ -62,6 +66,7 @@ class FullWeatherModel extends Equatable {
hourlyForecasts: [
for (final forecastJson in json['hourly'] as List)
HourlyForecast(
unitSystem: UnitSystem.metric,
date: date_time_utils.fromUtcUnixTime(forecastJson['dt'] as int),
iconCode: forecastJson['weather'][0]['icon'] as String,
temperature: (forecastJson['temp'] as num).toDouble(),
Expand Down
41 changes: 41 additions & 0 deletions packages/clima_data/lib/models/unit_system_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import 'package:clima_domain/entities/unit_system.dart';
import 'package:equatable/equatable.dart';

class UnitSystemModel extends Equatable {
const UnitSystemModel(this.unitSystem);

final UnitSystem unitSystem;

factory UnitSystemModel.parse(String string) {
switch (string) {
case 'metric':
return const UnitSystemModel(UnitSystem.metric);

case 'imperial':
return const UnitSystemModel(UnitSystem.imperial);

default:
throw ArgumentError();
}
}

@override
String toString() {
switch (unitSystem) {
case UnitSystem.metric:
return 'metric';

case UnitSystem.imperial:
return 'imperial';
}
}

@override
List<Object?> get props => [unitSystem];
}
32 changes: 32 additions & 0 deletions packages/clima_data/lib/repos/unit_system_repo_impl.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import 'package:clima_core/either.dart';
import 'package:clima_core/failure.dart';
import 'package:clima_data/data_sources/unit_system_local_data_source.dart';
import 'package:clima_data/models/unit_system_model.dart';
import 'package:clima_domain/entities/unit_system.dart';
import 'package:clima_domain/repos/unit_system_repo.dart';
import 'package:riverpod/riverpod.dart';

class UnitSystemRepoImpl implements UnitSystemRepo {
final UnitSystemLocalDataSource _localDataSource;

UnitSystemRepoImpl(this._localDataSource);

@override
Future<Either<Failure, UnitSystem>> getUnitSystem() async =>
(await _localDataSource.getUnitSystem())
.map((model) => model?.unitSystem ?? UnitSystem.metric);

@override
Future<Either<Failure, void>> setUnitSystem(UnitSystem unitSystem) =>
_localDataSource.setUnitSystem(UnitSystemModel(unitSystem));
}

final unitSystemRepoImplProvider = Provider(
(ref) => UnitSystemRepoImpl(ref.watch(unitSystemLocalDataSourceProvider)),
);
4 changes: 4 additions & 0 deletions packages/clima_data/test/models/full_weather_model_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:clima_data/utils/date_time.dart' as date_time_utils;
import 'package:clima_domain/entities/city.dart';
import 'package:clima_domain/entities/daily_forecast.dart';
import 'package:clima_domain/entities/hourly_forecast.dart';
import 'package:clima_domain/entities/unit_system.dart';
import 'package:clima_domain/entities/weather.dart';
import 'package:flutter_test/flutter_test.dart';

Expand All @@ -30,6 +31,7 @@ void main() {
expect(
fullWeather.currentWeather,
Weather(
unitSystem: UnitSystem.metric,
date: date_time_utils.fromUtcUnixTime(1634313115),
temperature: 27.16,
tempFeel: 29.5,
Expand All @@ -47,6 +49,7 @@ void main() {
expect(
fullWeather.hourlyForecasts[0],
HourlyForecast(
unitSystem: UnitSystem.metric,
temperature: 27.16,
iconCode: "01n",
date: date_time_utils.fromUtcUnixTime(1634310000),
Expand All @@ -55,6 +58,7 @@ void main() {
);

final dailyForecast = DailyForecast(
unitSystem: UnitSystem.metric,
date: date_time_utils.fromUtcUnixTime(1634284800),
sunrise: date_time_utils.fromUtcUnixTime(1634264178),
sunset: date_time_utils.fromUtcUnixTime(1634307772),
Expand Down
50 changes: 46 additions & 4 deletions packages/clima_domain/lib/entities/daily_forecast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import 'package:clima_domain/entities/unit_system.dart';
import 'package:clima_domain/utils/unit_conversion.dart';
import 'package:equatable/equatable.dart';

class DailyForecast extends Equatable {
Expand All @@ -13,17 +15,17 @@ class DailyForecast extends Equatable {

final DateTime sunset;

/// Minimum temperature at the moment. In degrees Celsius (for now).
final double minTemperature;

/// Maximum temperature at the moment. In degrees Celsius (for now).
final double maxTemperature;

/// Probability of precipitation.
final double pop;

final String iconCode;

final UnitSystem unitSystem;

const DailyForecast({
required this.date,
required this.sunrise,
Expand All @@ -32,9 +34,49 @@ class DailyForecast extends Equatable {
required this.maxTemperature,
required this.pop,
required this.iconCode,
required this.unitSystem,
});

@override
List<Object?> get props =>
[date, sunrise, sunset, minTemperature, maxTemperature, pop, iconCode];
List<Object?> get props => [
date,
sunrise,
sunset,
minTemperature,
maxTemperature,
pop,
iconCode,
unitSystem
];

DailyForecast changeUnitSystem(UnitSystem newUnitSystem) {
if (unitSystem == newUnitSystem) {
return this;
}

final double newMaxTemperature;
final double newMinTemperature;

switch (unitSystem) {
case UnitSystem.imperial:
newMaxTemperature = convertFahrenheitToCelsius(maxTemperature);
newMinTemperature = convertFahrenheitToCelsius(minTemperature);
break;

case UnitSystem.metric:
newMaxTemperature = convertCelsiusToFahrenheit(maxTemperature);
newMinTemperature = convertCelsiusToFahrenheit(minTemperature);
}

return DailyForecast(
date: date,
iconCode: iconCode,
sunrise: sunrise,
sunset: sunset,
pop: pop,
maxTemperature: newMaxTemperature,
minTemperature: newMinTemperature,
unitSystem: newUnitSystem,
);
}
}
35 changes: 33 additions & 2 deletions packages/clima_domain/lib/entities/full_weather.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import 'package:clima_domain/entities/daily_forecast.dart';
import 'package:clima_domain/entities/hourly_forecast.dart';
import 'package:clima_domain/entities/unit_system.dart';
import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart';

Expand All @@ -19,6 +20,7 @@ class FullWeather extends Equatable {
required this.currentWeather,
required this.dailyForecasts,
required this.hourlyForecasts,
required this.unitSystem,
});

final City city;
Expand All @@ -31,6 +33,8 @@ class FullWeather extends Equatable {

final List<HourlyForecast> hourlyForecasts;

final UnitSystem unitSystem;

DailyForecast get currentDayForecast => minBy(
dailyForecasts.where(
(forecast) => forecast.date.weekday == currentWeather.date.weekday,
Expand All @@ -39,6 +43,33 @@ class FullWeather extends Equatable {
)!;

@override
List<Object> get props =>
[city, timeZoneOffset, currentWeather, dailyForecasts, hourlyForecasts];
List<Object> get props => [
city,
timeZoneOffset,
currentWeather,
dailyForecasts,
hourlyForecasts,
unitSystem
];

FullWeather changeUnitSystem(UnitSystem newUnitSystem) {
if (unitSystem == newUnitSystem) {
return this;
}

return FullWeather(
unitSystem: newUnitSystem,
city: city,
timeZoneOffset: timeZoneOffset,
currentWeather: currentWeather.changeUnitSystem(newUnitSystem),
hourlyForecasts: [
for (final forecast in hourlyForecasts)
forecast.changeUnitSystem(newUnitSystem)
],
dailyForecasts: [
for (final forecast in dailyForecasts)
forecast.changeUnitSystem(newUnitSystem)
],
);
}
}
33 changes: 31 additions & 2 deletions packages/clima_domain/lib/entities/hourly_forecast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,55 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import 'package:clima_domain/entities/unit_system.dart';
import 'package:clima_domain/utils/unit_conversion.dart';
import 'package:equatable/equatable.dart';

class HourlyForecast extends Equatable {
final DateTime date;

/// In degrees Celsius (for now).
final double temperature;

/// Probability of precipitation.
final double pop;

final String iconCode;

final UnitSystem unitSystem;

const HourlyForecast({
required this.date,
required this.temperature,
required this.pop,
required this.iconCode,
required this.unitSystem,
});

@override
List<Object?> get props => [date, temperature, pop, iconCode];
List<Object?> get props => [date, temperature, pop, iconCode, unitSystem];

HourlyForecast changeUnitSystem(UnitSystem newUnitSystem) {
if (unitSystem == newUnitSystem) {
return this;
}

final double newTemperature;

switch (unitSystem) {
case UnitSystem.imperial:
newTemperature = convertFahrenheitToCelsius(temperature);
break;

case UnitSystem.metric:
newTemperature = convertCelsiusToFahrenheit(temperature);
}

return HourlyForecast(
pop: pop,
date: date,
temperature: newTemperature,
iconCode: iconCode,
unitSystem: newUnitSystem,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,4 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import 'package:riverpod/riverpod.dart';

enum UnitSystem { metric, imperial }

final unitProvider = StateProvider((ref) => UnitSystem.metric);
Loading

0 comments on commit a652d03

Please sign in to comment.