Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
273 changes: 88 additions & 185 deletions lib/src/api/threads.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:interstellar/src/controller/server.dart';
import 'package:interstellar/src/models/post.dart';
import 'package:interstellar/src/utils/models.dart';
import 'package:interstellar/src/utils/utils.dart';
import 'package:mime/mime.dart';

const Map<FeedSort, String> lemmyFeedSortMap = {
FeedSort.active: 'Active',
Expand Down Expand Up @@ -371,210 +372,102 @@ class APIThreads {
}
}

Future<PostModel> createArticle(
int communityId, {
Future<PostModel> create({
required int communityId,
required String title,
required bool isOc,
required String body,
required String lang,
required bool isAdult,
required List<String> tags,
String? body,
String? url,
XFile? image,
String? alt,
bool isAdult = false,
bool isOc = false,
List<String> tags = const [],
}) async {
switch (client.software) {
case ServerSoftware.mbin:
final path = '/magazine/$communityId/article';

final response = await client.post(
path,
body: {
'title': title,
'tags': tags,
'isOc': isOc,
'body': body,
'lang': lang,
'isAdult': isAdult,
},
);

return PostModel.fromMbinEntry(response.bodyJson);

case ServerSoftware.lemmy:
const path = '/post';
final response = await client.post(
path,
body: {
'name': title,
'community_id': communityId,
'body': body,
'nsfw': isAdult,
'language_id': await client.languageIdFromCode(lang),
},
);

return PostModel.fromLemmy(
response.bodyJson,
langCodeIdPairs: await client.languageCodeIdPairs(),
);

case ServerSoftware.piefed:
const path = '/post';
final response = await client.post(
path,
body: {
'title': title,
'community_id': communityId,
'body': body,
'nsfw': isAdult,
'language_id': await client.languageIdFromCode(lang),
},
);

return PostModel.fromPiefed(
response.bodyJson,
langCodeIdPairs: await client.languageCodeIdPairs(),
);
}
}

Future<PostModel> createLink(
int communityId, {
required String title,
required String url,
required bool isOc,
required String body,
required String lang,
required bool isAdult,
required List<String> tags,
}) async {
switch (client.software) {
case ServerSoftware.mbin:
final path = '/magazine/$communityId/link';

final response = await client.post(
path,
body: {
'title': title,
'url': url,
'tags': tags,
'isOc': isOc,
'body': body,
'lang': lang,
'isAdult': isAdult,
},
);

return PostModel.fromMbinEntry(response.bodyJson);

case ServerSoftware.lemmy:
const path = '/post';
final response = await client.post(
path,
body: {
'name': title,
'community_id': communityId,
'url': url,
'body': body,
'nsfw': isAdult,
'language_id': await client.languageIdFromCode(lang),
},
assert(
body?.isNotEmpty != null || url?.isNotEmpty != null || image != null,
'Post needs either a body an url or an image.',
);
tags = tags.where((tag) => tag.isNotEmpty).toList();

return PostModel.fromLemmy(
response.bodyJson,
langCodeIdPairs: await client.languageCodeIdPairs(),
);

case ServerSoftware.piefed:
const path = '/post';
final response = await client.post(
path,
body: {
'title': title,
'community_id': communityId,
'url': url,
'body': body,
'nsfw': isAdult,
'language_id': await client.languageIdFromCode(lang),
},
);

return PostModel.fromPiefed(
response.bodyJson,
langCodeIdPairs: await client.languageCodeIdPairs(),
);
}
}

Future<PostModel> createImage(
int communityId, {
required String title,
required XFile image,
required String alt,
required bool isOc,
required String body,
required String lang,
required bool isAdult,
required List<String> tags,
}) async {
switch (client.software) {
case ServerSoftware.mbin:
final path = '/magazine/$communityId/image';
final path = '/magazine/$communityId/entries';

final request = http.MultipartRequest(
'POST',
Uri.https(client.domain, client.software.apiPathPrefix + path),
);
final multipartFile = http.MultipartFile.fromBytes(
'uploadImage',
await image.readAsBytes(),
filename: image.name,
contentType: MediaType.parse(image.mimeType!),
);
request.files.add(multipartFile);

request.fields['title'] = title;
for (var i = 0; i < tags.length; i++) {
if (url != null) {
request.fields['url'] = url;
}
for (var i = 0; i < tags.length; ++i) {
request.fields['tags[$i]'] = tags[i];
}
request.fields['isOc'] = isOc.toString();
request.fields['body'] = body;
if (body != null && body.isNotEmpty) {
request.fields['body'] = body;
}
request.fields['lang'] = lang;
request.fields['isAdult'] = isAdult.toString();
request.fields['alt'] = alt;
if (alt != null) {
request.fields['alt'] = alt;
}
if (image != null) {
final file = http.MultipartFile.fromBytes(
'uploadImage',
await image.readAsBytes(),
filename: image.name,
contentType: MediaType.parse(
image.mimeType ?? lookupMimeType(image.path)!,
),
);
request.files.add(file);
}

final response = await client.sendRequest(request);

return PostModel.fromMbinEntry(response.bodyJson);

case ServerSoftware.lemmy:
const pictrsPath = '/pictrs/image';
if (image != null) {
const uploadPath = '/pictrs/image';

final uploadRequest = http.MultipartRequest(
'POST',
Uri.https(client.domain, pictrsPath),
);
final multipartFile = http.MultipartFile.fromBytes(
'images[]',
await image.readAsBytes(),
filename: image.name,
contentType: MediaType.parse(image.mimeType!),
);
uploadRequest.files.add(multipartFile);
final pictrsResponse = await client.sendRequest(uploadRequest);
final uploadRequest = http.MultipartRequest(
'POST',
Uri.https(client.domain, uploadPath),
);
final multipartFile = http.MultipartFile.fromBytes(
'images[]',
await image.readAsBytes(),
filename: image.name,
contentType: MediaType.parse(
image.mimeType ?? lookupMimeType(image.path)!,
),
);
uploadRequest.files.add(multipartFile);
final pictrsResponse = await client.sendRequest(uploadRequest);

final imageName =
((pictrsResponse.bodyJson['files']! as List<Object?>).first!
as JsonMap)['file']
as String?;
final imageName =
((pictrsResponse.bodyJson['files']! as List<Object?>).first!
as JsonMap)['file']
as String?;

url = 'https://${client.domain}/pictrs/image/$imageName';
}

const path = '/post';
final response = await client.post(
path,
body: {
'name': title,
'community_id': communityId,
'url': 'https://${client.domain}/pictrs/image/$imageName',
'url': url,
'body': body,
'nsfw': isAdult,
'alt_text': nullIfEmpty(alt),
'alt_text': alt,
'language_id': await client.languageIdFromCode(lang),
},
);
Expand All @@ -585,33 +478,43 @@ class APIThreads {
);

case ServerSoftware.piefed:
const uploadPath = '/upload/image';
if (image != null) {
const uploadPath = '/upload/image';

final uploadRequest = http.MultipartRequest(
'POST',
Uri.https(
client.domain,
client.software.apiPathPrefix + uploadPath,
),
);
final multipartFile = http.MultipartFile.fromBytes(
'file',
await image.readAsBytes(),
filename: image.name,
contentType: MediaType.parse(
image.mimeType ?? lookupMimeType(image.path)!,
),
);
uploadRequest.files.add(multipartFile);

final uploadRequest = http.MultipartRequest(
'POST',
Uri.https(client.domain, client.software.apiPathPrefix + uploadPath),
);
final multipartFile = http.MultipartFile.fromBytes(
'file',
await image.readAsBytes(),
filename: image.name,
contentType: MediaType.parse(image.mimeType!),
);
uploadRequest.files.add(multipartFile);
final uploadResponse = await client.sendRequest(uploadRequest);

final uploadResponse = await client.sendRequest(uploadRequest);
final imageUrl = uploadResponse.bodyJson['url'] as String?;

final imageUrl = uploadResponse.bodyJson['url'] as String?;
url = imageUrl;
}

const path = '/post';
final response = await client.post(
path,
body: {
'title': title,
'community_id': communityId,
'url': imageUrl,
'url': url,
'body': body,
'nsfw': isAdult,
'alt_text': alt,
'language_id': await client.languageIdFromCode(lang),
},
);
Expand Down
16 changes: 8 additions & 8 deletions lib/src/screens/feed/create_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,8 @@ class _CreateScreenState extends State<CreateScreen> {
: () async {
final tags = _tagsTextController.text.split(' ');

final post = await ac.api.threads.createArticle(
_community!.id,
final post = await ac.api.threads.create(
communityId: _community!.id,
title: _titleTextController.text,
isOc: _isOc,
body: _bodyTextController.text,
Expand Down Expand Up @@ -444,11 +444,11 @@ class _CreateScreenState extends State<CreateScreen> {
: () async {
final tags = _tagsTextController.text.split(' ');

final post = await ac.api.threads.createImage(
_community!.id,
final post = await ac.api.threads.create(
communityId: _community!.id,
title: _titleTextController.text,
image: _imageFile!,
alt: _altText ?? '',
image: _imageFile,
alt: _altText,
isOc: _isOc,
body: _bodyTextController.text,
lang: _lang,
Expand Down Expand Up @@ -486,8 +486,8 @@ class _CreateScreenState extends State<CreateScreen> {
: () async {
final tags = _tagsTextController.text.split(' ');

final post = await ac.api.threads.createLink(
_community!.id,
final post = await ac.api.threads.create(
communityId: _community!.id,
title: _titleTextController.text,
url: _urlTextController.text,
isOc: _isOc,
Expand Down