Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor feature fetch message structure #1528

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
22 changes: 22 additions & 0 deletions lib/core/data/model/query/query_parameter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
abstract class QueryParameter<T> {
final String queryName;
final T queryValue;

QueryParameter(this.queryName, this.queryValue);
}

class BooleanQueryParameter extends QueryParameter<bool> {
BooleanQueryParameter(String queryName, bool queryValue) : super(queryName, queryValue);
}

class StringQueryParameter extends QueryParameter<String> {
StringQueryParameter(String queryName, String queryValue) : super(queryName, queryValue);
}

class IntQueryParameter extends QueryParameter<int> {
IntQueryParameter(String queryName, int queryValue) : super(queryName, queryValue);
}

extension ListQueryParameterExtension on List<QueryParameter?> {
Map<String, dynamic> toMap() => { for (var data in this) if (data != null) data.queryName : data.queryValue };
}
17 changes: 17 additions & 0 deletions lib/core/domain/repository/repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:flutter/material.dart';
import 'package:twake/models/globals/globals.dart';

abstract class RepositoryHelper {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explain your idea?

navigatorDatasource({
VoidCallback? onLocal,
VoidCallback? onRemote,
}) {
if (!Globals.instance.isNetworkConnected) {
onLocal?.call();
return;
}
onRemote?.call();
Comment on lines +9 to +13
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, it is not generic enough. For example: when we need to first: fetch data from local, in parallel, fetch the data with network to update.

}
}

abstract class Repository with RepositoryHelper {}
16 changes: 16 additions & 0 deletions lib/core/domain/state/app_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:dartz/dartz.dart';
import 'package:meta/meta.dart';
import 'package:equatable/equatable.dart';
import 'package:twake/core/domain/state/failure.dart';
import 'package:twake/core/domain/state/success.dart';


@immutable
abstract class AppState with EquatableMixin {
final Either<Failure, Success> viewState;

AppState(this.viewState);

@override
List<Object?> get props => [viewState];
}
16 changes: 16 additions & 0 deletions lib/core/domain/state/failure.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:equatable/equatable.dart';

abstract class Failure extends Equatable {}

abstract class FeatureFailure extends Failure {}

class ExceptionFailure extends Failure {
final dynamic exception;

ExceptionFailure(this.exception);

@override
List<Object?> get props => [
exception,
];
}
48 changes: 48 additions & 0 deletions lib/core/domain/state/success.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'package:equatable/equatable.dart';

abstract class Success with EquatableMixin {}

abstract class ViewState extends Success {}

abstract class ViewEvent extends Success {}

class UIState extends ViewState {
static final idle = UIState();

UIState() : super();

@override
List<Object?> get props => [];
}

class SuccessUIState<T> extends ViewState {
final T result;

SuccessUIState(this.result) : super();

@override
List<Object?> get props => [
result,
];
}

class LoadingState extends UIState {
LoadingState();

@override
List<Object?> get props => [];
}

class LoadingMoreState extends UIState {
LoadingMoreState();

@override
List<Object?> get props => [];
}

class RefreshingState extends UIState {
RefreshingState();

@override
List<Object?> get props => [];
}
12 changes: 12 additions & 0 deletions lib/core/domain/use_case/use_case.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'package:dartz/dartz.dart';
import 'package:twake/core/domain/state/failure.dart';

abstract class UseCase<Input extends UseCaseInput, Success> {
Either<ExceptionFailure, Success> execute({required Input input});
}

abstract class NonInputUseCase<Success> {
Either<ExceptionFailure, Success> execute();
}

abstract class UseCaseInput {}
16 changes: 16 additions & 0 deletions lib/features/message/data/datasource/message_datasource.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:twake/features/message/data/model/message/response/message.dart';

abstract class MessageDataSource {
Future<List<Message>> fetch({
String? companyId,
String? workspaceId,
required String channelId,
String? threadId,
String? afterMessageId,
bool? withExistedFiles = false,
});

Future<void> multiInsert({
required Iterable<Message> data,
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import 'package:twake/features/message/data/datasource/message_datasource.dart';
import 'package:twake/features/message/data/model/message/response/message.dart';
import 'package:twake/services/storage_service.dart';

class LocalMessageDataSourceImpl extends MessageDataSource {
final _storage = StorageService.instance;

@override
Future<List<Message>> fetch(
{String? companyId,
String? workspaceId,
required String channelId,
String? threadId,
String? afterMessageId,
bool? withExistedFiles = false}) async {
var where = 'channel_id = ?';
if (threadId == null) {
where += ' AND thread_id = id';
} else {
where += ' AND thread_id = ?';
}
if (withExistedFiles == true) {
where += ' AND files <> ?';
}

final localResult = await _storage.select(
table: Table.message,
where: where,
limit: threadId == null ? 25 : 9999,
orderBy: 'created_at DESC',
whereArgs: [
channelId,
if (threadId != null) threadId,
if (withExistedFiles == true) '[]'
],
);
final messages =
localResult.map((entry) => Message.fromJson(entry)).toList();

return messages;
}

@override
Future<void> multiInsert({required Iterable<Message> data}) async {
await _storage.multiInsert(table: Table.message, data: data);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import 'package:sprintf/sprintf.dart';
import 'package:twake/core/data/model/query/query_parameter.dart';
import 'package:twake/features/message/data/datasource/message_datasource.dart';
import 'package:twake/features/message/data/model/message/response/message.dart';
import 'package:twake/models/globals/globals.dart';
import 'package:twake/services/api_service.dart';
import 'package:twake/services/endpoints.dart';

class RemoteMessageDataSourceImpl extends MessageDataSource {
final _api = ApiService.instance;

@override
Future<List<Message>> fetch(
{String? companyId,
String? workspaceId,
required String channelId,
String? threadId,
String? afterMessageId,
bool? withExistedFiles = false}) async {
List<dynamic> remoteResult;

final queryParameters = <QueryParameter?>[
IntQueryParameter('include_users', 1),
BooleanQueryParameter('emoji', false),
StringQueryParameter('direction', 'history'),
IntQueryParameter('limit', 25),
];

if (afterMessageId != null) {
queryParameters.addAll([
StringQueryParameter('page_token', afterMessageId),
StringQueryParameter('direction', 'future'),
]);
}
if (withExistedFiles == true) {
queryParameters.add(
StringQueryParameter('filter', 'files'),
);
}
if (threadId == null) {
remoteResult = await _api.get(
endpoint: sprintf(Endpoint.threadsChannel, [
companyId ?? Globals.instance.companyId,
workspaceId ?? Globals.instance.workspaceId,
channelId
]),
queryParameters: queryParameters.toMap(),
key: 'resources',
);
} else {
final queryParameters = <QueryParameter?>[
IntQueryParameter('include_users', 1),
BooleanQueryParameter('emoji', false),
StringQueryParameter('direction', 'history'),
];

remoteResult = await _api.get(
endpoint: sprintf(Endpoint.threadMessages, [
companyId ?? Globals.instance.companyId,
threadId,
]),
queryParameters: queryParameters.toMap(),
key: 'resources',
);
}

return remoteResult
.where((rm) =>
rm['type'] == 'message' &&
rm['subtype'] != 'system' &&
rm['subtype'] !=
'application') // TODO remove the last condition once the support for applications has been implemented
.map((entry) => Message.fromJson(
entry,
channelId: channelId,
jsonify: true,
transform: true,
))
.toList();
}

@override
Future<void> multiInsert({required Iterable<Message> data}) {
// TODO: implement multiInsert
throw UnimplementedError();
}
}
Loading