Skip to content

Commit

Permalink
feat: repositoty and remote data sources for the uploading thumbnail
Browse files Browse the repository at this point in the history
  • Loading branch information
AhsanRns committed May 15, 2024
1 parent 407981c commit 0ce678d
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 26 deletions.
3 changes: 2 additions & 1 deletion evently/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@
"free_gift": "Free Gift",
"free_drink": "1 free drink",
"publish" : "Publish",
"recipe_created": "Recipe созданный"
"recipe_created": "Recipe созданный",
"update_failed": "Upload Fehlgeschlagen"
}
3 changes: 2 additions & 1 deletion evently/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@
"free_gift": "Free Gift",
"free_drink": "1 free drink",
"publish" : "Publish",
"recipe_created": "Recipe created"
"recipe_created": "Recipe created",
"update_failed": "Upload Failed"
}
3 changes: 2 additions & 1 deletion evently/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@
"free_gift": "Free Gift",
"free_drink": "1 free drink",
"publish" : "Publish",
"recipe_created": "Recipe creada"
"recipe_created": "Recipe creada",
"update_failed": "Subida ha fallado"
}
3 changes: 2 additions & 1 deletion evently/i18n/ru-RU.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@
"free_gift": "Free Gift",
"free_drink": "1 free drink",
"publish" : "Publish",
"recipe_created": "Recipe созданный"
"recipe_created": "Recipe созданный",
"update_failed": "Загрузка не удалась"
}
1 change: 1 addition & 0 deletions evently/lib/generated/locale_keys.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,6 @@ abstract class LocaleKeys {
static const free_gift = 'free_gift';
static const free_drink = 'free_drink';
static const recipe_created = 'recipe_created';
static const update_failed = 'update_failed';

}
111 changes: 111 additions & 0 deletions evently/lib/models/storage_response_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import 'package:evently/services/third_party_services/quick_node.dart';

class StorageResponseModel {
bool? ok;
Value? value;

StorageResponseModel({this.ok, this.value});

StorageResponseModel.fromJson(Map<String, dynamic> json) {
ok = json['ok'] as bool?;
value = json['value'] != null ? Value.fromJson(json['value'] as Map<String, dynamic>) : null;
}

Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['ok'] = ok;
if (value != null) {
map['value'] = value?.toJson();
}
return map;
}

factory StorageResponseModel.initial() {
return StorageResponseModel();
}

factory StorageResponseModel.fromQuickNode({required UploadIPFSOutput uploadIPFSOutput}) {
return StorageResponseModel(
ok: true,
value: Value(
cid: uploadIPFSOutput.pin?.cid,
created: uploadIPFSOutput.created,
size: int.parse(
uploadIPFSOutput.info?.size ?? '0',
),
pin: Pin(
cid: uploadIPFSOutput.pin?.cid,
created: uploadIPFSOutput.created,
size: int.parse(
uploadIPFSOutput.info?.size ?? '0',
),
status: uploadIPFSOutput.status,
)),
);
}
}

class Value {
String? cid;
String? created;
String? type;
String? scope;
int? size;
Pin? pin;

Value({
this.cid,
this.created,
this.type,
this.scope,
this.size,
this.pin,
});

Value.fromJson(Map<String, dynamic> json) {
cid = json['cid'] as String?;
created = json['created'] as String?;
type = json['type'] as String?;
scope = json['scope'] as String?;
size = json['size'] as int?;
pin = json['pin'] != null ? Pin.fromJson(json['pin'] as Map<String, dynamic>) : null;
}

Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['cid'] = cid;
map['created'] = created;
map['type'] = type;
map['scope'] = scope;
map['size'] = size;
if (pin != null) {
map['pin'] = pin?.toJson();
}
return map;
}
}

class Pin {
String? cid;
String? created;
int? size;
String? status;

Pin({this.cid, this.created, this.size, this.status});

Pin.fromJson(Map<String, dynamic> json) {
cid = json['cid'] as String?;
created = json['created'] as String?;
size = json['size'] as int?;
status = json['status'] as String?;
}

Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['cid'] = cid;
map['created'] = created;
map['size'] = size;
map['status'] = status;
return map;
}
}
22 changes: 21 additions & 1 deletion evently/lib/repository/repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ import 'package:dartz/dartz.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:evently/generated/locale_keys.g.dart';
import 'package:evently/models/picked_file_model.dart';
import 'package:evently/models/storage_response_model.dart';
import 'package:evently/services/datasources/local_datasource.dart';
import 'package:evently/utils/failure/failure.dart';
import 'package:evently/services/datasources/remote_datasource.dart';
import 'package:evently/services/third_party_services/quick_node.dart';
import 'package:evently/utils/file_utils_helper.dart';
import 'package:injectable/injectable.dart';

import '../utils/failure/failure.dart';

abstract class Repository {
/// This function picks a file from device storage
/// Input: [format] it is the file format which needs to be picked from local storage
Expand All @@ -33,17 +37,24 @@ abstract class Repository {
/// This method will generate easel Id for the NFT
/// Output: [String] the id of the NFT that is going to be added in the recipe
String autoGenerateEventlyId();

/// This method is used uploading provided file to the server using [QuickNode]
/// Input : [UploadIPFSInput] which needs to be uploaded
/// Output : [ApiResponse] the ApiResponse which can contain [success] or [error] response
Future<Either<Failure, StorageResponseModel>> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback});
}

@LazySingleton(as: Repository)
class RepositoryImp implements Repository {
RepositoryImp({
required this.fileUtilsHelper,
required this.localDataSource,
required this.remoteDataSource,
});

final FileUtilsHelper fileUtilsHelper;
final LocalDataSource localDataSource;
final RemoteDataSource remoteDataSource;

@override
Future<Either<Failure, PickedFileModel>> pickFile() async {
Expand Down Expand Up @@ -79,4 +90,13 @@ class RepositoryImp implements Repository {
return localDataSource.autoGenerateEventlyId();
}

@override
Future<Either<Failure, StorageResponseModel>> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback}) async {
try {
final storageResponseModel = await remoteDataSource.uploadFileUsingQuickNode(uploadIPFSInput: uploadIPFSInput, onUploadProgressCallback: onUploadProgressCallback);
return Right(storageResponseModel);
} on Exception catch (_) {
return Left(CacheFailure(LocaleKeys.update_failed.tr()));
}
}
}
23 changes: 23 additions & 0 deletions evently/lib/services/datasources/remote_datasource.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:evently/models/storage_response_model.dart';
import 'package:evently/services/third_party_services/quick_node.dart';
import 'package:injectable/injectable.dart';

abstract class RemoteDataSource {
/// This method is used uploading provided file to the server using [QuickNode]
/// Input : [UploadIPFSInput] which needs to be uploaded
/// Output : [Future<ApiResponse<StorageResponseModel>>] the ApiResponse which can contain [success] or [error] response
Future<StorageResponseModel> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback});
}

@LazySingleton(as: RemoteDataSource)
class RemoteDataSourceImpl extends RemoteDataSource {
RemoteDataSourceImpl({required this.quickNode});

final QuickNode quickNode;

@override
Future<StorageResponseModel> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback}) async {
final response = await quickNode.uploadNewObjectToIPFS(uploadIPFSInput: uploadIPFSInput, onUploadProgressCallback: onUploadProgressCallback);
return response;
}
}
10 changes: 4 additions & 6 deletions evently/lib/services/third_party_services/quick_node.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dart:async';

import 'package:dio/dio.dart';
import 'package:evently/env.dart';
import 'package:evently/models/storage_response_model.dart';
import 'package:injectable/injectable.dart';

typedef OnUploadProgressCallback = void Function(UploadProgress uploadProgress);
Expand All @@ -22,15 +22,14 @@ abstract class QuickNode {
/// Upload a new object to IPFS and pins it for permanent storage on the network.
/// [UploadIPFSInput] as an input
/// [UploadIPFSOutput] as an output
Future<void> uploadNewObjectToIPFS({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback});
Future<StorageResponseModel> uploadNewObjectToIPFS({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback});

/// these are the list of extension required
static List<String> listOfQuickNodeAllowedExtension() => ['jpg', 'png', 'heif', 'jpeg', 'gif'];

/// this method is used to get the content type while making request input to quick node
static String getContentType(String fileExtension) {
final dict = {
///* images
"jpg": "image/jpg",
"png": "image/png",
'heif': "image/heif",
Expand All @@ -48,7 +47,7 @@ class QuickNodeImpl extends QuickNode {
final Dio httpClient;

@override
Future<void> uploadNewObjectToIPFS({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback}) async {
Future<StorageResponseModel> uploadNewObjectToIPFS({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback}) async {
try {
httpClient.options.headers['x-api-key'] = xApiKey;

Expand All @@ -68,8 +67,7 @@ class QuickNodeImpl extends QuickNode {
);

final uploadIPFSOutput = UploadIPFSOutput.fromJson(response.data as Map<String, dynamic>);

// return //StorageResponseModel.fromQuickNode(uploadIPFSOutput: uploadIPFSOutput);
return StorageResponseModel.fromQuickNode(uploadIPFSOutput: uploadIPFSOutput);
} catch (e) {
throw Exception('Failed to upload file: $e');
}
Expand Down
39 changes: 24 additions & 15 deletions evently/lib/utils/di/di.config.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions evently/lib/utils/failure/failure.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,10 @@ class PickingFileFailure extends Failure {
@override
List<Object?> get props => [message];
}

class CacheFailure extends Failure {
const CacheFailure(super.message);

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

0 comments on commit 0ce678d

Please sign in to comment.