-
Notifications
You must be signed in to change notification settings - Fork 21
Feat earthquake report #521
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
Open
PiscesXD
wants to merge
3
commits into
main
Choose a base branch
from
feat-earthquake-report
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ library; | |
| import 'package:dpip/core/error/result.dart'; | ||
| import 'package:dpip/core/network/api_exception.dart'; | ||
| import 'package:dpip/features/earthquake/data/earthquake_api.dart'; | ||
| import 'package:dpip/features/earthquake/domain/earthquake_report.dart'; | ||
| import 'package:dpip/features/earthquake/domain/partial_earthquake_report.dart'; | ||
| import 'package:dpip/features/earthquake/domain/report_list_query.dart'; | ||
| import 'package:dpip/features/earthquake/domain/report_repository.dart'; | ||
|
|
@@ -40,6 +41,12 @@ class ReportRepositoryImpl implements ReportRepository { | |
| return parseReportList(raw); | ||
| }); | ||
|
|
||
| @override | ||
| Future<Result<EarthquakeReport>> get(String id) => guardResult(() async { | ||
| final raw = await _api.getReport(id); | ||
| return EarthquakeReport.fromJson((raw as Map).cast<String, dynamic>()); | ||
| }); | ||
|
Comment on lines
+44
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [maintainability · low] |
||
|
|
||
| /// Skips malformed rows so one bad record cannot blank the catalogue. | ||
| static List<PartialEarthquakeReport> parseReportList(List<dynamic> raw) { | ||
| return [ | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| /// Full earthquake report — `GET /api/v2/eq/report/{id}`, the per-area/town | ||
| /// intensity breakdown behind a catalogue row ([PartialEarthquakeReport]). | ||
| library; | ||
|
|
||
| import 'package:freezed_annotation/freezed_annotation.dart'; | ||
|
|
||
| part 'earthquake_report.freezed.dart'; | ||
| part 'earthquake_report.g.dart'; | ||
|
|
||
| /// The full earthquake report — epicentre, magnitude, and the per-area/town | ||
| /// felt-intensity breakdown. Fetched by id from [ReportRepository.get] when a | ||
| /// catalogue row is opened. | ||
| @freezed | ||
| abstract class EarthquakeReport with _$EarthquakeReport { | ||
| const EarthquakeReport._(); | ||
|
|
||
| const factory EarthquakeReport({ | ||
| required String id, | ||
| @JsonKey(name: 'lon') required double longitude, | ||
| @JsonKey(name: 'lat') required double latitude, | ||
| @JsonKey(name: 'loc') required String location, | ||
| required double depth, | ||
| @JsonKey(name: 'mag') required double magnitude, | ||
| required Map<String, AreaIntensity> list, | ||
|
|
||
| /// Origin time as Unix **milliseconds**. | ||
| required int time, | ||
| required int trem, | ||
| }) = _EarthquakeReport; | ||
|
|
||
| factory EarthquakeReport.fromJson(Map<String, dynamic> json) => | ||
| _$EarthquakeReportFromJson(json); | ||
|
|
||
| /// Leading CWA serial segment (e.g. `115032` or `115000`). | ||
| String get serial => id.split('-').first; | ||
|
|
||
| /// `…000` serials are 小區域有感 — no numbered CWA report. | ||
| bool get isLocalFelt => serial.endsWith('000'); | ||
|
|
||
| /// Numbered CWA report id, or null when [isLocalFelt]. | ||
| String? get number => isLocalFelt ? null : serial; | ||
|
|
||
| bool get hasNumber => number != null; | ||
|
|
||
| /// Origin time in UTC. | ||
| DateTime get originTimeUtc => | ||
| DateTime.fromMillisecondsSinceEpoch(time, isUtc: true); | ||
|
|
||
| /// Short place string — prefer the parenthetical CWA locality when present. | ||
| String get shortLocation { | ||
| final open = location.indexOf('('); | ||
| final close = location.indexOf(')'); | ||
| if (open >= 0 && close > open) { | ||
| var inner = location.substring(open + 1, close); | ||
| if (inner.startsWith('位於')) inner = inner.substring(2); | ||
| return inner.trim(); | ||
| } | ||
| final fang = location.indexOf('方'); | ||
| if (fang >= 0) return location.substring(0, fang + 1).trim(); | ||
| return location.trim(); | ||
| } | ||
|
|
||
| /// Highest observed intensity across every area/town in [list]. | ||
| int get maxIntensity { | ||
| var max = 0; | ||
| for (final area in list.values) { | ||
| for (final town in area.town.values) { | ||
| if (town.intensity > max) max = town.intensity; | ||
| } | ||
| } | ||
| return max; | ||
| } | ||
|
|
||
| /// The official CWA report page for this event. | ||
| Uri get reportUrl { | ||
| final segments = id.split('-')..removeAt(0); | ||
| final magCode = (magnitude * 10).floor(); | ||
| final numberSuffix = hasNumber ? number!.substring(3) : ''; | ||
| return Uri.parse( | ||
| 'https://scweb.cwa.gov.tw/zh-tw/earthquake/details/' | ||
| '${segments.join()}$magCode$numberSuffix', | ||
| ); | ||
| } | ||
|
|
||
| /// CWA's rendered report image (地震報告圖). The filename is derived from the | ||
| /// Taipei-local origin time, magnitude, and (when numbered) the report's | ||
| /// serial suffix — CWA doesn't expose this as a field, only as a static path. | ||
| Uri get reportImageUrl { | ||
| final t = originTimeUtc.add(const Duration(hours: 8)); // Asia/Taipei | ||
| final y = t.year.toString(); | ||
| final mo = t.month.toString().padLeft(2, '0'); | ||
| final d = t.day.toString().padLeft(2, '0'); | ||
| final h = t.hour.toString().padLeft(2, '0'); | ||
| final mi = t.minute.toString().padLeft(2, '0'); | ||
| final s = t.second.toString().padLeft(2, '0'); | ||
| final magCode = (magnitude * 10).floor(); | ||
| final numberSuffix = hasNumber ? number!.substring(3) : ''; | ||
| final name = '$y$mo$d$h$mi$s$magCode${numberSuffix}_H.png'; | ||
| final yearMonth = name.substring(0, 6); | ||
| return Uri.parse('https://scweb.cwa.gov.tw/webdata/OLDEQ/$yearMonth/$name'); | ||
| } | ||
| } | ||
|
|
||
| /// One area's (縣市) maximum observed intensity and its station/town breakdown. | ||
| @freezed | ||
| abstract class AreaIntensity with _$AreaIntensity { | ||
| const factory AreaIntensity({ | ||
| @JsonKey(name: 'int') required int intensity, | ||
| required Map<String, StationIntensity> town, | ||
| }) = _AreaIntensity; | ||
|
|
||
| factory AreaIntensity.fromJson(Map<String, dynamic> json) => | ||
| _$AreaIntensityFromJson(json); | ||
| } | ||
|
|
||
| /// One station/town's observed intensity and coordinates. | ||
| @freezed | ||
| abstract class StationIntensity with _$StationIntensity { | ||
| const factory StationIntensity({ | ||
| @JsonKey(name: 'lon') required double longitude, | ||
| @JsonKey(name: 'lat') required double latitude, | ||
| @JsonKey(name: 'int') required int intensity, | ||
| }) = _StationIntensity; | ||
|
|
||
| factory StationIntensity.fromJson(Map<String, dynamic> json) => | ||
| _$StationIntensityFromJson(json); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[maintainability · low]
在使用
state.pathParameters['id']!時,使用了強制解包(bang operator!)。雖然在路由配置中AppRoutes.earthquakeReportPath定義為:id,理論上該參數應該存在,但直接使用!可能在參數缺失或路由解析異常時導致運行時錯誤(Runtime Error)。建議考慮更穩健的處理方式,例如提供預設值或進行檢查。Suggestion: