Compare commits
No commits in common. "b2a6ca72447d9f2ff0304dc209f04aef2959983d" and "8b3c45ab294d091116346c44d5328bb2e3b1ce14" have entirely different histories.
b2a6ca7244
...
8b3c45ab29
@ -115,10 +115,10 @@ class PostEditorController extends GetxController {
|
|||||||
builder: (context) => AttachmentEditorPopup(
|
builder: (context) => AttachmentEditorPopup(
|
||||||
usage: 'i.attachment',
|
usage: 'i.attachment',
|
||||||
initialAttachments: attachments,
|
initialAttachments: attachments,
|
||||||
onAdd: (int value) {
|
onAdd: (value) {
|
||||||
attachments.add(value);
|
attachments.add(value);
|
||||||
},
|
},
|
||||||
onRemove: (int value) {
|
onRemove: (value) {
|
||||||
attachments.remove(value);
|
attachments.remove(value);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
@ -27,40 +26,11 @@ class AttachmentUploaderController extends GetxController {
|
|||||||
RxDouble progressOfUpload = 0.0.obs;
|
RxDouble progressOfUpload = 0.0.obs;
|
||||||
RxList<AttachmentUploadTask> queueOfUpload = RxList.empty(growable: true);
|
RxList<AttachmentUploadTask> queueOfUpload = RxList.empty(growable: true);
|
||||||
|
|
||||||
Timer? _progressSyncTimer;
|
|
||||||
double _progressOfUpload = 0.0;
|
|
||||||
|
|
||||||
void _syncProgress() {
|
|
||||||
progressOfUpload.value = _progressOfUpload;
|
|
||||||
queueOfUpload.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startProgressSyncTimer() {
|
|
||||||
if (_progressSyncTimer != null) {
|
|
||||||
_progressSyncTimer!.cancel();
|
|
||||||
}
|
|
||||||
_progressSyncTimer = Timer.periodic(
|
|
||||||
const Duration(milliseconds: 500),
|
|
||||||
(_) => _syncProgress(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _stopProgressSyncTimer() {
|
|
||||||
if (_progressSyncTimer == null) return;
|
|
||||||
_progressSyncTimer!.cancel();
|
|
||||||
_progressSyncTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void enqueueTask(AttachmentUploadTask task) {
|
void enqueueTask(AttachmentUploadTask task) {
|
||||||
if (isUploading.value) throw Exception('uploading blocked');
|
if (isUploading.value) throw Exception('uploading blocked');
|
||||||
queueOfUpload.add(task);
|
queueOfUpload.add(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
void enqueueTaskBatch(Iterable<AttachmentUploadTask> tasks) {
|
|
||||||
if (isUploading.value) throw Exception('uploading blocked');
|
|
||||||
queueOfUpload.addAll(tasks);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dequeueTask(AttachmentUploadTask task) {
|
void dequeueTask(AttachmentUploadTask task) {
|
||||||
if (isUploading.value) throw Exception('uploading blocked');
|
if (isUploading.value) throw Exception('uploading blocked');
|
||||||
queueOfUpload.remove(task);
|
queueOfUpload.remove(task);
|
||||||
@ -70,8 +40,8 @@ class AttachmentUploaderController extends GetxController {
|
|||||||
isUploading.value = true;
|
isUploading.value = true;
|
||||||
progressOfUpload.value = 0;
|
progressOfUpload.value = 0;
|
||||||
|
|
||||||
_startProgressSyncTimer();
|
|
||||||
queueOfUpload[queueIndex].isUploading = true;
|
queueOfUpload[queueIndex].isUploading = true;
|
||||||
|
queueOfUpload.refresh();
|
||||||
|
|
||||||
final task = queueOfUpload[queueIndex];
|
final task = queueOfUpload[queueIndex];
|
||||||
final result = await _rawUploadAttachment(
|
final result = await _rawUploadAttachment(
|
||||||
@ -81,13 +51,13 @@ class AttachmentUploaderController extends GetxController {
|
|||||||
null,
|
null,
|
||||||
onProgress: (value) {
|
onProgress: (value) {
|
||||||
queueOfUpload[queueIndex].progress = value;
|
queueOfUpload[queueIndex].progress = value;
|
||||||
_progressOfUpload = value;
|
queueOfUpload.refresh();
|
||||||
|
progressOfUpload.value = value;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
queueOfUpload.removeAt(queueIndex);
|
queueOfUpload.removeAt(queueIndex);
|
||||||
_stopProgressSyncTimer();
|
queueOfUpload.refresh();
|
||||||
_syncProgress();
|
|
||||||
|
|
||||||
isUploading.value = false;
|
isUploading.value = false;
|
||||||
|
|
||||||
@ -100,10 +70,9 @@ class AttachmentUploaderController extends GetxController {
|
|||||||
isUploading.value = true;
|
isUploading.value = true;
|
||||||
progressOfUpload.value = 0;
|
progressOfUpload.value = 0;
|
||||||
|
|
||||||
_startProgressSyncTimer();
|
|
||||||
|
|
||||||
for (var idx = 0; idx < queueOfUpload.length; idx++) {
|
for (var idx = 0; idx < queueOfUpload.length; idx++) {
|
||||||
queueOfUpload[idx].isUploading = true;
|
queueOfUpload[idx].isUploading = true;
|
||||||
|
queueOfUpload.refresh();
|
||||||
|
|
||||||
final task = queueOfUpload[idx];
|
final task = queueOfUpload[idx];
|
||||||
final result = await _rawUploadAttachment(
|
final result = await _rawUploadAttachment(
|
||||||
@ -113,20 +82,20 @@ class AttachmentUploaderController extends GetxController {
|
|||||||
null,
|
null,
|
||||||
onProgress: (value) {
|
onProgress: (value) {
|
||||||
queueOfUpload[idx].progress = value;
|
queueOfUpload[idx].progress = value;
|
||||||
_progressOfUpload = (idx + value) / queueOfUpload.length;
|
queueOfUpload.refresh();
|
||||||
|
progressOfUpload.value = (idx + value) / queueOfUpload.length;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
_progressOfUpload = (idx + 1) / queueOfUpload.length;
|
progressOfUpload.value = (idx + 1) / queueOfUpload.length;
|
||||||
onData(result);
|
onData(result);
|
||||||
|
|
||||||
queueOfUpload[idx].isUploading = false;
|
queueOfUpload[idx].isUploading = false;
|
||||||
queueOfUpload[idx].isCompleted = false;
|
queueOfUpload[idx].isCompleted = false;
|
||||||
|
queueOfUpload.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
queueOfUpload.clear();
|
queueOfUpload.clear();
|
||||||
_stopProgressSyncTimer();
|
queueOfUpload.refresh();
|
||||||
_syncProgress();
|
|
||||||
|
|
||||||
isUploading.value = false;
|
isUploading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ import 'package:solian/controllers/post_editor_controller.dart';
|
|||||||
import 'package:solian/exts.dart';
|
import 'package:solian/exts.dart';
|
||||||
import 'package:solian/models/post.dart';
|
import 'package:solian/models/post.dart';
|
||||||
import 'package:solian/models/realm.dart';
|
import 'package:solian/models/realm.dart';
|
||||||
import 'package:solian/providers/attachment_uploader.dart';
|
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
@ -57,14 +56,6 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
|
|||||||
if (auth.isAuthorized.isFalse) return;
|
if (auth.isAuthorized.isFalse) return;
|
||||||
if (_editorController.isEmpty) return;
|
if (_editorController.isEmpty) return;
|
||||||
|
|
||||||
final AttachmentUploaderController uploader = Get.find();
|
|
||||||
if (uploader.queueOfUpload.any(
|
|
||||||
((x) => x.usage == 'i.attachment' && x.isUploading),
|
|
||||||
)) {
|
|
||||||
context.showErrorDialog('attachmentUploadInProgress'.tr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
|
|
||||||
final client = auth.configureClient('interactive');
|
final client = auth.configureClient('interactive');
|
||||||
@ -101,16 +92,15 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _cancelAction() {
|
void cancelAction() {
|
||||||
_editorController.localClear();
|
_editorController.localClear();
|
||||||
AppRouter.instance.pop();
|
AppRouter.instance.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
Post? get _editTo => _editorController.editTo.value;
|
Post? get _editTo => _editorController.editTo.value;
|
||||||
|
|
||||||
Post? get _replyTo => _editorController.replyTo.value;
|
Post? get _replyTo => _editorController.replyTo.value;
|
||||||
|
|
||||||
Post? get _repostTo => _editorController.repostTo.value;
|
Post? get _repostTo => _editorController.repostTo.value;
|
||||||
|
Realm? get _realm => _editorController.realmZone.value;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -124,7 +114,7 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final notifyBannerActions = [
|
final notifyBannerActions = [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: _cancelAction,
|
onPressed: cancelAction,
|
||||||
child: Text('cancel'.tr),
|
child: Text('cancel'.tr),
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
abstract class ServiceFinder {
|
abstract class ServiceFinder {
|
||||||
static const bool devFlag = true;
|
static const bool devFlag = false;
|
||||||
|
|
||||||
static const String dealerUrl =
|
static const String dealerUrl =
|
||||||
devFlag ? 'http://localhost:8442' : 'https://api.sn.solsynth.dev';
|
devFlag ? 'http://localhost:8442' : 'https://api.sn.solsynth.dev';
|
||||||
|
@ -160,7 +160,6 @@ const i18nEnglish = {
|
|||||||
'attachmentAutoUpload': 'Auto Upload',
|
'attachmentAutoUpload': 'Auto Upload',
|
||||||
'attachmentUploadQueue': 'Upload Queue',
|
'attachmentUploadQueue': 'Upload Queue',
|
||||||
'attachmentUploadQueueStart': 'Start All',
|
'attachmentUploadQueueStart': 'Start All',
|
||||||
'attachmentUploadInProgress': 'There are attachments being uploaded. Please wait until all attachments have been uploaded before proceeding...',
|
|
||||||
'attachmentAttached': 'Exists Files',
|
'attachmentAttached': 'Exists Files',
|
||||||
'attachmentUploadBlocked': 'Upload blocked, there is currently a task in progress...',
|
'attachmentUploadBlocked': 'Upload blocked, there is currently a task in progress...',
|
||||||
'attachmentAdd': 'Attach attachments',
|
'attachmentAdd': 'Attach attachments',
|
||||||
|
@ -149,7 +149,6 @@ const i18nSimplifiedChinese = {
|
|||||||
'attachmentAutoUpload': '自动上传',
|
'attachmentAutoUpload': '自动上传',
|
||||||
'attachmentUploadQueue': '上传队列',
|
'attachmentUploadQueue': '上传队列',
|
||||||
'attachmentUploadQueueStart': '整队上传',
|
'attachmentUploadQueueStart': '整队上传',
|
||||||
'attachmentUploadInProgress': '有附件正在上传,请等待所有附件上传完毕后再进行操作……',
|
|
||||||
'attachmentAttached': '已附附件',
|
'attachmentAttached': '已附附件',
|
||||||
'attachmentUploadBlocked': '上传受阻,当前已有任务进行中……',
|
'attachmentUploadBlocked': '上传受阻,当前已有任务进行中……',
|
||||||
'attachmentAdd': '附加附件',
|
'attachmentAdd': '附加附件',
|
||||||
|
@ -56,10 +56,12 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
final medias = await _imagePicker.pickMultiImage();
|
final medias = await _imagePicker.pickMultiImage();
|
||||||
if (medias.isEmpty) return;
|
if (medias.isEmpty) return;
|
||||||
|
|
||||||
_enqueueTaskBatch(medias.map((x) {
|
for (final media in medias) {
|
||||||
final file = File(x.path);
|
final file = File(media.path);
|
||||||
return AttachmentUploadTask(file: file, usage: widget.usage);
|
_enqueueTask(
|
||||||
}));
|
AttachmentUploadTask(file: file, usage: widget.usage),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _pickVideoToUpload() async {
|
Future<void> _pickVideoToUpload() async {
|
||||||
@ -86,9 +88,11 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
|
|
||||||
List<File> files = result.paths.map((path) => File(path!)).toList();
|
List<File> files = result.paths.map((path) => File(path!)).toList();
|
||||||
|
|
||||||
_enqueueTaskBatch(files.map((x) {
|
for (final file in files) {
|
||||||
return AttachmentUploadTask(file: x, usage: widget.usage);
|
_enqueueTask(
|
||||||
}));
|
AttachmentUploadTask(file: file, usage: widget.usage),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _takeMediaToUpload(bool isVideo) async {
|
Future<void> _takeMediaToUpload(bool isVideo) async {
|
||||||
@ -155,11 +159,7 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
_isFirstTimeBusy = false;
|
_isFirstTimeBusy = false;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
_attachments = List.filled(
|
_attachments = List.filled(widget.initialAttachments.length, null);
|
||||||
widget.initialAttachments.length,
|
|
||||||
null,
|
|
||||||
growable: true,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
@ -239,9 +239,20 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
FutureBuilder(
|
||||||
'In queue #${index + 1}',
|
future: element.file.length(),
|
||||||
style: const TextStyle(fontSize: 12),
|
builder: (context, snapshot) {
|
||||||
|
if (!snapshot.hasData) {
|
||||||
|
return const Text(
|
||||||
|
'- Bytes',
|
||||||
|
style: TextStyle(fontSize: 12),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Text(
|
||||||
|
_formatBytes(snapshot.data!),
|
||||||
|
style: const TextStyle(fontSize: 12),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -399,13 +410,6 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _enqueueTaskBatch(Iterable<AttachmentUploadTask> tasks) {
|
|
||||||
_uploadController.enqueueTaskBatch(tasks);
|
|
||||||
if (_isAutoUpload) {
|
|
||||||
_startUploading();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startUploading() {
|
void _startUploading() {
|
||||||
_uploadController.performUploadQueue(onData: (r) {
|
_uploadController.performUploadQueue(onData: (r) {
|
||||||
widget.onAdd(r.id);
|
widget.onAdd(r.id);
|
||||||
@ -429,10 +433,11 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
child: DropTarget(
|
child: DropTarget(
|
||||||
onDragDone: (detail) async {
|
onDragDone: (detail) async {
|
||||||
if (_uploadController.isUploading.value) return;
|
if (_uploadController.isUploading.value) return;
|
||||||
_enqueueTaskBatch(detail.files.map((x) {
|
for (final file in detail.files) {
|
||||||
final file = File(x.path);
|
_enqueueTask(
|
||||||
return AttachmentUploadTask(file: file, usage: widget.usage);
|
AttachmentUploadTask(file: File(file.path), usage: widget.usage),
|
||||||
}));
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -450,12 +455,11 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if (_uploadController.isUploading.value) {
|
if (_uploadController.isUploading.value) {
|
||||||
return SizedBox(
|
return const SizedBox(
|
||||||
width: 18,
|
width: 18,
|
||||||
height: 18,
|
height: 18,
|
||||||
child: CircularProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
strokeWidth: 2.5,
|
strokeWidth: 2.5,
|
||||||
value: _uploadController.progressOfUpload.value,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,9 @@ import 'package:solian/exts.dart';
|
|||||||
import 'package:solian/models/account.dart';
|
import 'package:solian/models/account.dart';
|
||||||
import 'package:solian/models/channel.dart';
|
import 'package:solian/models/channel.dart';
|
||||||
import 'package:solian/models/event.dart';
|
import 'package:solian/models/event.dart';
|
||||||
import 'package:solian/providers/attachment_uploader.dart';
|
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/widgets/attachments/attachment_editor.dart';
|
import 'package:solian/widgets/attachments/attachment_editor.dart';
|
||||||
import 'package:solian/widgets/chat/chat_event.dart';
|
import 'package:solian/widgets/chat/chat_event.dart';
|
||||||
import 'package:badges/badges.dart' as badges;
|
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class ChatMessageInput extends StatefulWidget {
|
class ChatMessageInput extends StatefulWidget {
|
||||||
@ -82,14 +80,6 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
final prof = auth.userProfile.value!;
|
final prof = auth.userProfile.value!;
|
||||||
if (auth.isAuthorized.isFalse) return;
|
if (auth.isAuthorized.isFalse) return;
|
||||||
|
|
||||||
final AttachmentUploaderController uploader = Get.find();
|
|
||||||
if (uploader.queueOfUpload.any(
|
|
||||||
((x) => x.usage == 'm.attachment' && x.isUploading),
|
|
||||||
)) {
|
|
||||||
context.showErrorDialog('attachmentUploadInProgress'.tr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Response resp;
|
Response resp;
|
||||||
|
|
||||||
final mentionedUserNames = _findMentionedUsers(_textController.text);
|
final mentionedUserNames = _findMentionedUsers(_textController.text);
|
||||||
@ -269,18 +259,7 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: badges.Badge(
|
icon: const Icon(Icons.attach_file),
|
||||||
badgeContent: Text(
|
|
||||||
_attachments.length.toString(),
|
|
||||||
style: const TextStyle(color: Colors.white),
|
|
||||||
),
|
|
||||||
showBadge: _attachments.isNotEmpty,
|
|
||||||
position: badges.BadgePosition.topEnd(
|
|
||||||
top: -12,
|
|
||||||
end: -8,
|
|
||||||
),
|
|
||||||
child: const Icon(Icons.file_present_rounded),
|
|
||||||
),
|
|
||||||
color: Colors.teal,
|
color: Colors.teal,
|
||||||
onPressed: () => _editAttachments(),
|
onPressed: () => _editAttachments(),
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user