City guide app. Development is in progress.
video5287743656415992783.mp4
After cloning don't forget to run flutter pub get
and flutter pub run build_runner build --delete-conflicting-outputs
Also in order to build this app you need to get an api key from Yandex Schedule Api, Yandex Map Api and add additional run arguments:
--dart-define=API_KEY=your_schedule_api_key
--dart-define=MAP_API_KEY=your_map_api_key
flutter_bloc
for state managementbloc_test
for bloc testingbuild_runner
dart code generator used byjson_serializable
,freezed
,auto_route
,flutter_gen
freezed
to reduce boilerplate code in model classesfreezed_annotation
to write annotations used by freezedjson_serializable
to create code for JSON serialization and deserializationjson_annotation
to write annotations used by json_serializableequatable
to create simple comparable classesget_it
service locatorflutter_gen
code generator for assetsdio
for handling network requestshttp_mock_adapter
for dio testingmockito
for testingauto_route
for app navigationauto_route_generator
generator forauto_route
easy_localization
to create localizationsintl
for currency, date, time formattingcached_network_image
for caching imagesshimmer
to add shimmer effect while loading datageolocator
for accessing platform specific location servicesyandex_mapkit
to use Yandex MapKitdartz
to implement Either and handle Errorsflutter_launcher_icons
to create launcher iconsflutter_native_splash
for generating native splash screenlottie
for lottie animation filesgoogle_fonts
for custom free fontsfont_awesome_flutter
for iconsflutter_typeahead
for showing suggestions to users as they typetoggle_switch
simple toggle switch widget
From this source
As in the diagram above, the clean architecture is depicted as a pyramid or a slice of onion when viewed from the top. The clean architecture will divide the Flutter project into 3 main layers, namely:
- Data & Platform layer
The data layer is located at the outermost layer. This layer consists of data source code such as consume Rest API, access to the local database, Firebase, or other sources. Also, on this layer, there is usually the platform code that builds up the UI (widgets). - Presentation Layer
The presentation layer consists of the code to access the data of the app from a repository. Also, there is the code for state management such as providers, BLoC, and so on. - Domain Layer
The domain layer is the deepest in the clean architecture. This layer contains the code for business logic applications such as entities and use cases. Each layer depends on the other layers. The arrows on the diagram show how the layers are related. The outermost layer will depend on the inner layer and so on.
The layer that does not depend on any other layers here is only the domain layer (independent) which is the code for the business logic. That way, the application is more adaptable and dynamic. For example, if we want to change the state management from the provider to BLoC, the migration process will not interfere with the existing business logic.
It is good to know how one can come to your city and leave it. So you need a schedule service.
Project involves Yandex Schedule Api
Documentation can be found here
Currently project uses two API methods:
- get schedule between two stations
- get nearest settlement to current location (geocoder)
In order to simplify entering from and to position for schedule this app uses suggestions API. Settlements name appear as you type letters, suggesting you convenient names. Schedule api also needs to have city codes in request. Suggests api is used for converting human readable city names to codes. This app uses Yandex suggests api
A native splash screen will be shown before flutter app starts.
flutter_native_splash:
color: "#0B85FF"
image: assets/images/bird.png
After adding assets run the following command:
flutter pub run flutter_native_splash:create
As an example of platform channel this app implements opening Yandex Map with a point to
make route to, showing organization card and showing 360 degree panorama.
Documentation to Yandex Map intents is here
To open Android native and iOS native from Android Studio Flutter project go to Tools-Flutter-Open
corresponding variant.
Writing custom platform-specific code
How To Call iOS Native Code [2021] Swift Platform Specific Code
How To Call Android Native Code [2021] 1/2 Java & Kotlin Platform Specific Code
For iOS don't forget to add url schemes in Info.plist file
<key>LSApplicationQueriesSchemes</key>
<array>
<string>yandexmaps</string>
</array>
The project uses Dio as network requests handler. Dio transformer allows changes to the request/response data before it is sent/received to/from the server. Transformer is used to set jsonDecodeCallback to execute a jsonDecode function in a separate isolate.
// Must be top-level function
_parseAndDecode(String response) {
return jsonDecode(response);
}
parseJson(String text) {
return compute(_parseAndDecode, text);
}
void main() {
...
//Custom jsonDecodeCallback
(dio.transformer as DefaultTransformer).jsonDecodeCallback = parseJson;
runApp(MyApp());
}
flutter test --coverage
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html
$default:
builders:
json_serializable:
options:
explicit_to_json: true
field_rename: snake
In Visual Studio Code you can hide dedicated file types in project tree. But sometimes you still need to look inside this files.
In Android Studio in oder to keep folder structure clear you can customize file nesting rules and add *.g.dart
and *.freezed.dart
. Press settings button in the upper right corner of project tree window and select "File Nesting"
DOC
More DOC (slightly different examples(maybe not up to date))
This app uses AutoRoute for navigation.
If you wrap FirstRoute() page content with BlocProvider and use context.router.push(SecondRoute())
for navigating to second page and try to access blocs provided in the first page you will get
an error. The second page doesn't know anything about blocs, provided on the first page.
In order to access the same bloc instance through multiple pages you can either pass it as a parameter orit is necessary to create nesting
routing by creating a wrapper page and implementing BlocProvider in it. So each page on this nested
route will have access to this bloc/blocs.
Milad-Akarie comment
In a nested route there is no back button in the AppBar by default, so you need to add it manually by
providing leading: const AutoLeadingButton()
By returning from a second page with back button press you can wrap the second page with
WillPopScope
and add events to bloc or execute functions of cubit by writing
context.read<MyCubit>().cubitFunction();
or context.read<MyBloc>().dispatch(blocEvent)
;
Felix Angelov comment
Alternative example implementing AutoRouteWapper
In order to show images instantly, without artefacts, you can preload them. Source
Use flutter run --release
Problems with iOS deployment. Fixed with changing target OS version to 12.0 and running this
Also need specify locale YMKMapKit.setLocale("ru_RU")
Use
flutter pub run flutter_launcher_icons:main
From here
Open AndroidManifest.xml (located at android/app/src/main)
Android
<application android:label="App Name" ...> // Your app name here
iOS
Open info.plist (located at ios/Runner)
<key>CFBundleName</key> <string>App Name</string> // Your app name here
Don't forget to run flutter clean
Can use THIS package alternatively.
For localization a package easy_localization is used.
Terminal commands:
- to generate translations:
flutter pub run easy_localization:generate -S "assets/translations" -O "lib/core/l10n"
- to generate keys:
flutter pub run easy_localization:generate -S "assets/translations" -O "lib/core/l10n" -o "locale_keys.dart" -f keys
Code generator for assets allowing to get rid of all String-based APIs. The code is generated with build_runner
. To explicitly specify output directory add this lines to pubspec.yaml
flutter_gen: output: lib/app/assets