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
2 changes: 1 addition & 1 deletion .fvmrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"flutter": "3.29.0",
"flutter": "3.29.3",
"flavors": {}
}
2 changes: 1 addition & 1 deletion .templates/newDTO/___dto_name____dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ part '___dto_name____dto.freezed.dart';
part '___dto_name____dto.g.dart';

@freezed
class ___DtoName___DTO with _$___DtoName___DTO {
abstract class ___DtoName___DTO with _$___DtoName___DTO {
const factory ___DtoName___DTO({
String? sampleField,
}) = ____DtoName___DTO;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part '___feature_name____event.freezed.dart';

@freezed
class ___FeatureName___Event with _$___FeatureName___Event {
sealed class ___FeatureName___Event with _$___FeatureName___Event {
const factory ___FeatureName___Event.error(CustomException error) = _Error;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ part '___feature_name____state.freezed.dart';
part '___feature_name____state.g.dart';

@freezed
class ___FeatureName___State with _$___FeatureName___State {
abstract class ___FeatureName___State with _$___FeatureName___State {
const factory ___FeatureName___State({
required bool sample,
}) = ____FeatureName___State;
Expand Down
2 changes: 1 addition & 1 deletion .templates/newModel/___model_name____model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part '___model_name____model.freezed.dart';

@freezed
class ___ModelName___Model with _$___ModelName___Model {
abstract class ___ModelName___Model with _$___ModelName___Model {
const ___ModelName___Model._();

const factory ___ModelName___Model({
Expand Down
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.29.0"
"dart.flutterSdkPath": ".fvm/versions/3.29.3"
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,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)
<!-- ################################################## -->
14 changes: 6 additions & 8 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,18 @@ releaseKeystoreProperties.load(new FileInputStream(rootProject.file("extras/keys

android {
compileSdkVersion compileAndroidSdkVersion
ndkVersion "27.2.12479018"
ndkVersion flutter.ndkVersion
flavorDimensions "env"
namespace "com.strv.flutter.template"

compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17

coreLibraryDesugaringEnabled true
}

kotlinOptions {
jvmTarget = '17'
jvmTarget = JavaVersion.VERSION_17
}

sourceSets {
Expand Down Expand Up @@ -159,10 +158,9 @@ flutter {
}

dependencies {
implementation 'com.google.android.material:material:1.13.0-alpha05'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0"
androidTestUtil "androidx.test:orchestrator:1.4.2"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
implementation 'com.google.android.material:material:1.13.0-alpha12'
androidTestUtil "androidx.test:orchestrator:1.5.1"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
}

// This section must appear at the bottom of the file
Expand Down
2 changes: 1 addition & 1 deletion android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx2048M
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
android.defaults.buildfeatures.buildconfig=true
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
9 changes: 4 additions & 5 deletions android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ pluginManagement {
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}
settings.ext.flutterSdkPath = flutterSdkPath()
}()

includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")

repositories {
google()
Expand All @@ -19,8 +18,8 @@ pluginManagement {

plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.1.4" apply false
id "org.jetbrains.kotlin.android" version "2.0.0" apply false
id "com.android.application" version "8.6.1" apply false
id "org.jetbrains.kotlin.android" version "2.1.20" apply false

// START: FlutterFire Configuration
id "com.google.gms.google-services" version "4.4.2" apply false
Expand Down
2 changes: 1 addition & 1 deletion lib/app/navigation/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AppRouter extends RootStackRouter {
initial: true,
// We don't really need to animate landing page, because
// it doesn't have UI, it's covered by splash screen.
durationInMilliseconds: 0,
duration: Duration.zero,
),

// Subtitle: Authentication Route
Expand Down
2 changes: 1 addition & 1 deletion lib/app/setup/setup_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Future<void> setupApp({required Flavor flavor}) async {
// Load Theme Mode from DB before starting app
await providerContainer.read(themeModeNotifierProvider.future);

// Setup reactive Edge-to-Edge support accross all platforms
// Setup reactive Edge-to-Edge support across all platforms
await CustomSystemBarsTheme.setupSystemBarsTheme(providerContainer: providerContainer);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/app/theme/custom_system_bars_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
class CustomSystemBarsTheme {
static Future<void> setupSystemBarsTheme({required ProviderContainer providerContainer}) async {
final brightness = providerContainer.read(themeModeNotifierProvider.notifier).brightness;
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
await _setupSystemBarsUpdateCallback(providerContainer: providerContainer);
await setSystemBarsTheme(brightness: brightness);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import 'package:flutter/material.dart';
/// but when child doesn't fit, it will automatically become scrollable widget.
class ExpandableSingleChildScrollView extends StatelessWidget {
const ExpandableSingleChildScrollView({
super.key,
required this.child,
this.padding = EdgeInsets.zero,
this.alwaysScrollablePhysics = false,
super.key,
});

final Widget child;
Expand Down
2 changes: 1 addition & 1 deletion lib/common/data/dto/create_device_token_request_dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ part 'create_device_token_request_dto.freezed.dart';
part 'create_device_token_request_dto.g.dart';

@Freezed(toJson: true)
class CreateDeviceTokenRequestDTO with _$CreateDeviceTokenRequestDTO {
abstract class CreateDeviceTokenRequestDTO with _$CreateDeviceTokenRequestDTO {
const factory CreateDeviceTokenRequestDTO({
required String? token,
}) = _CreateDeviceTokenRequestDTO;
Expand Down
2 changes: 1 addition & 1 deletion lib/common/data/dto/user_response_dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ part 'user_response_dto.freezed.dart';
part 'user_response_dto.g.dart';

@freezed
class UserResponseDTO with _$UserResponseDTO {
abstract class UserResponseDTO with _$UserResponseDTO {
const factory UserResponseDTO({
required String id,
required UserRole role,
Expand Down
40 changes: 20 additions & 20 deletions lib/common/data/model/exception/custom_exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ import 'package:sign_in_with_apple/sign_in_with_apple.dart';
part 'custom_exception.freezed.dart';

@freezed
class CustomException with _$CustomException implements Exception {
sealed class CustomException with _$CustomException implements Exception {
const CustomException._();

const factory CustomException.general() = _General;
const factory CustomException.withMessage({String? message}) = _CustomExceptionWithMessage;
const factory CustomException.unauthenticated() = _Unauthenticated;
const factory CustomException.notConnectedToTheInternet() = _NotConnectedToTheInternet;
const factory CustomException.decodingFailed() = _DecodingFailed;
const factory CustomException.general() = CustomExceptionGeneral;
const factory CustomException.withMessage({String? message}) = CustomExceptionWithMessage;
const factory CustomException.unauthenticated() = CustomExceptionUnauthenticated;
const factory CustomException.notConnectedToTheInternet() = CustomExceptionNotConnectedToTheInternet;
const factory CustomException.decodingFailed() = CustomExceptionDecodingFailed;

// Title: Mapped Firebase exception with error code `credential-already-in-use`.
const factory CustomException.signInCancelled() = _SignInCancelled;
const factory CustomException.credentialAlreadyInUse({required AuthCredential? credential}) = _CredentialAlreadyInUse;
// Note: Mapped Firebase exception with error code `credential-already-in-use`.
const factory CustomException.signInCancelled() = CustomExceptionSignInCancelled;
const factory CustomException.credentialAlreadyInUse({required AuthCredential? credential}) = CustomExceptionCredentialAlreadyInUse;

factory CustomException.fromErrorObject({required Object? error}) {
Flogger.e('[CustomException] Received error $error, ');
Expand All @@ -41,7 +41,7 @@ class CustomException with _$CustomException implements Exception {
Flogger.e("[CustomException] error.response: ${error.response?.data["errorCode"]}");
}

// Title: This is the place to handle your own error codes, response, or states, and map them to you own CustomException.
// Note: This is the place to handle your own error codes, response, or states, and map them to you own CustomException.

if (error.response?.statusCode == 401) {
return const CustomException.unauthenticated();
Expand Down Expand Up @@ -69,19 +69,19 @@ class CustomException with _$CustomException implements Exception {
}

String getMessage({required BuildContext context}) {
return mapOrNull(
withMessage: (exception) => exception.message,
unauthenticated: (_) => context.locale.customExceptionUnauthenticatedMessage,
notConnectedToTheInternet: (_) => context.locale.customExceptionInternetConnectionMessage,
) ??
context.locale.customExceptionGeneralMessage;
return switch (this) {
CustomExceptionWithMessage(message: final message) => message ?? context.locale.customExceptionGeneralMessage,
CustomExceptionUnauthenticated() => context.locale.customExceptionUnauthenticatedMessage,
CustomExceptionNotConnectedToTheInternet() => context.locale.customExceptionInternetConnectionMessage,
_ => context.locale.customExceptionGeneralMessage,
};
}

String getDetails({required BuildContext context}) {
return mapOrNull(
notConnectedToTheInternet: (_) => context.locale.customExceptionInternetConnectionDetails,
) ??
context.locale.customExceptionGeneralDetails;
return switch (this) {
CustomExceptionNotConnectedToTheInternet() => context.locale.customExceptionInternetConnectionDetails,
_ => context.locale.customExceptionGeneralDetails,
};
}

Future<void> showErrorSnackbar({
Expand Down
22 changes: 11 additions & 11 deletions lib/common/data/model/exception/validator_exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'validator_exception.freezed.dart';

@freezed
class ValidatorException with _$ValidatorException implements Exception {
sealed class ValidatorException with _$ValidatorException implements Exception {
const ValidatorException._();

const factory ValidatorException.generalIsEmpty(String Function(BuildContext) getText) = _GeneralIsEmpty;
const factory ValidatorException.generalIsTooShort(String Function(BuildContext) getText) = _GeneralIsTooShort;
const factory ValidatorException.generalIsTooLong(String Function(BuildContext) getText) = _GeneralIsTooLong;
const factory ValidatorException.generalIsInvalid(String Function(BuildContext) getText) = _GeneralIsInvalid;
const factory ValidatorException.generalIsEmpty(String Function(BuildContext) getText) = ValidatorExceptionGeneralIsEmpty;
const factory ValidatorException.generalIsTooShort(String Function(BuildContext) getText) = ValidatorExceptionGeneralIsTooShort;
const factory ValidatorException.generalIsTooLong(String Function(BuildContext) getText) = ValidatorExceptionGeneralIsTooLong;
const factory ValidatorException.generalIsInvalid(String Function(BuildContext) getText) = ValidatorExceptionGeneralIsInvalid;

String getMessage({required BuildContext context}) {
return map(
generalIsEmpty: (value) => value.getText(context),
generalIsTooShort: (value) => value.getText(context),
generalIsTooLong: (value) => value.getText(context),
generalIsInvalid: (value) => value.getText(context),
);
return switch (this) {
ValidatorExceptionGeneralIsEmpty(getText: final getText) => getText(context),
ValidatorExceptionGeneralIsTooShort(getText: final getText) => getText(context),
ValidatorExceptionGeneralIsTooLong(getText: final getText) => getText(context),
ValidatorExceptionGeneralIsInvalid(getText: final getText) => getText(context),
};
}
}
2 changes: 1 addition & 1 deletion lib/common/data/model/user_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ part 'user_model.freezed.dart';
part 'user_model.g.dart';

@freezed
class UserModel with _$UserModel {
abstract class UserModel with _$UserModel {
const UserModel._();

const factory UserModel({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ FutureOr<UserModel> signInWithAuthCredentialUseCase(
Flogger.d('[Authentication] Anonymous user was linked with google credential');
} on Exception catch (error) {
final customException = CustomException.fromErrorObject(error: error);
final credentialIsAlreadyInUse = customException.mapOrNull(credentialAlreadyInUse: (value) => value.credential);
final credentialIsAlreadyInUse = switch (customException) {
CustomExceptionCredentialAlreadyInUse(credential: final credential) => credential,
_ => null,
};

if (credentialIsAlreadyInUse != null) {
await FirebaseAuth.instance.signInWithCredential(credentialIsAlreadyInUse);
Expand Down
23 changes: 16 additions & 7 deletions lib/common/validator/text_field_validator_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,31 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'text_field_validator_state.freezed.dart';

@freezed
class TextFieldValidatorState with _$TextFieldValidatorState {
sealed class TextFieldValidatorState with _$TextFieldValidatorState {
const TextFieldValidatorState._();

const factory TextFieldValidatorState.initial() = _Initial;
const factory TextFieldValidatorState.valid() = _Valid;
const factory TextFieldValidatorState.invalid({required ValidatorException exception}) = _Invalid;
const factory TextFieldValidatorState.initial() = TextFieldValidatorStateInitial;
const factory TextFieldValidatorState.valid() = TextFieldValidatorStateValid;
const factory TextFieldValidatorState.invalid({required ValidatorException exception}) = TextFieldValidatorStateInvalid;

bool get isValid {
return mapOrNull(valid: (_) => true) ?? false;
return switch (this) {
TextFieldValidatorStateValid() => true,
_ => false,
};
}

bool get hasError {
return mapOrNull(invalid: (_) => true) ?? false;
return switch (this) {
TextFieldValidatorStateInvalid() => true,
_ => false,
};
}

String? getErrorMessage(BuildContext context) {
return mapOrNull(invalid: (value) => value.exception.getMessage(context: context));
return switch (this) {
TextFieldValidatorStateInvalid(exception: final exception) => exception.getMessage(context: context),
_ => null,
};
}
}
2 changes: 1 addition & 1 deletion lib/core/analytics/analytics_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'analytics_event.freezed.dart';

@freezed
class AnalyticsEvent with _$AnalyticsEvent {
abstract class AnalyticsEvent with _$AnalyticsEvent {
factory AnalyticsEvent._({
required String firebaseEventId,
Map<String, String>? firebaseEventParams,
Expand Down
2 changes: 1 addition & 1 deletion lib/core/analytics/analytics_screen_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'analytics_screen_view.freezed.dart';

@freezed
class AnalyticsScreenView with _$AnalyticsScreenView {
abstract class AnalyticsScreenView with _$AnalyticsScreenView {
factory AnalyticsScreenView._({
required String firebaseScreenName,
}) = _AnalyticsScreenView;
Expand Down
4 changes: 2 additions & 2 deletions lib/features/authentication/authentication_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'authentication_event.freezed.dart';

@freezed
class AuthenticationEvent with _$AuthenticationEvent {
const factory AuthenticationEvent.signedIn() = _SignedIn;
sealed class AuthenticationEvent with _$AuthenticationEvent {
const factory AuthenticationEvent.signedIn() = AuthenticationEventSignedIn;
}

final authenticationEventNotifierProvider =
Expand Down
7 changes: 3 additions & 4 deletions lib/features/authentication/authentication_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ class AuthenticationPage extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
ref.listen(
authenticationEventNotifierProvider,
(_, next) {
next?.whenOrNull(
signedIn: () => context.router.replaceAll([const LandingRoute()]),
);
(_, next) => switch (next) {
AuthenticationEventSignedIn() => context.router.replaceAll([const LandingRoute()]),
_ => () {},
},
);

Expand Down
Loading
Loading