Skip to content

Commit

Permalink
feat: upload from url (#233)
Browse files Browse the repository at this point in the history
  • Loading branch information
poppingmoon authored Jun 22, 2024
1 parent 6a41efd commit 68dfb2b
Show file tree
Hide file tree
Showing 10 changed files with 383 additions and 8 deletions.
15 changes: 15 additions & 0 deletions lib/model/streaming/main_event.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:misskey_dart/misskey_dart.dart';

part 'main_event.freezed.dart';
part 'main_event.g.dart';

sealed class MainEvent {}

class Notification implements MainEvent {
Expand Down Expand Up @@ -37,3 +41,14 @@ class AnnouncementCreated implements MainEvent {

final AnnouncementsResponse announcement;
}

@freezed
class UrlUploadFinished with _$UrlUploadFinished implements MainEvent {
const factory UrlUploadFinished({
String? marker,
required DriveFile file,
}) = _UrlUploadFinished;

factory UrlUploadFinished.fromJson(Map<String, Object?> json) =>
_$UrlUploadFinishedFromJson(json);
}
183 changes: 183 additions & 0 deletions lib/model/streaming/main_event.freezed.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark

part of 'main_event.dart';

// **************************************************************************
// FreezedGenerator
// **************************************************************************

T _$identity<T>(T value) => value;

final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');

UrlUploadFinished _$UrlUploadFinishedFromJson(Map<String, dynamic> json) {
return _UrlUploadFinished.fromJson(json);
}

/// @nodoc
mixin _$UrlUploadFinished {
String? get marker => throw _privateConstructorUsedError;
DriveFile get file => throw _privateConstructorUsedError;

Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$UrlUploadFinishedCopyWith<UrlUploadFinished> get copyWith =>
throw _privateConstructorUsedError;
}

/// @nodoc
abstract class $UrlUploadFinishedCopyWith<$Res> {
factory $UrlUploadFinishedCopyWith(
UrlUploadFinished value, $Res Function(UrlUploadFinished) then) =
_$UrlUploadFinishedCopyWithImpl<$Res, UrlUploadFinished>;
@useResult
$Res call({String? marker, DriveFile file});

$DriveFileCopyWith<$Res> get file;
}

/// @nodoc
class _$UrlUploadFinishedCopyWithImpl<$Res, $Val extends UrlUploadFinished>
implements $UrlUploadFinishedCopyWith<$Res> {
_$UrlUploadFinishedCopyWithImpl(this._value, this._then);

// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;

@pragma('vm:prefer-inline')
@override
$Res call({
Object? marker = freezed,
Object? file = null,
}) {
return _then(_value.copyWith(
marker: freezed == marker
? _value.marker
: marker // ignore: cast_nullable_to_non_nullable
as String?,
file: null == file
? _value.file
: file // ignore: cast_nullable_to_non_nullable
as DriveFile,
) as $Val);
}

@override
@pragma('vm:prefer-inline')
$DriveFileCopyWith<$Res> get file {
return $DriveFileCopyWith<$Res>(_value.file, (value) {
return _then(_value.copyWith(file: value) as $Val);
});
}
}

/// @nodoc
abstract class _$$UrlUploadFinishedImplCopyWith<$Res>
implements $UrlUploadFinishedCopyWith<$Res> {
factory _$$UrlUploadFinishedImplCopyWith(_$UrlUploadFinishedImpl value,
$Res Function(_$UrlUploadFinishedImpl) then) =
__$$UrlUploadFinishedImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({String? marker, DriveFile file});

@override
$DriveFileCopyWith<$Res> get file;
}

/// @nodoc
class __$$UrlUploadFinishedImplCopyWithImpl<$Res>
extends _$UrlUploadFinishedCopyWithImpl<$Res, _$UrlUploadFinishedImpl>
implements _$$UrlUploadFinishedImplCopyWith<$Res> {
__$$UrlUploadFinishedImplCopyWithImpl(_$UrlUploadFinishedImpl _value,
$Res Function(_$UrlUploadFinishedImpl) _then)
: super(_value, _then);

@pragma('vm:prefer-inline')
@override
$Res call({
Object? marker = freezed,
Object? file = null,
}) {
return _then(_$UrlUploadFinishedImpl(
marker: freezed == marker
? _value.marker
: marker // ignore: cast_nullable_to_non_nullable
as String?,
file: null == file
? _value.file
: file // ignore: cast_nullable_to_non_nullable
as DriveFile,
));
}
}

/// @nodoc
@JsonSerializable()
class _$UrlUploadFinishedImpl implements _UrlUploadFinished {
const _$UrlUploadFinishedImpl({this.marker, required this.file});

factory _$UrlUploadFinishedImpl.fromJson(Map<String, dynamic> json) =>
_$$UrlUploadFinishedImplFromJson(json);

@override
final String? marker;
@override
final DriveFile file;

@override
String toString() {
return 'UrlUploadFinished(marker: $marker, file: $file)';
}

@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$UrlUploadFinishedImpl &&
(identical(other.marker, marker) || other.marker == marker) &&
(identical(other.file, file) || other.file == file));
}

@JsonKey(ignore: true)
@override
int get hashCode => Object.hash(runtimeType, marker, file);

@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$UrlUploadFinishedImplCopyWith<_$UrlUploadFinishedImpl> get copyWith =>
__$$UrlUploadFinishedImplCopyWithImpl<_$UrlUploadFinishedImpl>(
this, _$identity);

@override
Map<String, dynamic> toJson() {
return _$$UrlUploadFinishedImplToJson(
this,
);
}
}

abstract class _UrlUploadFinished implements UrlUploadFinished {
const factory _UrlUploadFinished(
{final String? marker,
required final DriveFile file}) = _$UrlUploadFinishedImpl;

factory _UrlUploadFinished.fromJson(Map<String, dynamic> json) =
_$UrlUploadFinishedImpl.fromJson;

@override
String? get marker;
@override
DriveFile get file;
@override
@JsonKey(ignore: true)
_$$UrlUploadFinishedImplCopyWith<_$UrlUploadFinishedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
29 changes: 29 additions & 0 deletions lib/model/streaming/main_event.g.dart

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

16 changes: 16 additions & 0 deletions lib/provider/api/drive_files_notifier_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,22 @@ class DriveFilesNotifier extends _$DriveFilesNotifier {
state = AsyncValue.data(value.copyWith(items: [response, ...value.items]));
}

Future<void> uploadFromUrl(
String url, {
String? comment,
bool? isSensitive,
}) async {
await _misskey.drive.files.uploadFromUrl(
DriveFilesUploadFromUrlRequest(
url: url,
folderId: folderId,
comment: comment,
isSensitive: isSensitive,
force: true,
),
);
}

Future<void> delete(String fileId) async {
await _misskey.drive.files.delete(DriveFilesDeleteRequest(fileId: fileId));
final value = state.valueOrNull ?? const PaginationState();
Expand Down
2 changes: 1 addition & 1 deletion lib/provider/api/drive_files_notifier_provider.g.dart

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

2 changes: 2 additions & 0 deletions lib/provider/streaming/main_stream_notifier_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class MainStreamNotifier extends _$MainStreamNotifier {
body!['announcement'] as Map<String, dynamic>,
);
yield AnnouncementCreated(announcement);
case 'urlUploadFinished':
yield UrlUploadFinished.fromJson(body!);
}
}
}
Expand Down

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

20 changes: 14 additions & 6 deletions lib/view/page/timelines_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,23 +68,22 @@ class TimelinesPage extends HookConsumerWidget {
useEffect(
() {
void callback() {
if (tabs.isEmpty) return;
final previousIndex = tabIndex.value;
final nextIndex = controller.index;
if (previousIndex == nextIndex) {
return;
}
final previousAccount = tabSettings?.account;
if (previousIndex == nextIndex) return;
final previousAccount = tabs[previousIndex].account;
final nextTab = tabs[nextIndex];
final nextAccount = nextTab.account;
if (previousAccount != nextAccount) {
if (previousAccount?.host != nextAccount.host) {
if (previousAccount.host != nextAccount.host) {
ref
.read(
emojisNotifierProvider(nextAccount.host).notifier,
)
.reloadEmojis();
}
if (previousAccount != null && !previousAccount.isGuest) {
if (!previousAccount.isGuest) {
ref
.read(mainStreamNotifierProvider(previousAccount).notifier)
.disconnect();
Expand Down Expand Up @@ -112,6 +111,15 @@ class TimelinesPage extends HookConsumerWidget {
tabIndex.value = nextIndex;
}

if (tabSettings != null) {
final account = tabSettings.account;
ref
.read(emojisNotifierProvider(account.host).notifier)
.reloadEmojis();
if (!account.isGuest) {
ref.read(mainStreamNotifierProvider(account).notifier).connect();
}
}
controller.addListener(callback);
return () => controller.removeListener(callback);
},
Expand Down
29 changes: 29 additions & 0 deletions lib/view/widget/drive_create_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import '../../provider/file_system_provider.dart';
import '../../util/compress_image.dart';
import '../../util/future_with_dialog.dart';
import '../../util/randomize_filename.dart';
import '../dialog/message_dialog.dart';
import '../dialog/text_field_dialog.dart';

class DriveCreateSheet extends HookConsumerWidget {
Expand Down Expand Up @@ -67,6 +68,29 @@ class DriveCreateSheet extends HookConsumerWidget {
ref.context.pop();
}

Future<void> _uploadFromUrl(WidgetRef ref) async {
final result = await showTextFieldDialog(
ref.context,
title: Text(t.misskey.uploadFromUrl),
);
if (!ref.context.mounted) return;
if (result == null) return;
final url = Uri.tryParse(result.trim());
if (url == null) {
await showMessageDialog(ref.context, t.misskey.invalidValue);
return;
}
await futureWithDialog(
ref.context,
ref
.read(driveFilesNotifierProvider(account, folder?.id).notifier)
.uploadFromUrl(url.toString()),
message: t.misskey.uploadFromUrlRequested,
);
if (!ref.context.mounted) return;
ref.context.pop();
}

Future<void> _createFolder(WidgetRef ref) async {
final name = await showTextFieldDialog(
ref.context,
Expand Down Expand Up @@ -124,6 +148,11 @@ class DriveCreateSheet extends HookConsumerWidget {
keepOriginalFilename.value,
),
),
ListTile(
leading: const Icon(Icons.link),
title: Text(t.misskey.fromUrl),
onTap: () => _uploadFromUrl(ref),
),
ListTile(
leading: const Icon(Icons.folder),
title: Text(t.misskey.createFolder),
Expand Down
Loading

0 comments on commit 68dfb2b

Please sign in to comment.