basic attachments are live
This commit is contained in:
parent
8aa49dc2ea
commit
d0235cac5d
|
@ -1,7 +1,10 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:loris/global.dart' as global;
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class FileUpload {
|
||||
final MultipartFile data;
|
||||
String description;
|
||||
final String path;
|
||||
|
||||
|
@ -10,18 +13,45 @@ class FileUpload {
|
|||
Map<String, String> ids = {};
|
||||
|
||||
FileUpload({
|
||||
required this.data,
|
||||
required this.description,
|
||||
required this.path,
|
||||
this.ids = const {},
|
||||
});
|
||||
|
||||
static Future<FileUpload> fromPath(String path, String description) async {
|
||||
final data = await MultipartFile.fromPath("file", path);
|
||||
return FileUpload(
|
||||
data: data,
|
||||
description: description,
|
||||
path: path,
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
sends a media attachments and returns the http status code
|
||||
if the status code is 200, the String is the media attachments id,
|
||||
otherwise it's the error response
|
||||
*/
|
||||
Future<MapEntry<int, String>> upload(String identityName) async {
|
||||
final identity = global.settings!.identities[identityName]!;
|
||||
final headers = {
|
||||
...global.defaultHeaders,
|
||||
...identity.getAuthHeaders(),
|
||||
};
|
||||
final uri =
|
||||
Uri(scheme: "https", host: identity.instanceUrl, path: "/api/v2/media");
|
||||
final request = MultipartRequest(
|
||||
"POST",
|
||||
uri,
|
||||
);
|
||||
request.headers.addAll(headers);
|
||||
request.files.add(await MultipartFile.fromPath(
|
||||
"file",
|
||||
path,
|
||||
));
|
||||
request.fields.addAll({"description": description});
|
||||
final response = await http.Response.fromStream(await request.send());
|
||||
if (response.statusCode != 200 && response.statusCode != 202) {
|
||||
return MapEntry(response.statusCode, jsonDecode(response.body)["error"]);
|
||||
}
|
||||
return MapEntry(response.statusCode, jsonDecode(response.body)["id"]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,17 +11,19 @@ class MakePostModel {
|
|||
final Visibility visibility;
|
||||
final String? scheduledAt;
|
||||
final String? inReplyToId;
|
||||
List<String> mediaIds;
|
||||
|
||||
MakePostModel({
|
||||
required this.identity,
|
||||
required this.status,
|
||||
required this.spoilerText,
|
||||
required this.visibility,
|
||||
required this.mediaIds,
|
||||
this.scheduledAt,
|
||||
this.inReplyToId,
|
||||
});
|
||||
|
||||
Future<int> sendPost() async {
|
||||
Future<http.Response> sendPost() async {
|
||||
final headers = global.settings!.identities[identity]!.getAuthHeaders();
|
||||
headers.addAll(global.defaultHeaders);
|
||||
|
||||
|
@ -29,6 +31,7 @@ class MakePostModel {
|
|||
"status": status,
|
||||
"sensitive": false,
|
||||
"visibility": visibility.queryParam,
|
||||
"media_ids": mediaIds,
|
||||
};
|
||||
|
||||
if (inReplyToId != null) {
|
||||
|
@ -55,6 +58,6 @@ class MakePostModel {
|
|||
headers: headers,
|
||||
body: jsonEncode(params),
|
||||
);
|
||||
return response.statusCode;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:localization/localization.dart';
|
||||
import 'package:loris/business_logic/fileupload/fileupload.dart';
|
||||
|
@ -9,6 +11,7 @@ import '../partials/post.dart';
|
|||
import 'package:loris/global.dart' as global;
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:mime/mime.dart';
|
||||
import 'package:universal_io/io.dart' as io;
|
||||
|
||||
class MakePost extends StatefulWidget {
|
||||
const MakePost({Key? key, this.inReplyTo}) : super(key: key);
|
||||
|
@ -24,6 +27,8 @@ class _MakePostState extends State<MakePost> {
|
|||
InstanceInformation? instanceInfo;
|
||||
String text = "";
|
||||
String spoilerText = "";
|
||||
String? status;
|
||||
bool sending = false;
|
||||
// tracks fileuploads and their ids on servers
|
||||
// if the id is null the file has not been uploaded yet
|
||||
List<FileUpload> files = [];
|
||||
|
@ -201,7 +206,7 @@ class _MakePostState extends State<MakePost> {
|
|||
// then parse them
|
||||
for (var path in result.paths) {
|
||||
if (path != null && mounted) {
|
||||
print(path);
|
||||
if (await io.Directory(path).exists()) break;
|
||||
final FileUpload f = await FileUpload.fromPath(path, "");
|
||||
setState(() {
|
||||
files.add(f);
|
||||
|
@ -212,7 +217,7 @@ class _MakePostState extends State<MakePost> {
|
|||
},
|
||||
icon: const Icon(Icons.attachment),
|
||||
label: Text(
|
||||
"${"add-file".i18n()}${instanceInfo == null ? "(${"loading...".i18n()})" : " (${instanceInfo!.configuration.statusconfig.maxMediaAttachments - files.length} ${"remaining".i18n()})"}")),
|
||||
"${"add-files".i18n()}${instanceInfo == null ? "(${"loading...".i18n()})" : " (${instanceInfo!.configuration.statusconfig.maxMediaAttachments - files.length} ${"remaining".i18n()})"}")),
|
||||
DropdownButtonHideUnderline(
|
||||
child: DropdownButton<String>(
|
||||
alignment: Alignment.center,
|
||||
|
@ -234,7 +239,38 @@ class _MakePostState extends State<MakePost> {
|
|||
tooManyAttachments())
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
sending = true;
|
||||
status = "sending...".i18n();
|
||||
});
|
||||
|
||||
// upload the media attachments
|
||||
List<String> mediaIds = [];
|
||||
for (var file in files) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
status =
|
||||
"${"sending-file".i18n()}${mediaIds.length + 1}/${files.length}";
|
||||
});
|
||||
}
|
||||
final response = await file.upload(accountid);
|
||||
if (response.key == 200 || response.key == 202) {
|
||||
mediaIds.add(response.value);
|
||||
break;
|
||||
}
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
status = response.value;
|
||||
sending = false;
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
print(mediaIds);
|
||||
|
||||
// send the final post
|
||||
final model = MakePostModel(
|
||||
mediaIds: mediaIds,
|
||||
spoilerText: spoilerText.trim(),
|
||||
identity: accountid,
|
||||
status: text,
|
||||
|
@ -244,8 +280,15 @@ class _MakePostState extends State<MakePost> {
|
|||
: identitiesAvailable[accountid]!,
|
||||
);
|
||||
final result = await model.sendPost();
|
||||
if (result == 200) {
|
||||
Navigator.of(context).pop();
|
||||
if (mounted) {
|
||||
if (result.statusCode == 200) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
setState(() {
|
||||
sending = false;
|
||||
status =
|
||||
"${"failed-to-send".i18n()}: ${jsonDecode(result.body)["error"].toString()}";
|
||||
});
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.send),
|
||||
|
@ -351,10 +394,18 @@ class _MakePostState extends State<MakePost> {
|
|||
return SimpleDialog(
|
||||
alignment: Alignment.center,
|
||||
contentPadding: const EdgeInsets.all(24),
|
||||
title: SelectableText(
|
||||
textAlign: TextAlign.center,
|
||||
widget.inReplyTo == null ? "make-post".i18n() : "make-reply".i18n(),
|
||||
style: Theme.of(context).textTheme.displayMedium),
|
||||
title: Column(
|
||||
children: [
|
||||
SelectableText(
|
||||
textAlign: TextAlign.center,
|
||||
widget.inReplyTo == null
|
||||
? "make-post".i18n()
|
||||
: "make-reply".i18n(),
|
||||
style: Theme.of(context).textTheme.displayMedium),
|
||||
if (status != null) SelectableText(status!),
|
||||
if (sending) const LinearProgressIndicator(),
|
||||
],
|
||||
),
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
child: Container(
|
||||
|
@ -391,8 +442,7 @@ class FileUploadDisplay extends StatelessWidget {
|
|||
children: [
|
||||
const Icon(Icons.attachment, size: 32),
|
||||
Expanded(
|
||||
child: SelectableText(
|
||||
"${file.path} (${(file.data.length / 1024).toStringAsFixed(2)}kb)",
|
||||
child: SelectableText(file.path,
|
||||
style: Theme.of(context).textTheme.displaySmall),
|
||||
),
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue