Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
048acc2
chore: Update Flutter Template
michalurbanek Sep 23, 2025
4b307e2
fix: Launch file, gradle build warnings
michalurbanek Oct 2, 2025
fc47601
chore: Upgrade to stable version of flutter
michalurbanek Oct 2, 2025
15b2bea
chore: Upgrade dependencies
michalurbanek Oct 2, 2025
8268040
fix: Rename generated providers after Riverpod update
michalurbanek Oct 2, 2025
7472cfc
fix: Event notifier due to Riverpod upgrade
michalurbanek Oct 2, 2025
e762fa3
fix: Use FutureProvider for future use cases
michalurbanek Oct 2, 2025
8bd54a8
fix: State Handler - notifier changes
michalurbanek Oct 2, 2025
e0b6fff
fix: Freezed and Flogger updates
michalurbanek Oct 2, 2025
48bf7ea
fix: Use ref.mounted for async gaps
michalurbanek Oct 2, 2025
862f2a4
fix: ProviderObserver after upgrade
michalurbanek Oct 2, 2025
77c426e
fix: Use autodispose for sign in future providers
michalurbanek Oct 3, 2025
369783f
fix: TODO style
michalurbanek Oct 3, 2025
ddab3a0
fix: Remove unused import
michalurbanek Oct 3, 2025
bf4e558
fix: Replace deprecated color
michalurbanek Oct 3, 2025
7bebd68
fix: Use radio group for radio buttons
michalurbanek Oct 3, 2025
3e9b5d5
chore: Use profile app suffix id for profile
michalurbanek Oct 3, 2025
07d4e48
fix: Remove applicationIdSuffix from Profile build type
michalurbanek Oct 3, 2025
9aaba8a
chore: Upgrade Flutter to 3.35.5
michalurbanek Oct 3, 2025
31c3a68
chore: Upgrade podfile with latest versions
michalurbanek Oct 3, 2025
82138d1
fix: Revert autodispose due to accessing ref in async
michalurbanek Oct 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .fvmrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"flutter": "3.27.1",
"flutter": "3.35.5",
"flavors": {}
}
9 changes: 3 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/

# IntelliJ related
Expand Down Expand Up @@ -40,16 +42,11 @@ app.*.symbols
app.*.map.json

# Android Studio will place build artifacts here
/android/app/.cxx/
/android/app/debug
/android/app/profile
/android/app/release

# App Icons Gen
extras/app_icon_generator/generated

# iOS related stuff
Podfile.lock

# Firebase
.crashlytics
.firebase/
Expand Down
137 changes: 137 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Develop - Debug",
"request": "launch",
"type": "dart",
"program": "lib/main_develop.dart",
"args": [
"--web-browser-flag",
"--user-data-dir=./.chrome_data_dir",
"--web-port",
"5000",
"--flavor",
"develop"
]
},
{
"name": "Develop - Profile",
"request": "launch",
"type": "dart",
"program": "lib/main_develop.dart",
"flutterMode": "profile",
"args": [
"--web-browser-flag",
"--user-data-dir=./.chrome_data_dir",
"--web-port",
"5000",
"--flavor",
"develop"
]
},
{
"name": "Develop - Release",
"request": "launch",
"type": "dart",
"program": "lib/main_develop.dart",
"flutterMode": "release",
"args": [
"--web-browser-flag",
"--user-data-dir=./.chrome_data_dir",
"--web-port",
"5000",
"--flavor",
"develop"
]
},
{
"name": "Staging - Debug",
"request": "launch",
"type": "dart",
"program": "lib/main_staging.dart",
"args": [
"--web-browser-flag",
"--user-data-dir=./.chrome_data_dir",
"--web-port",
"5000",
"--flavor",
"staging"
]
},
{
"name": "Staging - Profile",
"request": "launch",
"type": "dart",
"program": "lib/main_staging.dart",
"flutterMode": "profile",
"args": [
"--web-browser-flag",
"--user-data-dir=./.chrome_data_dir",
"--web-port",
"5000",
"--flavor",
"staging"
]
},
{
"name": "Staging - Release",
"request": "launch",
"type": "dart",
"program": "lib/main_staging.dart",
"flutterMode": "release",
"args": [
"--web-browser-flag",
"--user-data-dir=./.chrome_data_dir",
"--web-port",
"5000",
"--flavor",
"staging"
]
},
{
"name": "Production - Debug",
"request": "launch",
"type": "dart",
"program": "lib/main_production.dart",
"args": [
"--web-browser-flag",
"--user-data-dir=./.chrome_data_dir",
"--web-port",
"5000",
"--flavor",
"production"
]
},
{
"name": "Production - Profile",
"request": "launch",
"type": "dart",
"program": "lib/main_production.dart",
"flutterMode": "profile",
"args": [
"--web-browser-flag",
"--user-data-dir=./.chrome_data_dir",
"--web-port",
"5000",
"--flavor",
"production"
]
},
{
"name": "Production - Release",
"request": "launch",
"type": "dart",
"program": "lib/main_production.dart",
"flutterMode": "release",
"args": [
"--web-browser-flag",
"--user-data-dir=./.chrome_data_dir",
"--web-port",
"5000",
"--flavor",
"production"
]
}
]
}
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"dart.flutterSdkPath": ".fvm/versions/3.27.1"
"dart.flutterSdkPath": ".fvm/versions/3.35.5"
}
36 changes: 21 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,15 @@

- [Authors](#authors)


<!-- ################################################## -->
<!-- ####### Project Notes ####### -->
<!-- ################################################## -->
# Project notes

- Notes that could be benefitial to know during the development.
- Notes that could be beneficial to know during the development.
- For example list of test accounts, required credentials, steps required to get testing account, etc.
<!-- ################################################## -->


<!-- ################################################## -->
Expand All @@ -74,6 +76,7 @@ These are our four core values:
- **Innovation** - We encourage creativity and innovation within the Flutter team. Support an environment where team members feel comfortable suggesting new ideas, experimenting with different approaches, and finding new solutions to problems.
<!-- ################################################## -->


<!-- ################################################## -->
<!-- ######## First steps ######## -->
<!-- ################################################## -->
Expand All @@ -96,6 +99,7 @@ These are our four core values:
9. - [ ] Go through all the ToDo's inside the project, and react to them.
<!-- ################################################## -->


<!-- ################################################## -->
<!-- ########## Project ########## -->
<!-- ################################################## -->
Expand All @@ -119,7 +123,7 @@ These are our four core values:
‣ dbo -> Classes to transfer data over to the database
‣ dto -> Classes to transfer data over the network
‣ enum -> Enum classes used across the App
model -> Model classes used across the App
entity -> Entity classes used across the App
‣ extensions -> Extension classes/methods over existing data types
‣ provider -> Global Services and manager providers, like Notification Service
‣ usecase -> Methods used to get/post data. Usually from/to network or local database
Expand Down Expand Up @@ -154,7 +158,7 @@ flutter pub run build_runner watch --delete-conflicting-outputs

as an alternative you can just use:
```
make build_runner
make watch
```

### Linux
Expand All @@ -175,12 +179,13 @@ You can read about flavors setup in the following tutorials:
- 🖥️ [Linux](https://docs.flutter.dev/deployment/linux) - Flavors are not supported yet.

In case of using firebase with multiple flavors, you have to:
- for iOS add custom build run script phase and copy appropriate `GoogleService-Info.plist` file. It's already prepared, you just need to uncomment it and add appropriate plists to destinations according to the script.
- For iOS, add the custom Build Run Script phase and copy the appropriate `GoogleService-Info.plist` file. The script is already prepared; simply uncomment it and add the necessary `plist` files to their destinations.

For Google sign in:
- for iOS, you have to copy value from `REVERSED_CLIENT_ID` from `GoogleService-Info.plist` into `GOOGLE_REVERSED_CLIENT_ID` in build settings.
<!-- ################################################## -->


<!-- ################################################## -->
<!-- ########## Build and Distribution ########## -->
<!-- ################################################## -->
Expand All @@ -189,7 +194,7 @@ For Google sign in:
- As we are using flavors, we have to specify which flavor to build using `--flavor` argument, and also select a correct main file using `-t` argument.
- One of the arguments you should use is `--obfuscate`. This makes reverse engineering harder. This has to be used also with `--split-debug-info` which should make the app smaller, and also specify the directory where the mapping file to read obfuscated stack trace is stored.
- Optional step is to include precompiled Shaders. To do that you have to first [Precompile Shaders](#precompiling-shaders) and add `--bundle-sksl-path` argument.
- In case we would like to build a Debugable version of the app, we have to add `--debug` argument.
- To build a debug version of the app, include the `--debug` flag.

Here is an example of assembling an Android app bundle using all the commands:
```
Expand Down Expand Up @@ -292,7 +297,7 @@ We covered the UI part, now we need to focus more on the app state and business
The second class is `StateNotifier` class, annotated with `@riverpod` annotation. Rather than splitting the logic completely into small chunks, we believe that it is a good practice to usually have just one `StateNotifier`, providing the `State` for the feature. Naming should follow the same rules as the State class. For example: `UserDetailStateNotifier`. This class must override the `build` method. The State is built inside this method. This is a good place to for example call any necessary API calls, to get data, make some init logic for the feature, etc.. This class can also contain additional methods, to manipulate the State. For example method `updateUser` will update the state with `isUpdatingUser` to `true`, then update the user on the BE side and update the state again with progress set to `false``, and providing new user data.
Even through we have just a single huge StateHandler, it is possible to observe just specific fields that are needed for building the UI. This way we can optimize the redrawing of the app when the state changes.

The last part is the solution, on how to communicate one-time events from `StateNotifier` back to the UI. For this, we are using a custom implementation of `EventNotifier` which extends `StateNotifier`. This part is implemented inside `*_event.dart` file. For example: `user_detail_event.dart`. Inside we can find the `Freezed` class defining the events (for example `error` event, `userUpdated` event). There is also a definition of an autodispose StateNotifierProvider, named by the feature. For example: `userDetailEventNotifierProvider`. We should then listen to all these defined events using `ref.listen()` inside our `*_page_content.dart` widget build method.
The last part is the solution, on how to communicate one-time events from `StateNotifier` back to the UI. For this, we are using a custom implementation of `EventNotifier` which extends `StateNotifier`. This part is implemented inside `*_event.dart` file. For example: `user_detail_event.dart`. Inside we can find the `Freezed` class defining the events (for example `error` event, `userUpdated` event). There is also a definition of an autodispose StateNotifierProvider, named by the feature. For example: `userDetailEventNotifierProvider`. We should then listen to all these defined events using `ref.listen()` inside our `*_page.dart` widget build method.
<!-- ################################################## -->

## Push Notifications
Expand All @@ -302,7 +307,7 @@ On the iOS side, on the other hand, the notification will be always displayed by

![Push Notifications Payload](docs/push_notifications_payload.jpg)

As for the handling of notifications of different types, we introduced `NotificationPayloadModel`, and `NotificationType`. These both define all the notifications types expected from BE, which the app will be able to handle. All the rest of the logic is handled inside `FirebaseMessagingService` and `NotificationsService` files.
As for the handling of notifications of different types, we introduced `NotificationPayloadEntity`, and `NotificationType`. These both define all the notifications types expected from BE, which the app will be able to handle. All the rest of the logic is handled inside `FirebaseMessagingService` and `NotificationsService` files.

![Displaying Push Notifications](docs/displaying_push_notifications.jpg)

Expand Down Expand Up @@ -339,7 +344,7 @@ This way we are ensuring that at least the Android version is buildable. We are
## Theming
Theming is done inside `lib/core/themes/app_theme.dart`. Currently, we suggest using Material 3. The main setup is done in file `app_theme.dart`.

The main idea right now is to overwrite the whole `colorScheme` with an "undefined" pinkish color and to not use the default theme colorScheme anywhere in the app. Every widget like AppBar, EleveatedButton, TextField, etc. should have a custom implementation starting with the word `Custom` so it is easily recognizable. This Widget then should wrap the appropriate widget, and should utilize colors from `context.colorScheme`, which has an extension method, as is returning our own implementation of `CustomColorScheme`. All colors should be declared there.
The current approach is to completely override the default `colorScheme` with a custom "undefined" pinkish palette and avoid using the default theme anywhere in the app. Every widget—such as AppBar, ElevatedButton, and TextField—should have a custom implementation prefixed with `Custom` for easy identification. Each `Custom` widget should wrap the corresponding standard widget and use colors from `context.colorScheme` and text styles from `context.textTheme`. These context extensions return our custom implementations: `CustomColorScheme` and `CustomTextTheme`, where all colors and text styles are defined.

The most tricky part of theming is to make sure that the app supports Edge-to-Edge, and that it has correct navigation and StatusBar colors set. To make this possible, we had to implement our own `CustomSystemBarsTheme` class. To use it properly, make sure you are calling `setupSystemBarsTheme` during the App startup. In case of the need of overriding the Brightness for a specific screen, there are two approaches. First, the simple one is to just use `CustomAppBar`, and set brightness to it. Second, wrap the whole Scaffold inside `CustomSystemBarsThemeWidget` and set Brightness to it.
<!-- ################################################## -->
Expand All @@ -356,10 +361,10 @@ To be able to use the firebase provider for Apple login, we need to do some conf

- Create a Service ID - this is the service that would provide sign in with apple. `Developer -> Certificates, Identifiers & Profiles -> Identifiers -> Create new -> Services IDs`
(note: to get into services there is a filter on Identifiers screen on right top where you can switch from identifiers to services.)
- Description will be visible to our users - e.g. WearTechClub
- Identifier - can be app/bundle ID `com.wearthech.club.develop` or simply `weartechclub-develop`
- Description will be visible to our users - e.g. Template
- Identifier - can be app/bundle ID `com.strv.flutter.template.develop` or simply `flutter-template-develop`
- Enable Sign in with Apple for the service
- Domains is url of your page e.g. `weartechclub.com`
- Domains is url of your page e.g. `template.com`
- Return URL is crucial part - this will be taken from Firebase: Authentication -> Sign-in method -> Apple -> callback URL

- Create a key: `Developer -> Certificates, Identifiers & Profiles -> Keys -> Create new`
Expand All @@ -370,9 +375,9 @@ To be able to use the firebase provider for Apple login, we need to do some conf
- Save -> Continue -> Register -> download the key

- Firebase setup that will be done under `Authentication -> Sign-in method -> Apple`
- Services ID - this is the Identifier of a Service ID created in Apple Developer - `weartechclub-develop`
- Apple team Id from Developer (e.g. `965Y62DKGTU`)
- Key Id - generated when the key was created in previous step (e.g. `798BRVKFKO`)
- Services ID - this is the Identifier of a Service ID created in Apple Developer - `flutter-template-develop`
- Apple team Id from Developer (e.g. `965Y6XXXXXX`)
- Key Id - generated when the key was created in previous step (e.g. `798BXXXXXX`)
- Private key - when you created the key you downloaded the Private key as .p8 file
- Save it and check the `callback URL` - if it changed from what you have in your `Service ID` as `Return URL`, update it in Apple Developer
<!-- ################################################## -->
Expand All @@ -389,6 +394,7 @@ To be able to use the firebase provider for Apple login, we need to do some conf
- The app will crash, and you will see the error message `[CustomException] Received error PlatformException(google_sign_in, Your app is missing support for the following URL schemes: com.googleusercontent.apps......` in the debug console if the custom URL schemes setup is incorrect after tapping the Google Auth button.
<!-- ################################################## -->


<!-- ################################################## -->
<!-- ########## Testing ########## -->
<!-- ################################################## -->
Expand Down Expand Up @@ -524,7 +530,7 @@ For the purpose of Fraud prevention, user safety, and compliance the dedicated A
<!-- ########## Authors ########## -->
<!-- ################################################## -->
# Authors
- [Lukáš Hermann](mailto:lukas.hermann@strv.com)
- [Lukáš Hermann](mailto:hermann@helu.cz)
- [Robert Oravec](mailto:robert.oravec@strv.com)
- [Michal Urbánek](mailto:michal.urbanek@strv.com)
<!-- ################################################## -->
46 changes: 14 additions & 32 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,21 @@

# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
include: package:netglade_analysis/lints.yaml

analyzer:
exclude:
exclude:
- 'project_setup/**'
- '**.g.dart'
- '**.gen.dart'
- '**.config.dart'
- '**.graphql.dart'
errors:
todo: info

formatter:
page_width: 140
trailing_commas: preserve

linter:
# The lint rules applied to this project can be customized in the
Expand All @@ -28,36 +36,10 @@ linter:
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_redundant_argument_values: true
always_declare_return_types: true
always_use_package_imports: true
avoid_catches_without_on_clauses: true
avoid_catching_errors: true
avoid_empty_else: true
avoid_field_initializers_in_const_classes: true
avoid_final_parameters: true
avoid_multiple_declarations_per_line: true
avoid_types_as_parameter_names: true
avoid_types_on_closure_parameters: true
avoid_unnecessary_containers: true
avoid_void_async: true
await_only_futures: true
camel_case_extensions: true
camel_case_types: true
curly_braces_in_flow_control_structures: true
empty_statements: true
eol_at_end_of_file: true
file_names: true
leading_newlines_in_multiline_strings: true
library_names: true
no_duplicate_case_values: true
no_logic_in_create_state: true
no_self_assignments: true
no_wildcard_variable_uses: true
prefer_single_quotes: true
prefer_void_to_null: true
slash_for_doc_comments: true
unnecessary_brace_in_string_interps: true
sort_pub_dependencies: false
require_trailing_commas: false
avoid_positional_boolean_parameters: false
no_default_cases: false

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
Loading