This PR introduces the Activities screen, handling of errors in view
models and commands, and logs using the dart `logging` package.
**Activities**
- The screen loads a list of activities, split in daytime and evening
activities, and the user can select them.
- Server adds the endpoint `/destination/<id>/activitity` which was
missing before.
Screencast provided:
[Screencast from 2024-07-29
16-29-02.webm](https://github.com/user-attachments/assets/a56024d8-0a9c-49e7-8fd0-c895da15badc)
**Error handling**
_UI Error handling:_
In the screencast you can see a `SnackBar` appearing, since the
"Confirm" button is not yet implemented.
The `saveActivities` Command returns an error `Result.error()`, then the
error state is exposed by the Command and consumed by the listener in
the `ActivityScreen`, which displays a `SnackBar` and consumes the
state.
Functionality is similar to the one found in [UI events - Consuming
events can trigger state
updates](https://developer.android.com/topic/architecture/ui-layer/events#consuming-trigger-updates)
from the Android architecture guide, as the command state is "consumed"
and cleared.
The Snackbar also includes an action to "try again". Tapping on it calls
to the failed Command `execute()` so users can run the action again.
For example, here the `saveActivities` command failed, so `error` is
`true`. Then we call to `clearResult()` to remove the failed status, and
show a `SnackBar`, with the `SnackBarAction` that runs `saveActivities`
again when tapped.
```dart
if (widget.viewModel.saveActivities.error) {
widget.viewModel.saveActivities.clearResult();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Error while saving activities'),
action: SnackBarAction(
label: "Try again",
onPressed: widget.viewModel.saveActivities.execute,
),
),
);
}
```
Since commands expose `running`, `error` and `completed`, it is easy to
implement loading and error indicator widgets:
[Screencast from 2024-07-29
16-55-42.webm](https://github.com/user-attachments/assets/fb5772d0-7b9d-4ded-8fa2-9ce347f4d555)
As side node, we can easily simulate that state by adding these lines in
any of the repository implementations:
```dart
await Future.delayed(Durations.extralong1);
return Result.error(Exception('ERROR!'));
```
_In-code error handling:_
The project introduces the `logging` package.
In the entry point `main_development.dart` the log level is configured.
Then in code, a `Logger` is creaded in each View Model with the name of
the class. Then the log calls are used depending on the `Result`
response, some finer traces are also added.
By default, they are printed to the IDE debug console, for example:
```
[SearchFormViewModel] Continents (7) loaded
[SearchFormViewModel] ItineraryConfig loaded
[SearchFormViewModel] Selected continent: Asia
[SearchFormViewModel] Selected date range: 2024-07-30 00:00:00.000 - 2024-08-08 00:00:00.000
[SearchFormViewModel] Set guests number: 1
[SearchFormViewModel] ItineraryConfig saved
```
**Other changes**
- The json files containing destinations and activities are moved into
the `app/assets/` folders, and the server is querying those files
instead of their own copy. This is done to avoid file duplication but we
can make a copy of those assets files for the server if we decide to.
**TODO Next**
- I will implement the "book a trip" screen which would complete the
main application flow, which should introduce a more complex
"component/use case" outside a view model.
## Pre-launch Checklist
- [x] I read the [Flutter Style Guide] _recently_, and have followed its
advice.
- [x] I signed the [CLA].
- [x] I read the [Contributors Guide].
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] All existing and new tests are passing.
If you need help, consider asking for advice on the #hackers-devrel
channel on [Discord].
<!-- Links -->
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md
[CLA]: https://cla.developers.google.com/
[Discord]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Chat.md
[Contributors Guide]:
https://github.com/flutter/samples/blob/main/CONTRIBUTING.md