emoji in display names and post bodies

This commit is contained in:
zoe 2022-10-01 15:51:02 +02:00
parent 0caefbe4b9
commit b76e53def1
8 changed files with 65 additions and 11 deletions

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:loris/business_logic/emoji/emoji.dart';
import 'package:loris/business_logic/timeline/timeline.dart'; import 'package:loris/business_logic/timeline/timeline.dart';
import 'package:loris/global.dart' as global; import 'package:loris/global.dart' as global;
@ -19,6 +20,7 @@ class AccountModel {
final bool? bot; final bool? bot;
final bool? suspended; final bool? suspended;
final String identity; final String identity;
final List<Emoji> emojis;
AccountModel({ AccountModel({
required this.identity, required this.identity,
@ -34,9 +36,17 @@ class AccountModel {
required this.avatar, required this.avatar,
required this.url, required this.url,
required this.id, required this.id,
required this.emojis,
}); });
factory AccountModel.fromJson(Map<String, dynamic> json, String identity) { factory AccountModel.fromJson(Map<String, dynamic> json, String identity) {
List<Emoji> emoji = [];
if (json["emojis"] != null) {
for (var e in json["emojis"]) {
emoji.add(Emoji.fromJson(e));
}
}
return AccountModel( return AccountModel(
identity: identity, identity: identity,
id: json["id"], id: json["id"],
@ -51,6 +61,7 @@ class AccountModel {
bot: json["bot"], bot: json["bot"],
fields: json["fields"], fields: json["fields"],
suspended: json["suspended"], suspended: json["suspended"],
emojis: emoji,
); );
} }
} }

View File

@ -0,0 +1,17 @@
class Emoji {
final String shortcode;
final String url;
Emoji({required this.shortcode, required this.url});
factory Emoji.fromJson(Map<String, dynamic> json) {
return Emoji(
shortcode: json["shortcode"],
url: json["url"],
);
}
}
String insertEmojiInMd(String input, Emoji emoji) {
return input.replaceAll(
":${emoji.shortcode}:", "![${emoji.shortcode}](${emoji.url})");
}

View File

@ -49,8 +49,6 @@ Future<RelationshipModel?> handleFollowRequest(AccountModel account,
); );
final result = await http.post(uri, headers: headers); final result = await http.post(uri, headers: headers);
print(uri);
print(result.body);
if (result.statusCode != 200) { if (result.statusCode != 200) {
return null; return null;
} }

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:localization/localization.dart'; import 'package:localization/localization.dart';
import 'package:loris/business_logic/account/account.dart'; import 'package:loris/business_logic/account/account.dart';
import 'package:loris/business_logic/emoji/emoji.dart';
import 'package:loris/business_logic/posting/mentions.dart'; import 'package:loris/business_logic/posting/mentions.dart';
import 'package:loris/business_logic/timeline/media.dart'; import 'package:loris/business_logic/timeline/media.dart';
import '../../global.dart' as global; import '../../global.dart' as global;
@ -89,6 +90,7 @@ class PostModel implements Comparable {
late List<MentionModel> mentions = []; late List<MentionModel> mentions = [];
// exists if post is a reblog // exists if post is a reblog
late String originalId; late String originalId;
late List<Emoji> emojis = [];
PostModel.fromJson(Map<String, dynamic> json, this.identity) { PostModel.fromJson(Map<String, dynamic> json, this.identity) {
id = json["id"] as String; id = json["id"] as String;
@ -125,6 +127,11 @@ class PostModel implements Comparable {
for (var element in jsonMentionList) { for (var element in jsonMentionList) {
mentions.add(MentionModel.fromJson(element)); mentions.add(MentionModel.fromJson(element));
} }
List<dynamic>? jsonEmojiList = json["emojis"];
if (jsonEmojiList != null) {}
for (var element in jsonEmojiList!) {
emojis.add(Emoji.fromJson(element));
}
} }
// get instance of account that received this post // get instance of account that received this post

View File

@ -2,7 +2,6 @@ import 'dart:convert';
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:localization/localization.dart'; import 'package:localization/localization.dart';
import 'package:loris/business_logic/fileupload/fileupload.dart'; import 'package:loris/business_logic/fileupload/fileupload.dart';
import 'package:loris/business_logic/instance/instance.dart'; import 'package:loris/business_logic/instance/instance.dart';

View File

@ -1,5 +1,3 @@
import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:localization/localization.dart'; import 'package:localization/localization.dart';
import 'package:loris/business_logic/account/account.dart'; import 'package:loris/business_logic/account/account.dart';

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:localization/localization.dart'; import 'package:localization/localization.dart';
import 'package:loris/business_logic/account/account.dart'; import 'package:loris/business_logic/account/account.dart';
import 'package:loris/business_logic/emoji/emoji.dart';
import 'package:loris/business_logic/timeline/media.dart'; import 'package:loris/business_logic/timeline/media.dart';
import 'package:loris/dialogues/full_post_view.dart'; import 'package:loris/dialogues/full_post_view.dart';
import 'package:loris/dialogues/makepost.dart'; import 'package:loris/dialogues/makepost.dart';
@ -88,6 +90,11 @@ class DisplayName extends StatelessWidget {
} else { } else {
usernameStyle = Theme.of(context).textTheme.displaySmall; usernameStyle = Theme.of(context).textTheme.displaySmall;
} }
String dname = account.displayName;
for (var emoji in account.emojis) {
dname = insertEmojiInMd(dname, emoji);
}
return InkWell( return InkWell(
borderRadius: const BorderRadius.all(themes.defaultRadius), borderRadius: const BorderRadius.all(themes.defaultRadius),
onTap: !openInBrowser onTap: !openInBrowser
@ -110,12 +117,13 @@ class DisplayName extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SelectableText( MarkdownBody(
minLines: 1, data: dname,
maxLines: 2, selectable: true,
account.displayName, imageBuilder: (uri, title, alt) => Image.network(
style: usernameStyle, uri.toString(),
), height: usernameStyle?.fontSize),
styleSheet: MarkdownStyleSheet(p: usernameStyle)),
SelectableText( SelectableText(
account.acct, account.acct,
style: Theme.of(context).textTheme.bodySmall, style: Theme.of(context).textTheme.bodySmall,
@ -295,6 +303,7 @@ class _PostBodyState extends State<PostBody> {
PostTextRenderer( PostTextRenderer(
input: widget.content, input: widget.content,
identityName: widget.model.identity, identityName: widget.model.identity,
emoji: widget.model.emojis,
), ),
MediaAttachments(models: widget.media), MediaAttachments(models: widget.media),
], ],

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:html2md/html2md.dart' as html2md; import 'package:html2md/html2md.dart' as html2md;
import 'package:loris/business_logic/emoji/emoji.dart';
import 'package:loris/dialogues/profile_view.dart'; import 'package:loris/dialogues/profile_view.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../business_logic/account/account.dart' as account; import '../business_logic/account/account.dart' as account;
@ -9,10 +10,12 @@ class PostTextRenderer extends StatelessWidget {
const PostTextRenderer({ const PostTextRenderer({
required this.identityName, required this.identityName,
required this.input, required this.input,
this.emoji = const [],
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
final String input; final String input;
final String identityName; final String identityName;
final List<Emoji> emoji;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -43,9 +46,19 @@ class PostTextRenderer extends StatelessWidget {
); );
String s = html2md.convert(input); String s = html2md.convert(input);
for (var e in emoji) {
s = insertEmojiInMd(s, e);
}
return MarkdownBody( return MarkdownBody(
imageBuilder: (uri, title, alt) {
return Image.network(
"${uri.scheme}://${uri.host}${uri.path}",
height: Theme.of(context).textTheme.bodyMedium?.fontSize,
);
},
onTapLink: ((text, href, title) async { onTapLink: ((text, href, title) async {
if (href != null) { if (href != null) {
// see if this is an account and in that case search for it
if (text.startsWith("@")) { if (text.startsWith("@")) {
final result = await account.searchModel(identityName, href); final result = await account.searchModel(identityName, href);
if (result.keys.first == 200) { if (result.keys.first == 200) {
@ -56,6 +69,8 @@ class PostTextRenderer extends StatelessWidget {
return; return;
} }
} }
// if this is not an account or the account couldn't be found
// then just open it in the default browser
launchUrl(Uri.parse(href)); launchUrl(Uri.parse(href));
} }
}), }),