✨ FIle index
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
description: This file stores settings for Dart & Flutter DevTools.
|
description: This file stores settings for Dart & Flutter DevTools.
|
||||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||||
extensions:
|
extensions:
|
||||||
|
- drift: true
|
||||||
|
- provider: true
|
||||||
|
- shared_preferences: true
|
||||||
@@ -60,3 +60,19 @@ sealed class SnCloudFile with _$SnCloudFile {
|
|||||||
factory SnCloudFile.fromJson(Map<String, dynamic> json) =>
|
factory SnCloudFile.fromJson(Map<String, dynamic> json) =>
|
||||||
_$SnCloudFileFromJson(json);
|
_$SnCloudFileFromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class SnCloudFileIndex with _$SnCloudFileIndex {
|
||||||
|
const factory SnCloudFileIndex({
|
||||||
|
required String id,
|
||||||
|
required String path,
|
||||||
|
required String fileId,
|
||||||
|
required SnCloudFile file,
|
||||||
|
required DateTime createdAt,
|
||||||
|
required DateTime updatedAt,
|
||||||
|
required DateTime? deletedAt,
|
||||||
|
}) = _SnCloudFileIndex;
|
||||||
|
|
||||||
|
factory SnCloudFileIndex.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnCloudFileIndexFromJson(json);
|
||||||
|
}
|
||||||
|
|||||||
@@ -622,4 +622,297 @@ $SnFilePoolCopyWith<$Res>? get pool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$SnCloudFileIndex {
|
||||||
|
|
||||||
|
String get id; String get path; String get fileId; SnCloudFile get file; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
|
||||||
|
/// Create a copy of SnCloudFileIndex
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnCloudFileIndexCopyWith<SnCloudFileIndex> get copyWith => _$SnCloudFileIndexCopyWithImpl<SnCloudFileIndex>(this as SnCloudFileIndex, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this SnCloudFileIndex to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnCloudFileIndex&&(identical(other.id, id) || other.id == id)&&(identical(other.path, path) || other.path == path)&&(identical(other.fileId, fileId) || other.fileId == fileId)&&(identical(other.file, file) || other.file == file)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,id,path,fileId,file,createdAt,updatedAt,deletedAt);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnCloudFileIndex(id: $id, path: $path, fileId: $fileId, file: $file, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $SnCloudFileIndexCopyWith<$Res> {
|
||||||
|
factory $SnCloudFileIndexCopyWith(SnCloudFileIndex value, $Res Function(SnCloudFileIndex) _then) = _$SnCloudFileIndexCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
String id, String path, String fileId, SnCloudFile file, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$SnCloudFileCopyWith<$Res> get file;
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$SnCloudFileIndexCopyWithImpl<$Res>
|
||||||
|
implements $SnCloudFileIndexCopyWith<$Res> {
|
||||||
|
_$SnCloudFileIndexCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final SnCloudFileIndex _self;
|
||||||
|
final $Res Function(SnCloudFileIndex) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnCloudFileIndex
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? path = null,Object? fileId = null,Object? file = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,path: null == path ? _self.path : path // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,fileId: null == fileId ? _self.fileId : fileId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,file: null == file ? _self.file : file // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnCloudFile,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
/// Create a copy of SnCloudFileIndex
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnCloudFileCopyWith<$Res> get file {
|
||||||
|
|
||||||
|
return $SnCloudFileCopyWith<$Res>(_self.file, (value) {
|
||||||
|
return _then(_self.copyWith(file: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [SnCloudFileIndex].
|
||||||
|
extension SnCloudFileIndexPatterns on SnCloudFileIndex {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnCloudFileIndex value)? $default,{required TResult orElse(),}){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnCloudFileIndex() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnCloudFileIndex value) $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnCloudFileIndex():
|
||||||
|
return $default(_that);}
|
||||||
|
}
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnCloudFileIndex value)? $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnCloudFileIndex() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String path, String fileId, SnCloudFile file, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnCloudFileIndex() when $default != null:
|
||||||
|
return $default(_that.id,_that.path,_that.fileId,_that.file,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String path, String fileId, SnCloudFile file, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnCloudFileIndex():
|
||||||
|
return $default(_that.id,_that.path,_that.fileId,_that.file,_that.createdAt,_that.updatedAt,_that.deletedAt);}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String path, String fileId, SnCloudFile file, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnCloudFileIndex() when $default != null:
|
||||||
|
return $default(_that.id,_that.path,_that.fileId,_that.file,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
|
||||||
|
class _SnCloudFileIndex implements SnCloudFileIndex {
|
||||||
|
const _SnCloudFileIndex({required this.id, required this.path, required this.fileId, required this.file, required this.createdAt, required this.updatedAt, required this.deletedAt});
|
||||||
|
factory _SnCloudFileIndex.fromJson(Map<String, dynamic> json) => _$SnCloudFileIndexFromJson(json);
|
||||||
|
|
||||||
|
@override final String id;
|
||||||
|
@override final String path;
|
||||||
|
@override final String fileId;
|
||||||
|
@override final SnCloudFile file;
|
||||||
|
@override final DateTime createdAt;
|
||||||
|
@override final DateTime updatedAt;
|
||||||
|
@override final DateTime? deletedAt;
|
||||||
|
|
||||||
|
/// Create a copy of SnCloudFileIndex
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$SnCloudFileIndexCopyWith<_SnCloudFileIndex> get copyWith => __$SnCloudFileIndexCopyWithImpl<_SnCloudFileIndex>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$SnCloudFileIndexToJson(this, );
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnCloudFileIndex&&(identical(other.id, id) || other.id == id)&&(identical(other.path, path) || other.path == path)&&(identical(other.fileId, fileId) || other.fileId == fileId)&&(identical(other.file, file) || other.file == file)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,id,path,fileId,file,createdAt,updatedAt,deletedAt);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnCloudFileIndex(id: $id, path: $path, fileId: $fileId, file: $file, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$SnCloudFileIndexCopyWith<$Res> implements $SnCloudFileIndexCopyWith<$Res> {
|
||||||
|
factory _$SnCloudFileIndexCopyWith(_SnCloudFileIndex value, $Res Function(_SnCloudFileIndex) _then) = __$SnCloudFileIndexCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
String id, String path, String fileId, SnCloudFile file, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@override $SnCloudFileCopyWith<$Res> get file;
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$SnCloudFileIndexCopyWithImpl<$Res>
|
||||||
|
implements _$SnCloudFileIndexCopyWith<$Res> {
|
||||||
|
__$SnCloudFileIndexCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _SnCloudFileIndex _self;
|
||||||
|
final $Res Function(_SnCloudFileIndex) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnCloudFileIndex
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? path = null,Object? fileId = null,Object? file = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||||
|
return _then(_SnCloudFileIndex(
|
||||||
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,path: null == path ? _self.path : path // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,fileId: null == fileId ? _self.fileId : fileId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,file: null == file ? _self.file : file // ignore: cast_nullable_to_non_nullable
|
||||||
|
as SnCloudFile,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of SnCloudFileIndex
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnCloudFileCopyWith<$Res> get file {
|
||||||
|
|
||||||
|
return $SnCloudFileCopyWith<$Res>(_self.file, (value) {
|
||||||
|
return _then(_self.copyWith(file: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// dart format on
|
// dart format on
|
||||||
|
|||||||
@@ -78,3 +78,28 @@ Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) =>
|
|||||||
'updated_at': instance.updatedAt.toIso8601String(),
|
'updated_at': instance.updatedAt.toIso8601String(),
|
||||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_SnCloudFileIndex _$SnCloudFileIndexFromJson(Map<String, dynamic> json) =>
|
||||||
|
_SnCloudFileIndex(
|
||||||
|
id: json['id'] as String,
|
||||||
|
path: json['path'] as String,
|
||||||
|
fileId: json['file_id'] as String,
|
||||||
|
file: SnCloudFile.fromJson(json['file'] as Map<String, dynamic>),
|
||||||
|
createdAt: DateTime.parse(json['created_at'] as String),
|
||||||
|
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||||
|
deletedAt:
|
||||||
|
json['deleted_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['deleted_at'] as String),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnCloudFileIndexToJson(_SnCloudFileIndex instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'path': instance.path,
|
||||||
|
'file_id': instance.fileId,
|
||||||
|
'file': instance.file.toJson(),
|
||||||
|
'created_at': instance.createdAt.toIso8601String(),
|
||||||
|
'updated_at': instance.updatedAt.toIso8601String(),
|
||||||
|
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||||
|
};
|
||||||
|
|||||||
@@ -349,6 +349,7 @@ class EnhancedFileUploader extends FileUploader {
|
|||||||
String? encryptPassword,
|
String? encryptPassword,
|
||||||
String? expiredAt,
|
String? expiredAt,
|
||||||
int? customChunkSize,
|
int? customChunkSize,
|
||||||
|
String? path,
|
||||||
Function(double? progress, Duration estimate)? onProgress,
|
Function(double? progress, Duration estimate)? onProgress,
|
||||||
}) async {
|
}) async {
|
||||||
// Step 1: Create upload task
|
// Step 1: Create upload task
|
||||||
@@ -362,6 +363,7 @@ class EnhancedFileUploader extends FileUploader {
|
|||||||
encryptPassword: encryptPassword,
|
encryptPassword: encryptPassword,
|
||||||
expiredAt: expiredAt,
|
expiredAt: expiredAt,
|
||||||
chunkSize: customChunkSize,
|
chunkSize: customChunkSize,
|
||||||
|
path: path,
|
||||||
);
|
);
|
||||||
|
|
||||||
int totalSize;
|
int totalSize;
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
|
import 'package:cross_file/cross_file.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/file.dart';
|
import 'package:island/models/file.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/pods/file_pool.dart';
|
import 'package:island/services/file_uploader.dart';
|
||||||
import 'package:island/utils/format.dart';
|
import 'package:island/utils/format.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
@@ -22,54 +24,35 @@ part 'file_list.g.dart';
|
|||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
class CloudFileListNotifier extends _$CloudFileListNotifier
|
class CloudFileListNotifier extends _$CloudFileListNotifier
|
||||||
with CursorPagingNotifierMixin<SnCloudFile> {
|
with CursorPagingNotifierMixin<SnCloudFileIndex> {
|
||||||
String? _poolId;
|
String _currentPath = '/';
|
||||||
bool _includeRecycled = false;
|
|
||||||
|
|
||||||
void setFilters(String? poolId, bool includeRecycled) {
|
void setPath(String path) {
|
||||||
_poolId = poolId;
|
_currentPath = path;
|
||||||
_includeRecycled = includeRecycled;
|
|
||||||
ref.invalidateSelf();
|
ref.invalidateSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<CursorPagingData<SnCloudFile>> build() => fetch(cursor: null);
|
Future<CursorPagingData<SnCloudFileIndex>> build() => fetch(cursor: null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<CursorPagingData<SnCloudFile>> fetch({required String? cursor}) async {
|
Future<CursorPagingData<SnCloudFileIndex>> fetch({
|
||||||
|
required String? cursor,
|
||||||
|
}) async {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
|
||||||
final take = 20;
|
|
||||||
|
|
||||||
final queryParameters = <String, dynamic>{'offset': offset, 'take': take};
|
|
||||||
|
|
||||||
// Add filter parameters
|
|
||||||
if (_poolId != null) {
|
|
||||||
queryParameters['pool'] = _poolId!;
|
|
||||||
}
|
|
||||||
if (_includeRecycled) {
|
|
||||||
queryParameters['recycled'] = 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
'/drive/files/me',
|
'/drive/index/browse',
|
||||||
queryParameters: queryParameters,
|
queryParameters: {'path': _currentPath},
|
||||||
);
|
);
|
||||||
|
|
||||||
final List<SnCloudFile> items =
|
final List<SnCloudFileIndex> items =
|
||||||
(response.data as List)
|
(response.data['files'] as List)
|
||||||
.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
|
.map((e) => SnCloudFileIndex.fromJson(e as Map<String, dynamic>))
|
||||||
.toList();
|
.toList();
|
||||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
|
||||||
|
|
||||||
final hasMore = offset + items.length < total;
|
// The new API returns all files in the path, no pagination
|
||||||
final nextCursor = hasMore ? (offset + items.length).toString() : null;
|
return CursorPagingData(items: items, hasMore: false, nextCursor: null);
|
||||||
|
|
||||||
return CursorPagingData(
|
|
||||||
items: items,
|
|
||||||
hasMore: hasMore,
|
|
||||||
nextCursor: nextCursor,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,19 +75,18 @@ class FileListScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
// Filter state
|
// Path navigation state
|
||||||
final selectedPool = useState<String?>(null);
|
final currentPath = useState<String>('/');
|
||||||
final includeRecycled = useState(false);
|
|
||||||
|
|
||||||
final usageAsync = ref.watch(billingUsageProvider);
|
final usageAsync = ref.watch(billingUsageProvider);
|
||||||
final quotaAsync = ref.watch(billingQuotaProvider);
|
final quotaAsync = ref.watch(billingQuotaProvider);
|
||||||
|
|
||||||
// Update notifier filters when state changes
|
// Update notifier path when state changes
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
final notifier = ref.read(cloudFileListNotifierProvider.notifier);
|
final notifier = ref.read(cloudFileListNotifierProvider.notifier);
|
||||||
notifier.setFilters(selectedPool.value, includeRecycled.value);
|
notifier.setPath(currentPath.value);
|
||||||
return null;
|
return null;
|
||||||
}, [selectedPool.value, includeRecycled.value]);
|
}, [currentPath.value]);
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
isNoBackground: false,
|
isNoBackground: false,
|
||||||
@@ -112,6 +94,11 @@ class FileListScreen extends HookConsumerWidget {
|
|||||||
title: Text('Files'),
|
title: Text('Files'),
|
||||||
leading: const PageBackButton(),
|
leading: const PageBackButton(),
|
||||||
actions: [
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Symbols.upload_file),
|
||||||
|
onPressed: () => _pickAndUploadFile(ref, currentPath.value),
|
||||||
|
tooltip: 'Upload File',
|
||||||
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.bar_chart),
|
icon: const Icon(Symbols.bar_chart),
|
||||||
onPressed:
|
onPressed:
|
||||||
@@ -127,14 +114,7 @@ class FileListScreen extends HookConsumerWidget {
|
|||||||
body: usageAsync.when(
|
body: usageAsync.when(
|
||||||
data:
|
data:
|
||||||
(usage) => quotaAsync.when(
|
(usage) => quotaAsync.when(
|
||||||
data:
|
data: (quota) => _buildQuotaUI(usage, quota, ref, currentPath),
|
||||||
(quota) => _buildQuotaUI(
|
|
||||||
usage,
|
|
||||||
quota,
|
|
||||||
ref,
|
|
||||||
selectedPool,
|
|
||||||
includeRecycled,
|
|
||||||
),
|
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
error: (e, _) => Center(child: Text('Error loading quota')),
|
error: (e, _) => Center(child: Text('Error loading quota')),
|
||||||
),
|
),
|
||||||
@@ -148,16 +128,13 @@ class FileListScreen extends HookConsumerWidget {
|
|||||||
Map<String, dynamic>? usage,
|
Map<String, dynamic>? usage,
|
||||||
Map<String, dynamic>? quota,
|
Map<String, dynamic>? quota,
|
||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
ValueNotifier<String?> selectedPool,
|
ValueNotifier<String> currentPath,
|
||||||
ValueNotifier<bool> includeRecycled,
|
|
||||||
) {
|
) {
|
||||||
if (usage == null) return const SizedBox.shrink();
|
if (usage == null) return const SizedBox.shrink();
|
||||||
return CustomScrollView(
|
return CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
const SliverGap(8),
|
const SliverGap(8),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(child: _buildPathNavigation(ref, currentPath)),
|
||||||
child: _buildFilters(ref, selectedPool, includeRecycled),
|
|
||||||
),
|
|
||||||
const SliverGap(8),
|
const SliverGap(8),
|
||||||
PagingHelperSliverView(
|
PagingHelperSliverView(
|
||||||
provider: cloudFileListNotifierProvider,
|
provider: cloudFileListNotifierProvider,
|
||||||
@@ -172,7 +149,8 @@ class FileListScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final item = data.items[index];
|
final item = data.items[index];
|
||||||
final itemType = item.mimeType?.split('/').firstOrNull;
|
final file = item.file;
|
||||||
|
final itemType = file.mimeType?.split('/').firstOrNull;
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: ClipRRect(
|
leading: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
@@ -180,7 +158,7 @@ class FileListScreen extends HookConsumerWidget {
|
|||||||
height: 48,
|
height: 48,
|
||||||
width: 48,
|
width: 48,
|
||||||
child: switch (itemType) {
|
child: switch (itemType) {
|
||||||
'image' => CloudImageWidget(file: item),
|
'image' => CloudImageWidget(file: file),
|
||||||
'audio' =>
|
'audio' =>
|
||||||
const Icon(Symbols.audio_file, fill: 1).center(),
|
const Icon(Symbols.audio_file, fill: 1).center(),
|
||||||
'video' =>
|
'video' =>
|
||||||
@@ -191,20 +169,20 @@ class FileListScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
title:
|
title:
|
||||||
item.name.isEmpty
|
file.name.isEmpty
|
||||||
? Text('untitled').tr().italic()
|
? Text('untitled').tr().italic()
|
||||||
: Text(
|
: Text(
|
||||||
item.name,
|
file.name,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
subtitle: Text(formatFileSize(item.size)),
|
subtitle: Text(formatFileSize(file.size)),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
useRootNavigator: true,
|
useRootNavigator: true,
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
builder: (context) => FileInfoSheet(item: item),
|
builder: (context) => FileInfoSheet(item: file),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
@@ -219,7 +197,7 @@ class FileListScreen extends HookConsumerWidget {
|
|||||||
if (context.mounted) showLoadingModal(context);
|
if (context.mounted) showLoadingModal(context);
|
||||||
try {
|
try {
|
||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
await client.delete('/drive/files/${item.id}');
|
await client.delete('/drive/index/remove/${item.id}');
|
||||||
ref.invalidate(cloudFileListNotifierProvider);
|
ref.invalidate(cloudFileListNotifierProvider);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showSnackBar('failedToDeleteFile'.tr());
|
showSnackBar('failedToDeleteFile'.tr());
|
||||||
@@ -236,138 +214,81 @@ class FileListScreen extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildFilters(
|
Widget _buildPathNavigation(
|
||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
ValueNotifier<String?> selectedPool,
|
ValueNotifier<String> currentPath,
|
||||||
ValueNotifier<bool> includeRecycled,
|
|
||||||
) {
|
) {
|
||||||
final poolsAsync = ref.watch(poolsProvider);
|
if (currentPath.value == '/') {
|
||||||
|
return Card(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Symbols.folder),
|
||||||
|
const Gap(8),
|
||||||
|
Text(
|
||||||
|
'Root Directory',
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).padding(horizontal: 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
final pathParts =
|
||||||
|
currentPath.value.split('/').where((part) => part.isNotEmpty).toList();
|
||||||
|
final breadcrumbs = <Widget>[];
|
||||||
|
|
||||||
|
// Add root
|
||||||
|
breadcrumbs.add(
|
||||||
|
InkWell(
|
||||||
|
onTap: () => currentPath.value = '/',
|
||||||
|
child: Text(
|
||||||
|
'Root',
|
||||||
|
style: TextStyle(color: Theme.of(ref.context).primaryColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add path parts
|
||||||
|
String currentPathBuilder = '';
|
||||||
|
for (int i = 0; i < pathParts.length; i++) {
|
||||||
|
currentPathBuilder += '/${pathParts[i]}';
|
||||||
|
final path = currentPathBuilder;
|
||||||
|
|
||||||
|
breadcrumbs.add(const Text(' / '));
|
||||||
|
if (i == pathParts.length - 1) {
|
||||||
|
// Current directory
|
||||||
|
breadcrumbs.add(
|
||||||
|
Text(pathParts[i], style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Clickable parent directory
|
||||||
|
breadcrumbs.add(
|
||||||
|
InkWell(
|
||||||
|
onTap: () => currentPath.value = path,
|
||||||
|
child: Text(
|
||||||
|
pathParts[i],
|
||||||
|
style: TextStyle(color: Theme.of(ref.context).primaryColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Text(
|
const Icon(Symbols.folder),
|
||||||
'filters'.tr(),
|
const Gap(8),
|
||||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
Expanded(
|
||||||
),
|
child: Wrap(
|
||||||
const Gap(16),
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
LayoutBuilder(
|
children: breadcrumbs,
|
||||||
builder: (context, constraints) {
|
),
|
||||||
final isWide = constraints.maxWidth > 600;
|
|
||||||
return isWide
|
|
||||||
? Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: poolsAsync.when(
|
|
||||||
data:
|
|
||||||
(pools) => DropdownButtonFormField<String?>(
|
|
||||||
value: selectedPool.value,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: 'Pool',
|
|
||||||
border: const OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
items: [
|
|
||||||
DropdownMenuItem<String?>(
|
|
||||||
value: null,
|
|
||||||
child: Text('allPools'.tr()),
|
|
||||||
),
|
|
||||||
...pools.map(
|
|
||||||
(pool) => DropdownMenuItem<String?>(
|
|
||||||
value: pool.id,
|
|
||||||
child: Text(pool.name),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
onChanged:
|
|
||||||
(value) => selectedPool.value = value,
|
|
||||||
),
|
|
||||||
loading: () => const CircularProgressIndicator(),
|
|
||||||
error: (e, _) => const Text('Error loading pools'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Gap(8),
|
|
||||||
Expanded(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Text('includeRecycled'.tr()),
|
|
||||||
const Gap(8),
|
|
||||||
Switch(
|
|
||||||
value: includeRecycled.value,
|
|
||||||
onChanged:
|
|
||||||
(value) => includeRecycled.value = value,
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Gap(16),
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Symbols.delete_sweep),
|
|
||||||
tooltip: 'deleteRecycledFiles'.tr(),
|
|
||||||
onPressed:
|
|
||||||
includeRecycled.value
|
|
||||||
? () => _deleteRecycledFiles(ref)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
poolsAsync.when(
|
|
||||||
data:
|
|
||||||
(pools) => DropdownButtonFormField<String?>(
|
|
||||||
value: selectedPool.value,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
labelText: 'Pool',
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
items: [
|
|
||||||
DropdownMenuItem<String?>(
|
|
||||||
value: null,
|
|
||||||
child: Text('allPools'.tr()),
|
|
||||||
),
|
|
||||||
...pools.map(
|
|
||||||
(pool) => DropdownMenuItem<String?>(
|
|
||||||
value: pool.id,
|
|
||||||
child: Text(pool.name),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
onChanged:
|
|
||||||
(value) => selectedPool.value = value,
|
|
||||||
),
|
|
||||||
loading: () => const CircularProgressIndicator(),
|
|
||||||
error: (e, _) => const Text('Error loading pools'),
|
|
||||||
),
|
|
||||||
const Gap(16),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text('includeRecycled'.tr()),
|
|
||||||
const Gap(8),
|
|
||||||
Switch(
|
|
||||||
value: includeRecycled.value,
|
|
||||||
onChanged:
|
|
||||||
(value) => includeRecycled.value = value,
|
|
||||||
),
|
|
||||||
const Spacer(),
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Symbols.delete_sweep),
|
|
||||||
tooltip: 'deleteRecycledFiles'.tr(),
|
|
||||||
onPressed:
|
|
||||||
includeRecycled.value
|
|
||||||
? () => _deleteRecycledFiles(ref)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -375,23 +296,52 @@ class FileListScreen extends HookConsumerWidget {
|
|||||||
).padding(horizontal: 8);
|
).padding(horizontal: 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _deleteRecycledFiles(WidgetRef ref) async {
|
Future<void> _pickAndUploadFile(WidgetRef ref, String currentPath) async {
|
||||||
final confirmed = await showConfirmAlert(
|
|
||||||
'confirmDeleteRecycledFiles'.tr(),
|
|
||||||
'deleteRecycledFiles'.tr(),
|
|
||||||
);
|
|
||||||
if (!confirmed) return;
|
|
||||||
|
|
||||||
if (ref.context.mounted) showLoadingModal(ref.context);
|
|
||||||
try {
|
try {
|
||||||
final client = ref.read(apiClientProvider);
|
final result = await FilePicker.platform.pickFiles(
|
||||||
await client.delete('/drive/files/recycled');
|
allowMultiple: true,
|
||||||
ref.invalidate(cloudFileListNotifierProvider);
|
withData: false,
|
||||||
showSnackBar('recycledFilesDeleted'.tr());
|
);
|
||||||
|
|
||||||
|
if (result != null && result.files.isNotEmpty) {
|
||||||
|
for (final file in result.files) {
|
||||||
|
if (file.path != null) {
|
||||||
|
// Create UniversalFile from the picked file
|
||||||
|
final universalFile = UniversalFile(
|
||||||
|
data: XFile(file.path!),
|
||||||
|
type: UniversalFileType.file,
|
||||||
|
displayName: file.name,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Upload the file with the current path
|
||||||
|
final completer = FileUploader.createCloudFile(
|
||||||
|
fileData: universalFile,
|
||||||
|
ref: ref,
|
||||||
|
path: currentPath,
|
||||||
|
onProgress: (progress, _) {
|
||||||
|
// Progress is handled by the upload tasks system
|
||||||
|
if (progress != null) {
|
||||||
|
debugPrint('Upload progress: ${(progress * 100).toInt()}%');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
completer.future
|
||||||
|
.then((uploadedFile) {
|
||||||
|
if (uploadedFile != null) {
|
||||||
|
// Refresh the file list after successful upload
|
||||||
|
ref.invalidate(cloudFileListNotifierProvider);
|
||||||
|
showSnackBar('File uploaded successfully');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catchError((error) {
|
||||||
|
showSnackBar('Failed to upload file: $error');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showSnackBar('failedToDeleteRecycledFiles'.tr());
|
showSnackBar('Error picking file: $e');
|
||||||
} finally {
|
|
||||||
if (ref.context.mounted) hideLoadingModal(ref.context);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,13 +45,13 @@ final billingQuotaProvider =
|
|||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef BillingQuotaRef = AutoDisposeFutureProviderRef<Map<String, dynamic>?>;
|
typedef BillingQuotaRef = AutoDisposeFutureProviderRef<Map<String, dynamic>?>;
|
||||||
String _$cloudFileListNotifierHash() =>
|
String _$cloudFileListNotifierHash() =>
|
||||||
r'22c45a8ea23147a3835ba870ad2f0bb833f853ea';
|
r'a29adc14e3eede41be05de373785f13439cf9e60';
|
||||||
|
|
||||||
/// See also [CloudFileListNotifier].
|
/// See also [CloudFileListNotifier].
|
||||||
@ProviderFor(CloudFileListNotifier)
|
@ProviderFor(CloudFileListNotifier)
|
||||||
final cloudFileListNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
final cloudFileListNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
||||||
CloudFileListNotifier,
|
CloudFileListNotifier,
|
||||||
CursorPagingData<SnCloudFile>
|
CursorPagingData<SnCloudFileIndex>
|
||||||
>.internal(
|
>.internal(
|
||||||
CloudFileListNotifier.new,
|
CloudFileListNotifier.new,
|
||||||
name: r'cloudFileListNotifierProvider',
|
name: r'cloudFileListNotifierProvider',
|
||||||
@@ -64,6 +64,6 @@ final cloudFileListNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
|||||||
);
|
);
|
||||||
|
|
||||||
typedef _$CloudFileListNotifier =
|
typedef _$CloudFileListNotifier =
|
||||||
AutoDisposeAsyncNotifier<CursorPagingData<SnCloudFile>>;
|
AutoDisposeAsyncNotifier<CursorPagingData<SnCloudFileIndex>>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class FileUploader {
|
|||||||
String? encryptPassword,
|
String? encryptPassword,
|
||||||
String? expiredAt,
|
String? expiredAt,
|
||||||
int? chunkSize,
|
int? chunkSize,
|
||||||
|
String? path,
|
||||||
}) async {
|
}) async {
|
||||||
String hash;
|
String hash;
|
||||||
int fileSize;
|
int fileSize;
|
||||||
@@ -100,6 +101,7 @@ class FileUploader {
|
|||||||
'encrypt_password': encryptPassword,
|
'encrypt_password': encryptPassword,
|
||||||
'expired_at': expiredAt,
|
'expired_at': expiredAt,
|
||||||
'chunk_size': chunkSize,
|
'chunk_size': chunkSize,
|
||||||
|
'path': path,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -150,6 +152,7 @@ class FileUploader {
|
|||||||
String? encryptPassword,
|
String? encryptPassword,
|
||||||
String? expiredAt,
|
String? expiredAt,
|
||||||
int? customChunkSize,
|
int? customChunkSize,
|
||||||
|
String? path,
|
||||||
Function(double? progress, Duration estimate)? onProgress,
|
Function(double? progress, Duration estimate)? onProgress,
|
||||||
}) async {
|
}) async {
|
||||||
// Step 1: Create upload task
|
// Step 1: Create upload task
|
||||||
@@ -163,6 +166,7 @@ class FileUploader {
|
|||||||
encryptPassword: encryptPassword,
|
encryptPassword: encryptPassword,
|
||||||
expiredAt: expiredAt,
|
expiredAt: expiredAt,
|
||||||
chunkSize: customChunkSize,
|
chunkSize: customChunkSize,
|
||||||
|
path: path,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (createResponse['file_exists'] == true) {
|
if (createResponse['file_exists'] == true) {
|
||||||
@@ -238,6 +242,7 @@ class FileUploader {
|
|||||||
required UniversalFile fileData,
|
required UniversalFile fileData,
|
||||||
required WidgetRef ref,
|
required WidgetRef ref,
|
||||||
String? poolId,
|
String? poolId,
|
||||||
|
String? path,
|
||||||
FileUploadMode? mode,
|
FileUploadMode? mode,
|
||||||
Function(double? progress, Duration estimate)? onProgress,
|
Function(double? progress, Duration estimate)? onProgress,
|
||||||
}) {
|
}) {
|
||||||
@@ -273,8 +278,14 @@ class FileUploader {
|
|||||||
await exif.writeAttributes(gpsAttributes);
|
await exif.writeAttributes(gpsAttributes);
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
(_) =>
|
(_) => _processUpload(
|
||||||
_processUpload(fileData, ref, poolId, onProgress, completer),
|
fileData,
|
||||||
|
ref,
|
||||||
|
poolId,
|
||||||
|
path,
|
||||||
|
onProgress,
|
||||||
|
completer,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.catchError((e) {
|
.catchError((e) {
|
||||||
debugPrint('Error removing GPS EXIF data: $e');
|
debugPrint('Error removing GPS EXIF data: $e');
|
||||||
@@ -282,6 +293,7 @@ class FileUploader {
|
|||||||
fileData,
|
fileData,
|
||||||
ref,
|
ref,
|
||||||
poolId,
|
poolId,
|
||||||
|
path,
|
||||||
onProgress,
|
onProgress,
|
||||||
completer,
|
completer,
|
||||||
);
|
);
|
||||||
@@ -291,7 +303,7 @@ class FileUploader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_processUpload(fileData, ref, poolId, onProgress, completer);
|
_processUpload(fileData, ref, poolId, path, onProgress, completer);
|
||||||
return completer;
|
return completer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,6 +312,7 @@ class FileUploader {
|
|||||||
UniversalFile fileData,
|
UniversalFile fileData,
|
||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
String? poolId,
|
String? poolId,
|
||||||
|
String? path,
|
||||||
Function(double? progress, Duration estimate)? onProgress,
|
Function(double? progress, Duration estimate)? onProgress,
|
||||||
Completer<SnCloudFile?> completer,
|
Completer<SnCloudFile?> completer,
|
||||||
) {
|
) {
|
||||||
@@ -314,6 +327,7 @@ class FileUploader {
|
|||||||
_performUpload(
|
_performUpload(
|
||||||
fileData: data,
|
fileData: data,
|
||||||
fileName: fileData.displayName ?? data.name,
|
fileName: fileData.displayName ?? data.name,
|
||||||
|
path: path,
|
||||||
contentType: actualMimetype,
|
contentType: actualMimetype,
|
||||||
ref: ref,
|
ref: ref,
|
||||||
poolId: poolId,
|
poolId: poolId,
|
||||||
@@ -342,6 +356,7 @@ class FileUploader {
|
|||||||
fileData: bytes,
|
fileData: bytes,
|
||||||
fileName: actualFilename,
|
fileName: actualFilename,
|
||||||
contentType: actualMimetype,
|
contentType: actualMimetype,
|
||||||
|
path: path,
|
||||||
ref: ref,
|
ref: ref,
|
||||||
poolId: poolId,
|
poolId: poolId,
|
||||||
onProgress: onProgress,
|
onProgress: onProgress,
|
||||||
@@ -359,6 +374,7 @@ class FileUploader {
|
|||||||
required String contentType,
|
required String contentType,
|
||||||
required WidgetRef ref,
|
required WidgetRef ref,
|
||||||
String? poolId,
|
String? poolId,
|
||||||
|
String? path,
|
||||||
Function(double? progress, Duration estimate)? onProgress,
|
Function(double? progress, Duration estimate)? onProgress,
|
||||||
required Completer<SnCloudFile?> completer,
|
required Completer<SnCloudFile?> completer,
|
||||||
}) {
|
}) {
|
||||||
@@ -373,6 +389,7 @@ class FileUploader {
|
|||||||
fileName: fileName,
|
fileName: fileName,
|
||||||
contentType: contentType,
|
contentType: contentType,
|
||||||
poolId: poolId,
|
poolId: poolId,
|
||||||
|
path: path,
|
||||||
onProgress: onProgress,
|
onProgress: onProgress,
|
||||||
)
|
)
|
||||||
.then((result) {
|
.then((result) {
|
||||||
|
|||||||
Reference in New Issue
Block a user