Skip to content

Commit

Permalink
Merge pull request #1509 from ardriveapp/dev
Browse files Browse the repository at this point in the history
PE-5113: Release ArDrive App v2.26.0
  • Loading branch information
thiagocarvalhodev authored Dec 4, 2023
2 parents 6abd0d7 + 6b64540 commit 8b5f191
Show file tree
Hide file tree
Showing 21 changed files with 872 additions and 618 deletions.
2 changes: 2 additions & 0 deletions android/fastlane/metadata/android/en-US/changelogs/81.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Adding a feature to allow navigation back and forth between image previews.
- Adding the application version number to the shared file page.
65 changes: 62 additions & 3 deletions lib/blocs/drive_detail/drive_detail_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:ardrive/entities/constants.dart';
import 'package:ardrive/models/models.dart';
import 'package:ardrive/pages/pages.dart';
import 'package:ardrive/services/services.dart';
import 'package:ardrive/utils/constants.dart';
import 'package:ardrive/utils/logger/logger.dart';
import 'package:ardrive/utils/open_url.dart';
import 'package:ardrive/utils/user_utils.dart';
Expand All @@ -33,6 +34,8 @@ class DriveDetailCubit extends Cubit<DriveDetailState> {
List<ArDriveDataTableItem> _selectedItems = [];
List<ArDriveDataTableItem> get selectedItems => _selectedItems;

List<FileDataTableItem>? _allImagesOfCurrentFolder;

bool _forceDisableMultiselect = false;

bool _refreshSelectedItem = false;
Expand Down Expand Up @@ -78,6 +81,7 @@ class DriveDetailCubit extends Cubit<DriveDetailState> {
}) async {
try {
_selectedItem = null;
_allImagesOfCurrentFolder = null;

emit(DriveDetailLoadInProgress());

Expand Down Expand Up @@ -303,11 +307,12 @@ class DriveDetailCubit extends Cubit<DriveDetailState> {
_selectedItems = items;

if (items.isEmpty) {
state = state.copyWith(multiselect: false, hasFoldersSelected: false);
emit(state);
emit(state.copyWith(multiselect: false, hasFoldersSelected: false));
} else {
emit(state.copyWith(
multiselect: true, hasFoldersSelected: hasFolderSelected));
multiselect: true,
hasFoldersSelected: hasFolderSelected,
));
}
}

Expand Down Expand Up @@ -397,9 +402,63 @@ class DriveDetailCubit extends Cubit<DriveDetailState> {
}
}

bool canNavigateThroughImages() {
final numberOfImages = getAllImagesOfCurrentFolder().length;
return numberOfImages > 1;
}

Future<void> selectNextImage() => _selectImageRelativeToCurrent(1);
Future<void> selectPreviousImage() => _selectImageRelativeToCurrent(-1);

Future<void> _selectImageRelativeToCurrent(int offset) async {
final currentIndex = getIndexForImage(_selectedItem as FileDataTableItem);
final nextIndex = currentIndex + offset;
final nextImage = getImageForIndex(nextIndex);

await selectDataItem(nextImage);
}

FileDataTableItem getImageForIndex(int index) {
final allImagesOfCurrentFolder = getAllImagesOfCurrentFolder();
final cyclicIndex = index % allImagesOfCurrentFolder.length;
final image = allImagesOfCurrentFolder[cyclicIndex];

return image;
}

int getIndexForImage(FileDataTableItem image) {
final allImagesOfCurrentFolder = getAllImagesOfCurrentFolder();
final index = allImagesOfCurrentFolder.indexWhere(
(element) => element.id == image.id,
);

return index;
}

List<FileDataTableItem> getAllImagesOfCurrentFolder() {
if (_allImagesOfCurrentFolder != null) {
return _allImagesOfCurrentFolder!;
}

final state = this.state as DriveDetailLoadSuccess;
final allImagesForFolder = state.currentFolderContents
.whereType<FileDataTableItem>()
.where(
(element) => supportedImageTypesInFilePreview.contains(
element.contentType,
),
)
.toList();

_allImagesOfCurrentFolder = allImagesForFolder;

return allImagesForFolder;
}

@override
Future<void> close() {
_folderSubscription?.cancel();
_allImagesOfCurrentFolder = null;
return super.close();
}
}
152 changes: 85 additions & 67 deletions lib/blocs/fs_entry_preview/fs_entry_preview_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:ardrive/models/models.dart';
import 'package:ardrive/pages/pages.dart';
import 'package:ardrive/services/services.dart';
import 'package:ardrive/utils/constants.dart';
import 'package:ardrive/utils/logger/logger.dart';
import 'package:ardrive_http/ardrive_http.dart';
import 'package:ardrive_io/ardrive_io.dart';
import 'package:ardrive_utils/ardrive_utils.dart';
Expand All @@ -31,7 +32,7 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {
final SecretKey? _fileKey;

StreamSubscription? _entrySubscription;
final ValueNotifier<ImagePreviewNotification> imagePreviewNotifier =
static final ValueNotifier<ImagePreviewNotification> imagePreviewNotifier =
ValueNotifier<ImagePreviewNotification>(ImagePreviewNotification());

final previewMaxFileSize = 1024 * 1024 * 100;
Expand All @@ -55,13 +56,13 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {
_fileKey = fileKey,
super(FsEntryPreviewInitial()) {
if (isSharedFile) {
sharedFilePreview(maybeSelectedItem!, fileKey);
_sharedFilePreview(maybeSelectedItem!, fileKey);
} else {
preview();
_preview();
}
}

Future<void> sharedFilePreview(
Future<void> _sharedFilePreview(
ArDriveDataTableItem selectedItem,
SecretKey? fileKey,
) async {
Expand All @@ -80,7 +81,7 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {

switch (previewType) {
case 'image':
_previewImage(
_previewImageSharePage(
fileKey != null,
selectedItem,
previewUrl,
Expand Down Expand Up @@ -111,7 +112,7 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {
}
}

Future<void> preview() async {
Future<void> _preview() async {
final selectedItem = maybeSelectedItem;
if (selectedItem != null) {
if (selectedItem.runtimeType == FileDataTableItem) {
Expand All @@ -137,7 +138,7 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {

switch (previewType) {
case 'image':
emitImagePreview(file, previewUrl);
_previewImageDriveExplorer(file, previewUrl);
break;

case 'audio':
Expand Down Expand Up @@ -169,13 +170,76 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {
}
}

void _previewImage(
Future<void> _previewImageDriveExplorer(
FileEntry file,
String dataUrl,
) async {
imagePreviewNotifier.value = ImagePreviewNotification(
isLoading: true,
filename: file.name,
contentType: file.dataContentType,
);

emit(FsEntryPreviewImage(previewUrl: dataUrl));

final Uint8List? dataBytes = await _getBytesFromCache(
dataTxId: file.dataTxId,
dataUrl: dataUrl,
);

try {
final driveId = file.driveId;
final drive = await _driveDao.driveById(driveId: driveId).getSingle();
final isPinFile = file.pinnedDataOwnerAddress != null;

switch (drive.privacy) {
case DrivePrivacyTag.public:
_emitImagePreview(file, dataUrl, dataBytes: dataBytes);
break;
case DrivePrivacyTag.private:
if (dataBytes == null || isPinFile) {
_emitImagePreview(file, dataUrl, dataBytes: dataBytes);
break;
}

final fileKey = await _getFileKey(
fileId: file.id,
driveId: driveId,
isPrivate: true,
isPin: isPinFile,
);

final decodedBytes = await _decodePrivateData(
dataBytes,
fileKey!,
file.dataTxId,
);

_emitImagePreview(file, dataUrl, dataBytes: decodedBytes);
break;

default:
logger.e('Unknown drive privacy tag');
_emitImagePreview(file, dataUrl, dataBytes: dataBytes);
}
} catch (_) {
_emitImagePreview(file, dataUrl);
}
}

void _previewImageSharePage(
bool isPrivate,
FileDataTableItem file,
String previewUrl,
) async {
final isPinFile = file.pinnedDataOwnerAddress != null;

imagePreviewNotifier.value = ImagePreviewNotification(
isLoading: true,
filename: file.name,
contentType: file.contentType,
);

final Uint8List? dataBytes = await _getBytesFromCache(
dataTxId: file.dataTxId,
dataUrl: previewUrl,
Expand Down Expand Up @@ -205,18 +269,18 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {
);
imagePreviewNotifier.value = ImagePreviewNotification(
dataBytes: decodedBytes,
filename: file.name,
contentType: file.contentType,
);
} else {
imagePreviewNotifier.value = ImagePreviewNotification(
dataBytes: dataBytes,
filename: file.name,
contentType: file.contentType,
);
}

emit(FsEntryPreviewImage(
previewUrl: previewUrl,
filename: file.name,
contentType: file.contentType,
));
emit(FsEntryPreviewImage(previewUrl: previewUrl));
}

Future<SecretKey?> _getFileKey({
Expand Down Expand Up @@ -287,51 +351,6 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {
emit(FsEntryPreviewUnavailable());
}

Future<void> emitImagePreview(FileEntry file, String dataUrl) async {
try {
emit(const FsEntryPreviewLoading());

final Uint8List? dataBytes = await _getBytesFromCache(
dataTxId: file.dataTxId,
dataUrl: dataUrl,
);

final drive = await _driveDao.driveById(driveId: driveId).getSingle();
final isPinFile = file.pinnedDataOwnerAddress != null;

switch (drive.privacy) {
case DrivePrivacyTag.public:
_emitImagePreview(file, dataUrl, dataBytes: dataBytes);
break;
case DrivePrivacyTag.private:
final fileKey = await _getFileKey(
fileId: file.id,
driveId: driveId,
isPrivate: true,
isPin: isPinFile,
);

if (dataBytes == null || isPinFile) {
_emitImagePreview(file, dataUrl, dataBytes: dataBytes);
return;
}

final decodedBytes = await _decodePrivateData(
dataBytes,
fileKey!,
file.dataTxId,
);
_emitImagePreview(file, dataUrl, dataBytes: decodedBytes);
break;

default:
_emitImagePreview(file, dataUrl, dataBytes: dataBytes);
}
} catch (err) {
_emitImagePreview(file, dataUrl);
}
}

Future<Uint8List?> _getBytesFromCache({
required String dataTxId,
required String dataUrl,
Expand Down Expand Up @@ -400,15 +419,15 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {
String dataUrl, {
Uint8List? dataBytes,
}) {
if (isClosed) {
return;
}
imagePreviewNotifier.value = ImagePreviewNotification(
dataBytes: dataBytes,
);
emit(FsEntryPreviewImage(
previewUrl: dataUrl,
filename: file.name,
contentType:
file.dataContentType ?? lookupMimeTypeWithDefaultType(file.name),
));
contentType: file.dataContentType,
);
emit(FsEntryPreviewImage(previewUrl: dataUrl));
}

bool _supportedExtension(String? previewType, String? fileExtension) {
Expand All @@ -431,9 +450,8 @@ class FsEntryPreviewCubit extends Cubit<FsEntryPreviewState> {
}

@override
Future<void> close() {
_entrySubscription?.cancel();
imagePreviewNotifier.dispose();
Future<void> close() async {
await _entrySubscription?.cancel();
return super.close();
}
}
9 changes: 1 addition & 8 deletions lib/blocs/fs_entry_preview/fs_entry_preview_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,7 @@ class FsEntryPreviewLoading extends FsEntryPreviewSuccess {
}

class FsEntryPreviewImage extends FsEntryPreviewSuccess {
final String filename;
final String contentType;

const FsEntryPreviewImage({
required this.filename,
required this.contentType,
required super.previewUrl,
});
const FsEntryPreviewImage({required super.previewUrl});

@override
List<Object> get props => [previewUrl];
Expand Down
12 changes: 11 additions & 1 deletion lib/blocs/fs_entry_preview/image_preview_notification.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import 'dart:typed_data';

class ImagePreviewNotification {
bool isLoading;
Uint8List? dataBytes;
String? filename;
String? contentType;

ImagePreviewNotification({this.dataBytes});
bool get isPreviewable => dataBytes != null;

ImagePreviewNotification({
this.dataBytes,
this.filename,
this.contentType,
this.isLoading = false,
});
}
Loading

0 comments on commit 8b5f191

Please sign in to comment.