Skip to content

Commit

Permalink
fix: feeback
Browse files Browse the repository at this point in the history
  • Loading branch information
AhsanRns committed Mar 28, 2024
1 parent 93b5b07 commit 6c735f6
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 87 deletions.
13 changes: 6 additions & 7 deletions easel/lib/easel_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -813,11 +813,11 @@ class EaselProvider extends ChangeNotifier {
uploadThumbnailResponse = uploadResponse.getOrElse(() => StorageResponseModel.initial());
}

final whereToUpload = QuickNode.listOfQuickNodeAllowedExtension().contains(fileExtension.toLowerCase());
final shouldUploadToQuickNode = QuickNode.listOfQuickNodeAllowedExtension().contains(fileExtension.toLowerCase());

Either<Failure, StorageResponseModel> response;

if (!whereToUpload) {
if (!shouldUploadToQuickNode) {
response = await repository.uploadFile(
file: _file!,
onUploadProgressCallback: (value) {
Expand All @@ -826,11 +826,10 @@ class EaselProvider extends ChangeNotifier {
);
} else {
response = await repository.uploadFileUsingQuickNode(
uploadIPFSInput: UploadIPFSInput(
fileName: fileName,
filePath: file?.path ?? '',
contentType: QuickNode.getContentType(fileExtension),
),
uploadIPFSInput: UploadIPFSInput(fileName: fileName, filePath: file!.path, contentType: QuickNode.getContentType(fileExtension)),
onUploadProgressCallback: (value) {
_uploadProgressController.sink.add(value);
},
);
}

Expand Down
6 changes: 3 additions & 3 deletions easel/lib/repository/repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ abstract class Repository {
/// 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});
Future<Either<Failure, StorageResponseModel>> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback});

/// This method will get the drafts List from the local database
/// Output: [List] returns that contains a number of [NFT]
Expand Down Expand Up @@ -331,13 +331,13 @@ class RepositoryImp implements Repository {
}

@override
Future<Either<Failure, StorageResponseModel>> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput}) async {
Future<Either<Failure, StorageResponseModel>> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback}) async {
if (!await networkInfo.isConnected) {
return Left(NoInternetFailure(LocaleKeys.no_internet.tr()));
}

try {
final storageResponseModel = await remoteDataSource.uploadFileUsingQuickNode(uploadIPFSInput: uploadIPFSInput);
final storageResponseModel = await remoteDataSource.uploadFileUsingQuickNode(uploadIPFSInput: uploadIPFSInput, onUploadProgressCallback: onUploadProgressCallback);
return Right(storageResponseModel);
} on Exception catch (_) {
crashlyticsHelper.recordFatalError(error: _.toString());
Expand Down
7 changes: 1 addition & 6 deletions easel/lib/screens/choose_format_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ class _ChooseFormatScreenState extends State<ChooseFormatScreen> {
return;
}




if (!provider.nftFormat.extensions.contains(result.extension)) {
final fileName = result.fileName.replaceAll(".${result.extension}", "");
errorText.value = LocaleKeys.could_not_uploaded.tr(
Expand Down Expand Up @@ -354,9 +351,7 @@ class _ErrorMessageWidget extends StatelessWidget {
),
SizedBox(height: 10.h),
Text(
(nftTypes == NFTTypes.video || nftTypes == NFTTypes.audio)
? "• ${(kFileSizeLimitForAudioVideoInGB * 1000).toStringAsFixed(0)}MB limit"
: "• ${kFileSizeLimitInGB}GB limit",
(nftTypes == NFTTypes.video || nftTypes == NFTTypes.audio) ? "• ${(kFileSizeLimitForAudioVideoInGB * 1000).toStringAsFixed(0)}MB limit" : "• ${kFileSizeLimitInGB}GB limit",
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Colors.white,
fontSize: 12.sp,
Expand Down
7 changes: 4 additions & 3 deletions easel/lib/services/datasources/remote_datasource.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ 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});
Future<StorageResponseModel> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback});
}

class RemoteDataSourceImpl implements RemoteDataSource {
Expand All @@ -45,8 +45,9 @@ class RemoteDataSourceImpl implements RemoteDataSource {
});

@override
Future<StorageResponseModel> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput}) async {
final response = await quickNode.uploadNewObjectToIPFS(uploadIPFSInput);
Future<StorageResponseModel> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback}) async {

final response = await quickNode.uploadNewObjectToIPFS(uploadIPFSInput: uploadIPFSInput, onUploadProgressCallback: onUploadProgressCallback);
return response;
}

Expand Down
109 changes: 45 additions & 64 deletions easel/lib/services/third_party_services/quick_node.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import 'dart:convert';
import 'dart:io';
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:easel_flutter/easel_provider.dart';
import 'package:easel_flutter/env.dart';
import 'package:easel_flutter/models/storage_response_model.dart';

///* using this because dio is already init with other base url
import 'package:http/http.dart' as http;
import 'package:easel_flutter/models/upload_progress.dart';

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<StorageResponseModel> uploadNewObjectToIPFS(UploadIPFSInput uploadIPFSInput);
Future<StorageResponseModel> uploadNewObjectToIPFS({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback});

/// these are the list of extension required
static List<String> listOfQuickNodeAllowedExtension() {
Expand All @@ -25,40 +24,36 @@ abstract class QuickNode {
}

class QuickNodeImpl extends QuickNode {
@override
Future<StorageResponseModel> uploadNewObjectToIPFS(UploadIPFSInput uploadIPFSInput) async {
final url = Uri.parse('https://api.quicknode.com/ipfs/rest/v1/s3/put-object');

final headers = {
'x-api-key': xApiKey,
};

final fields = {
'Key': uploadIPFSInput.fileName,
'ContentType': uploadIPFSInput.contentType,
};

final file = File(uploadIPFSInput.filePath);
QuickNodeImpl({required this.httpClient});

final request = http.MultipartRequest('POST', url);
final Dio httpClient;

request.headers.addAll(headers);

fields.forEach((key, value) {
request.fields[key] = value;
});

final fileStream = http.ByteStream(file.openRead());
final fileLength = await file.length();
final multipartFile = http.MultipartFile('Body', fileStream, fileLength, filename: file.path.split('/').last);

request.files.add(multipartFile);

final response = await http.Response.fromStream(await request.send());
@override
Future<StorageResponseModel> uploadNewObjectToIPFS({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback}) async {
try {
httpClient.options.headers['x-api-key'] = xApiKey;

final response = await httpClient.post(
'https://api.quicknode.com/ipfs/rest/v1/s3/put-object',
data: FormData.fromMap({
'Body': await MultipartFile.fromFile(uploadIPFSInput.filePath),
'Key': uploadIPFSInput.fileName,
'ContentType': uploadIPFSInput.contentType,
}),
onSendProgress: (uploaded, total) {
final double uploadedPercentage = uploaded / total;
onUploadProgressCallback(
UploadProgress(totalSize: total, sendSize: uploaded, uploadedProgressData: uploadedPercentage),
);
},
);

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

return StorageResponseModel.fromQuickNode(uploadIPFSOutput: a);
return StorageResponseModel.fromQuickNode(uploadIPFSOutput: uploadIPFSOutput);
} catch (e) {
throw Exception('Failed to upload file: $e');
}
}
}

Expand All @@ -72,10 +67,6 @@ class UploadIPFSInput {
required this.filePath,
required this.contentType,
});

Map<String, dynamic> toJson() {
return {};
}
}

class UploadIPFSOutput {
Expand All @@ -86,33 +77,25 @@ class UploadIPFSOutput {
final Info? info;
final List<String>? delegates;

UploadIPFSOutput({
this.requestId,
this.status,
this.created,
this.pin,
this.info,
this.delegates,
});

factory UploadIPFSOutput.fromJson(Map<String, dynamic> json) => UploadIPFSOutput(
requestId: json['requestid'] as String?,
status: json['status'] as String?,
created: json['created'] as String?,
pin: Pin.fromJson(json['pin'] as Map<String, dynamic>),
info: Info.fromJson(json['info'] as Map<String, dynamic>),
delegates: [],
);
UploadIPFSOutput({this.requestId, this.status, this.created, this.pin, this.info, this.delegates});

factory UploadIPFSOutput.fromJson(Map<String, dynamic> json) {
return UploadIPFSOutput(
requestId: json['requestid'] as String?,
status: json['status'] as String?,
created: json['created'] as String?,
pin: Pin.fromJson(json['pin'] as Map<String, dynamic>),
info: Info.fromJson(json['info'] as Map<String, dynamic>),
delegates: [],
);
}
}

class Pin {
String? cid;
String? name;

Pin({
this.cid,
this.name,
});
Pin({this.cid, this.name});

factory Pin.fromJson(Map<String, dynamic> json) => Pin(
cid: json['cid'] as String?,
Expand All @@ -123,9 +106,7 @@ class Pin {
class Info {
final String? size;

Info({
this.size,
});
Info({this.size});

factory Info.fromJson(Map<String, dynamic> json) => Info(size: json['size'] as String?);
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ void _registerLocalDataSources() {

void _registerProviders() {
sl.registerLazySingleton<EaselProvider>(
() => EaselProvider(videoPlayerHelper: sl(), audioPlayerHelperForFile: sl(), fileUtilsHelper: sl(), repository: sl(), audioPlayerHelperForUrl: sl(), mediaInfo: sl()));
() => EaselProvider(videoPlayerHelper: sl(), audioPlayerHelperForFile: sl(), fileUtilsHelper: sl(), repository: sl(), audioPlayerHelperForUrl: sl(), mediaInfo: sl()),
);
sl.registerLazySingleton<CreatorHubViewModel>(() => CreatorHubViewModel(sl()));
sl.registerLazySingleton<HomeViewModel>(() => HomeViewModel(sl()));
sl.registerLazySingleton<TutorialScreenViewModel>(() => TutorialScreenViewModel(repository: sl()));
Expand All @@ -88,5 +89,5 @@ void _registerServices() {
sl.registerLazySingleton<CrashlyticsHelper>(() => CrashlyticsHelperImp(crashlytics: sl()));
sl.registerLazySingleton<Repository>(() => RepositoryImp(networkInfo: sl(), localDataSource: sl(), remoteDataSource: sl(), fileUtilsHelper: sl(), crashlyticsHelper: sl()));

sl.registerLazySingleton<QuickNode>(() => QuickNodeImpl());
sl.registerLazySingleton<QuickNode>(() => QuickNodeImpl(httpClient: Dio()));
}
1 change: 0 additions & 1 deletion easel/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ dependencies:
focus_detector: ^2.0.1
get_it: ^7.2.0
google_fonts: ^4.0.3
http: ^0.13.6
image_cropper: ^4.0.1
internet_connection_checker: ^0.0.1+4
intl:
Expand Down
2 changes: 1 addition & 1 deletion easel/test/mock/mock_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ class MockRepositoryImp implements Repository {
}

@override
Future<Either<Failure, StorageResponseModel>> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput}) {
Future<Either<Failure, StorageResponseModel>> uploadFileUsingQuickNode({required UploadIPFSInput uploadIPFSInput, required OnUploadProgressCallback onUploadProgressCallback}) {
throw UnimplementedError();
}
}

0 comments on commit 6c735f6

Please sign in to comment.