Skip to content
Merged
Show file tree
Hide file tree
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
15 changes: 10 additions & 5 deletions lib/app/router/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import 'package:dpip/features/sponsor/presentation/pages/sponsor_page.dart';
import 'package:dpip/features/bug_tracker/presentation/pages/bug_list_page.dart';
import 'package:dpip/features/bug_tracker/presentation/pages/bug_thread_page.dart';
import 'package:dpip/features/status/presentation/pages/server_status_page.dart';
import 'package:dpip/features/weather/domain/weather_ranking.dart';
import 'package:dpip/features/weather/presentation/pages/weather_ranking_page.dart';
import 'package:dpip/shared/navigation/app_routes.dart';
import 'package:dpip/shared/navigation/refresh_on_appear.dart';
Expand Down Expand Up @@ -148,11 +149,15 @@ final GoRouter appRouter = GoRouter(
GoRoute(
path: AppRoutes.weatherRankingPath,
name: AppRoutes.weatherRanking,
builder: (_, state) => WeatherRankingPage(
initialTab: WeatherRankingTab.parse(
state.uri.queryParameters['tab'],
),
),
builder: (_, state) {
final rawTab = state.uri.queryParameters['tab'];
return WeatherRankingPage(
initialTab: WeatherRankingTab.parse(rawTab),
initialTempMetric: TempRankMetric.parse(
state.uri.queryParameters['metric'] ?? rawTab,
),
);
},
),
GoRoute(
path: AppRoutes.moonPath,
Expand Down
63 changes: 63 additions & 0 deletions lib/features/weather/domain/weather_ranking.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,37 @@ enum RankingMerge {
county,
}

/// Which temperature figure a ranking shows: the observation itself (at
/// whichever snapshot the list is drawn from) or one of the day's recorded
/// extremes.
///
/// Temperature is the only metric whose extremes the v5 snapshot carries
/// (`hi` / `lo` with their occurrence times), so it is the only one the app can
/// rank as an extreme without inventing one.
enum TempRankMetric {
/// The temperature recorded at the snapshot.
current,

/// The day's recorded maximum (`hi`).
high,

/// The day's recorded minimum (`lo`).
low,

/// Diurnal range (`hi − lo`).
range;

/// Parses the deep-link values the Data hub links use: the current metric,
/// and the aliases the standalone daily-extremes tab had before it became a
/// chip inside the temperature tab (`?tab=tempExtremes`, `?tab=low`, …).
static TempRankMetric parse(String? raw) => switch (raw) {
'high' || 'tempHigh' || 'tempExtremes' || 'extremes' => TempRankMetric.high,
'low' || 'tempLow' => TempRankMetric.low,
'range' => TempRankMetric.range,
_ => TempRankMetric.current,
};
}

/// Which daily-temperature extreme to rank by.
enum TempExtremeMetric {
/// Recorded daily maximum (`hi`).
Expand Down Expand Up @@ -177,6 +208,38 @@ List<RankedObservation> rankTempExtremes({
);
}

/// Ranks temperature by [metric]: the reading in the snapshot itself, or one of
/// the day's recorded extremes. One entry point so the temperature tab does not
/// have to know which of the two implementations backs the chip it is on.
List<RankedObservation> rankTemperature({
required Map<String, WeatherStation> stations,
required WeatherSnapshot snapshot,
required TempRankMetric metric,
required bool ascending,
required RankingMerge merge,
}) => switch (metric) {
TempRankMetric.current => rankWeather(
stations: stations,
snapshot: snapshot,
valueOf: (o) => o.temperature,
ascending: ascending,
merge: merge,
),
TempRankMetric.high ||
TempRankMetric.low ||
TempRankMetric.range => rankTempExtremes(
stations: stations,
snapshot: snapshot,
metric: switch (metric) {
TempRankMetric.high => TempExtremeMetric.high,
TempRankMetric.low => TempExtremeMetric.low,
_ => TempExtremeMetric.range,
},
ascending: ascending,
merge: merge,
),
};

class RankInput {
const RankInput({
required this.id,
Expand Down
Loading
Loading