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
6 changes: 6 additions & 0 deletions .templates/newDTO/___dto_name____dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@ abstract class ___DtoName___DTO with _$___DtoName___DTO {

factory ___DtoName___DTO.fromJson(Map<String, dynamic> json) => _$___DtoName___DTOFromJson(json);
}

extension ___DtoName___DTOExtension on ___DtoName___DTO {
___DtoName___Entity toEntity() => ___DtoName___Entity(
sampleField: sampleField,
);
}
10 changes: 10 additions & 0 deletions .templates/newEntity/___entity_name____entity.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:freezed_annotation/freezed_annotation.dart';

part '___entity_name____entity.freezed.dart';

@freezed
abstract class ___EntityName___Entity with _$___EntityName___Entity {
const factory ___EntityName___Entity({
required String? sampleField,
}) = ____EntityName___Entity;
}
6 changes: 6 additions & 0 deletions .templates/newEntity/template.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "New Data Entity",
"variables": [
"entityName"
]
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:flutter_app/common/data/model/exception/custom_exception.dart';
import 'package:flutter_app/common/data/entity/exception/custom_exception.dart';
import 'package:flutter_app/core/riverpod/event_notifier.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
Expand Down
30 changes: 0 additions & 30 deletions .templates/newModel/___model_name____model.dart

This file was deleted.

6 changes: 0 additions & 6 deletions .templates/newModel/template.config.json

This file was deleted.

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,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 @@ -324,7 +324,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
8 changes: 4 additions & 4 deletions build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ targets:
- lib/common/data/enum/*.dart
- lib/common/data/enum/**/*.dart

- lib/common/data/model/*.dart
- lib/common/data/model/**/*.dart
- lib/common/data/entity/*.dart
- lib/common/data/entity/**/*.dart

- lib/common/validator/*.dart

Expand Down Expand Up @@ -58,8 +58,8 @@ targets:
- lib/common/data/enum/*.dart
- lib/common/data/enum/**/*.dart

- lib/common/data/model/*.dart
- lib/common/data/model/**/*.dart
- lib/common/data/entity/*.dart
- lib/common/data/entity/**/*.dart


# Title: Auto Route
Expand Down
1 change: 1 addition & 0 deletions flutter.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@
"section": "components",
"dbo": "database",
"dto": "api",
"entity": "enum",
"exception": "error",
"analytics": "tasks",
"network": "connection",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:flutter_app/common/component/custom_button/custom_button_primary
import 'package:flutter_app/common/component/custom_text/custom_text.dart';
import 'package:flutter_app/common/composition/expandable_single_child_scroll_view.dart';
import 'package:flutter_app/common/composition/responsive_widget.dart';
import 'package:flutter_app/common/data/model/exception/custom_exception.dart';
import 'package:flutter_app/common/data/entity/exception/custom_exception.dart';
import 'package:flutter_app/common/extension/build_context.dart';

class ErrorPlaceholderWidget extends StatelessWidget {
Expand Down
12 changes: 12 additions & 0 deletions lib/common/data/dto/user_response_dto.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:flutter_app/common/data/entity/user_entity.dart';
import 'package:flutter_app/common/data/enum/user_role.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

Expand All @@ -16,3 +17,14 @@ abstract class UserResponseDTO with _$UserResponseDTO {

factory UserResponseDTO.fromJson(Map<String, dynamic> json) => _$UserResponseDTOFromJson(json);
}

extension UserResponseDTOExtension on UserResponseDTO {
UserEntity toEntity() => UserEntity(
id: id,
role: role,
email: email,
displayName: displayName,
imageUrl: null,
referredId: referredId,
);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:collection/collection.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'notification_payload_model.freezed.dart';
part 'notification_payload_model.g.dart';
part 'notification_payload_entity.freezed.dart';
part 'notification_payload_entity.g.dart';

@JsonEnum(valueField: 'value', alwaysCreate: true)
enum NotificationType {
Expand All @@ -17,32 +17,32 @@ enum NotificationType {
}

@Freezed(fromJson: true, toJson: true)
sealed class NotificationPayloadModel with _$NotificationPayloadModel {
const NotificationPayloadModel._();
sealed class NotificationPayloadEntity with _$NotificationPayloadEntity {
const NotificationPayloadEntity._();

// Title: Sample
const factory NotificationPayloadModel.sample({
const factory NotificationPayloadEntity.sample({
required int id,
required String title,
required String body,
@Default(NotificationType.sample) NotificationType type,
}) = NotificationPayloadModelSample;
}) = NotificationPayloadEntitySample;

// Subtitle: unknown
const factory NotificationPayloadModel.unknown({
const factory NotificationPayloadEntity.unknown({
@Default(-1) int id,
@Default('') String title,
@Default('') String body,
@Default(NotificationType.unknown) NotificationType type,
}) = NotificationPayloadModelUnknown;
}) = NotificationPayloadEntityUnknown;

factory NotificationPayloadModel.fromJson(Map<String, dynamic> json) {
factory NotificationPayloadEntity.fromJson(Map<String, dynamic> json) {
switch (NotificationType.fromString(json['type'] as String?)) {
case NotificationType.sample:
return NotificationPayloadModelSample.fromJson(json);
return NotificationPayloadEntitySample.fromJson(json);

case NotificationType.unknown:
return const NotificationPayloadModelUnknown();
return const NotificationPayloadEntityUnknown();
}
}
}
19 changes: 19 additions & 0 deletions lib/common/data/entity/user_entity.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:flutter_app/common/data/enum/user_role.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'user_entity.freezed.dart';
part 'user_entity.g.dart';

@freezed
abstract class UserEntity with _$UserEntity {
const factory UserEntity({
required String id,
required UserRole role,
required String? email,
required String? displayName,
required String? imageUrl,
required String? referredId,
}) = _UserEntity;

factory UserEntity.fromJson(Map<String, dynamic> json) => _$UserEntityFromJson(json);
}
32 changes: 0 additions & 32 deletions lib/common/data/model/user_model.dart

This file was deleted.

2 changes: 1 addition & 1 deletion lib/common/extension/async_value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:flutter_app/common/component/custom_app_bar.dart';
import 'package:flutter_app/common/component/custom_progress_indicator.dart';
import 'package:flutter_app/common/composition/placeholder/empty_placeholder_widget.dart';
import 'package:flutter_app/common/composition/placeholder/error_placeholder_widget.dart';
import 'package:flutter_app/common/data/model/exception/custom_exception.dart';
import 'package:flutter_app/common/data/entity/exception/custom_exception.dart';
import 'package:flutter_app/common/extension/dynamic.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

Expand Down
2 changes: 1 addition & 1 deletion lib/common/extension/response.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:dio/dio.dart';
import 'package:flutter_app/common/data/model/exception/custom_exception.dart';
import 'package:flutter_app/common/data/entity/exception/custom_exception.dart';

extension ResponseExtension on Response<Map<String, dynamic>> {
/// Tries to downcast `data` as `List<dynamic>`. If decoding fails,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import 'package:flutter_app/common/data/model/user_model.dart';
import 'package:flutter_app/common/data/entity/user_entity.dart';
import 'package:flutter_app/common/usecase/user/get_database_user_use_case.dart';
import 'package:flutter_app/common/usecase/user/set_database_user_use_case.dart';
import 'package:flutter_app/core/flogger.dart';
import 'package:flutter_app/core/riverpod/state_handler.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'current_user_model_state.g.dart';
part 'current_user_state.g.dart';

@Riverpod(keepAlive: true)
class CurrentUserModelState extends _$CurrentUserModelState with NullableStateHandler {
class CurrentUserState extends _$CurrentUserState with NullableStateHandler {
@override
FutureOr<UserModel?> build() async {
FutureOr<UserEntity?> build() async {
return await _getUserFromDatabase();
}

Future<void> updateCurrentUser(UserModel? user) async {
Flogger.d('[CurrentUserModelState] Going to set user $user');
Future<void> updateCurrentUser(UserEntity? user) async {
Flogger.d('[CurrentUserEntityState] Going to set user $user');

await ref.read(setDatabaseUserUseCaseProvider(user: user).future);

setStateData(user);
}

Future<UserModel?> _getUserFromDatabase() async {
Future<UserEntity?> _getUserFromDatabase() async {
return await ref.read(getDatabaseUserUseCaseProvider.future);
}
}
8 changes: 4 additions & 4 deletions lib/common/provider/firebase_messaging_service.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_app/app/configuration/configuration.dart';
import 'package:flutter_app/app/setup/app_platform.dart';
import 'package:flutter_app/common/data/model/notification_payload_model.dart';
import 'package:flutter_app/common/provider/current_user_model_state.dart';
import 'package:flutter_app/common/data/entity/notification_payload_entity.dart';
import 'package:flutter_app/common/provider/current_user_state.dart';
import 'package:flutter_app/common/provider/notifications_service.dart';
import 'package:flutter_app/common/usecase/create_device_token_use_case.dart';
import 'package:flutter_app/core/analytics/crashlytics_manager.dart';
Expand All @@ -16,7 +16,7 @@ class FirebaseMessagingService extends _$FirebaseMessagingService {
@pragma('vm:entry-point')
static Future<void> firebaseNotificationDisplayBgHandler(RemoteMessage message) async {
Flogger.d('[Firebase Messaging] Display notification with payload: ${message.data}');
await NotificationsService.showNotification(NotificationPayloadModel.fromJson(message.data));
await NotificationsService.showNotification(NotificationPayloadEntity.fromJson(message.data));
}

@pragma('vm:entry-point')
Expand Down Expand Up @@ -45,7 +45,7 @@ class FirebaseMessagingService extends _$FirebaseMessagingService {
}

try {
if (await ref.read(currentUserModelStateProvider.future) != null) {
if (await ref.read(currentUserStateProvider.future) != null) {
await ref.read(createDeviceTokenUseCaseProvider(deviceToken: fcmToken.toString()).future);
}
} on Exception catch (e, st) {
Expand Down
18 changes: 9 additions & 9 deletions lib/common/provider/notifications_service.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dart:convert';

import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_app/common/data/model/notification_payload_model.dart';
import 'package:flutter_app/common/data/entity/notification_payload_entity.dart';
import 'package:flutter_app/core/flogger.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:permission_handler/permission_handler.dart';
Expand Down Expand Up @@ -52,13 +52,13 @@ class NotificationsService extends _$NotificationsService {
_tryOpeningNotificationFromPayload(notificationResponse.payload);
}

static void handleNotificationOpen(NotificationPayloadModel notificationModel) {
switch (notificationModel) {
case NotificationPayloadModelSample():
static void handleNotificationOpen(NotificationPayloadEntity notification) {
switch (notification) {
case NotificationPayloadEntitySample():
Flogger.d('[Notifications] Handle open of Sample notification');
// TODO(HELU): [Notifications] Handle Notification open action here

case NotificationPayloadModelUnknown():
case NotificationPayloadEntityUnknown():
// Do nothing
}
}
Expand All @@ -73,8 +73,8 @@ class NotificationsService extends _$NotificationsService {
await _tryOpeningNotificationFromPayload(notificationAppLaunchDetails?.notificationResponse?.payload);
}

static Future<void> showNotification(NotificationPayloadModel notification) async {
if (notification is NotificationPayloadModelUnknown) return;
static Future<void> showNotification(NotificationPayloadEntity notification) async {
if (notification is NotificationPayloadEntityUnknown) return;

Flogger.i('[Notifications] New local notification to display: $notification');
await _flutterLocalNotifications.cancelAll();
Expand All @@ -93,7 +93,7 @@ class NotificationsService extends _$NotificationsService {
}

try {
handleNotificationOpen(NotificationPayloadModel.fromJson(jsonDecode(payload) as Map<String, dynamic>));
handleNotificationOpen(NotificationPayloadEntity.fromJson(jsonDecode(payload) as Map<String, dynamic>));
return Future.value(true);
} on Exception catch (e) {
Flogger.e('[Notifications] Could not parse payload from notification: $payload with error $e');
Expand All @@ -107,7 +107,7 @@ class NotificationsService extends _$NotificationsService {
}

try {
handleNotificationOpen(NotificationPayloadModel.fromJson(message.data));
handleNotificationOpen(NotificationPayloadEntity.fromJson(message.data));
return Future.value(true);
} on Exception catch (e) {
Flogger.e('[Notifications] Could not parse payload from notification: ${message.data} with error $e');
Expand Down
Loading
Loading