fluffychat merge - resolve conflicts

This commit is contained in:
ggurdin 2024-09-04 15:53:37 -04:00
commit 6a83249236
No known key found for this signature in database
GPG key ID: A01CB41737CBB478
13 changed files with 602 additions and 70 deletions

View file

@ -2772,5 +2772,22 @@
"sendRoomNotifications": "إرسال إشعارات @room",
"@sendRoomNotifications": {},
"changeTheDescriptionOfTheGroup": "تغيير وصف الدردشة",
"@changeTheDescriptionOfTheGroup": {}
"@changeTheDescriptionOfTheGroup": {},
"invitedBy": "📩 تمت دعوته من قبل {user}",
"@invitedBy": {
"placeholders": {
"user": {}
}
},
"chatPermissionsDescription": "‪حدد مستوى الصلاحية الضروري لإجراءات معينة في هذه الدردشة. عادة ما تمثل مستويات الصلاحية 0 و 50 و 100 المستخدمين والمشرفين ولكن أي تدرج ممكن.",
"@chatPermissionsDescription": {},
"changelog": "سجل التغييرات",
"@changelog": {},
"updateInstalled": "تم تثبيت🎉 تحديث {version}!",
"@updateInstalled": {
"type": "text",
"placeholders": {
"version": {}
}
}
}

View file

@ -558,7 +558,7 @@
"type": "text",
"placeholders": {}
},
"defaultPermissionLevel": "Standardberechtigungsstufe",
"defaultPermissionLevel": "Standardberechtigungsstufe für neue Benutzer",
"@defaultPermissionLevel": {
"type": "text",
"placeholders": {}
@ -2737,5 +2737,57 @@
"chats": {},
"participants": {}
}
}
},
"changeGeneralChatSettings": "Allgemeine Chat-Einstellungen ändern",
"@changeGeneralChatSettings": {},
"userLevel": "{level} - Benutzer",
"@userLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"moderatorLevel": "{level} - Moderator",
"@moderatorLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"changeTheChatPermissions": "Ändere die Chat-Berechtigungen",
"@changeTheChatPermissions": {},
"changeTheVisibilityOfChatHistory": "Wechsele die Sichtbarkeit der Chat-Historie",
"@changeTheVisibilityOfChatHistory": {},
"chatPermissionsDescription": "Definieren Sie, welche Befugnisstufe für bestimmte Aktionen in diesem Chat erforderlich ist. Die Befugnisstufen 0, 50 und 100 stehen üblicherweise für Benutzer, Moderatoren und Admins, aber jede Abstufung ist möglich.",
"@chatPermissionsDescription": {},
"invitedBy": "📩 Eingeladen von {user}",
"@invitedBy": {
"placeholders": {
"user": {}
}
},
"adminLevel": "{level} - Administrator",
"@adminLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"inviteOtherUsers": "Lade andere Benutzer in diesen Chat ein",
"@inviteOtherUsers": {},
"changeTheCanonicalRoomAlias": "Ändern der Hauptadresse für den öffentlichen Chat",
"@changeTheCanonicalRoomAlias": {},
"sendRoomNotifications": "Senden Sie eine @room-Benachrichtigung",
"@sendRoomNotifications": {},
"changeTheDescriptionOfTheGroup": "Ändern Sie die Beschreibung des Chats",
"@changeTheDescriptionOfTheGroup": {},
"updateInstalled": "🎉 Update {version} installiert!",
"@updateInstalled": {
"type": "text",
"placeholders": {
"version": {}
}
},
"changelog": "Änderungsprotokoll",
"@changelog": {}
}

View file

@ -2772,5 +2772,22 @@
"changeTheChatPermissions": "Muuda vestluse õigusi",
"@changeTheChatPermissions": {},
"changeTheDescriptionOfTheGroup": "Muuda vestluse kirjeldust",
"@changeTheDescriptionOfTheGroup": {}
"@changeTheDescriptionOfTheGroup": {},
"chatPermissionsDescription": "Määra erinevatele kasutajatele selles vestluses vajalikud õigused. Tüüpiliselt on need 0, 50 ja 100 (vastavalt kasutajad, moderaatorid ja peakasutajad), kuid igasugused vahepealsed variatsioonid on ka võimalikud.",
"@chatPermissionsDescription": {},
"invitedBy": "📩 Kutsujaks {user}",
"@invitedBy": {
"placeholders": {
"user": {}
}
},
"updateInstalled": "🎉 Versiooniuuendus {version} on paigaldatud!",
"@updateInstalled": {
"type": "text",
"placeholders": {
"version": {}
}
},
"changelog": "Muudatuste logi",
"@changelog": {}
}

View file

@ -2679,7 +2679,7 @@
"@noPublicLinkHasBeenCreatedYet": {},
"userRole": "Erabiltzailearen rola",
"@userRole": {},
"minimumPowerLevel": "{level} da gutxieneko botere maila.",
"minimumPowerLevel": "{level} da gutxieneko botere-maila.",
"@minimumPowerLevel": {
"type": "text",
"placeholders": {
@ -2772,5 +2772,22 @@
"changeTheVisibilityOfChatHistory": "Aldatu txataren historiaren ikusgaitasuna",
"@changeTheVisibilityOfChatHistory": {},
"changeTheCanonicalRoomAlias": "Aldatu txataren helbide publiko nagusia",
"@changeTheCanonicalRoomAlias": {}
"@changeTheCanonicalRoomAlias": {},
"invitedBy": "📩 {user}(e)k gonbidatua",
"@invitedBy": {
"placeholders": {
"user": {}
}
},
"updateInstalled": "🎉 {version} bertsioa instalatu da!",
"@updateInstalled": {
"type": "text",
"placeholders": {
"version": {}
}
},
"changelog": "Aldaketak",
"@changelog": {},
"chatPermissionsDescription": "Definitu zer botere-maila behar den txat honetako ekintza jakinetarako. 0, 50 eta 100 botere-mailek erabiltzaileak, moderatzaileak eta administratzaileak ordezkatzen dituzte, baina edozein graduazio posible da.",
"@chatPermissionsDescription": {}
}

View file

@ -2772,5 +2772,22 @@
"sendRoomNotifications": "Enviar notificacións a @room",
"@sendRoomNotifications": {},
"changeTheDescriptionOfTheGroup": "Cambiar a descrición do chat",
"@changeTheDescriptionOfTheGroup": {}
"@changeTheDescriptionOfTheGroup": {},
"invitedBy": "📩 Convidada por {user}",
"@invitedBy": {
"placeholders": {
"user": {}
}
},
"changelog": "Novidades na versión",
"@changelog": {},
"chatPermissionsDescription": "Define que nivel de permisos son necesarios para realizar certas accións neste chat. Os niveis de permiso 0, 50 e 100 normalmente representan, usuarias, moderadoras e administradoras, pero son posibles outras escalas.",
"@chatPermissionsDescription": {},
"updateInstalled": "🎉 Instalouse a actualización a {version}!",
"@updateInstalled": {
"type": "text",
"placeholders": {
"version": {}
}
}
}

View file

@ -562,7 +562,7 @@
"type": "text",
"placeholders": {}
},
"defaultPermissionLevel": "Standaardmachtigingsniveau",
"defaultPermissionLevel": "Standaard machtigingsniveau voor nieuwe personen",
"@defaultPermissionLevel": {
"type": "text",
"placeholders": {}
@ -2313,7 +2313,7 @@
"@replace": {},
"report": "rapporteer",
"@report": {},
"reportErrorDescription": "Oh nee. Er is iets misgegaan. Probeer het later nog eens. Als je wilt, kun je de bug rapporteren aan de ontwikkelaars.",
"reportErrorDescription": "😭 Oh nee. Er is iets misgegaan. Probeer het later nog eens. Als je wilt, kun je de bug rapporteren aan de ontwikkelaars.",
"@reportErrorDescription": {},
"sendTypingNotifications": "Typemeldingen verzenden",
"@sendTypingNotifications": {},
@ -2349,7 +2349,7 @@
"@inviteContactToGroupQuestion": {},
"optionalRedactReason": "(Optioneel) Reden voor aanpassing van dit bericht...",
"@optionalRedactReason": {},
"addChatDescription": "Voeg een chatbeschrijving toe",
"addChatDescription": "Voeg een chatbeschrijving toe...",
"@addChatDescription": {},
"invalidServerName": "Foute servernaam",
"@invalidServerName": {},
@ -2404,7 +2404,7 @@
"@makeAdminDescription": {},
"archiveRoomDescription": "De chat zal naar het archief worden verplaatst. Andere personen zullen in staat zijn te zien dat je de chat hebt verlaten.",
"@archiveRoomDescription": {},
"hasKnocked": "{user} heeft geklopt",
"hasKnocked": "🚪 {user} heeft geklopt",
"@hasKnocked": {
"placeholders": {
"user": {}
@ -2421,5 +2421,175 @@
"alwaysUse24HourFormat": "true",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
}
},
"joinSpace": "Deelname aan space",
"@joinSpace": {},
"block": "Blokkeren",
"@block": {},
"blockedUsers": "Geblokkeerde personen",
"@blockedUsers": {},
"presenceStyle": "Aanwezigheid:",
"@presenceStyle": {
"type": "text",
"placeholders": {}
},
"searchChatsRooms": "Zoek naar #chats, @personen...",
"@searchChatsRooms": {},
"swipeRightToLeftToReply": "Veeg van rechts naar links om te reageren",
"@swipeRightToLeftToReply": {},
"calls": "Gesprekken",
"@calls": {},
"customEmojisAndStickers": "Aangepaste emojis and stickers",
"@customEmojisAndStickers": {},
"accessAndVisibilityDescription": "Wie mag meedoen in deze chat en hoe de chat ontdekt kan worden.",
"@accessAndVisibilityDescription": {},
"customEmojisAndStickersBody": "Voeg toe of deel aangepaste emojis of stickers die gebruikt kunnen worden in elke chat.",
"@customEmojisAndStickersBody": {},
"hideRedactedMessages": "Verberg verwijderde berichten",
"@hideRedactedMessages": {},
"hideRedactedMessagesBody": "Als iemand een bericht verwijdert, is dit bericht niet meer zichtbaar in de chat.",
"@hideRedactedMessagesBody": {},
"hideInvalidOrUnknownMessageFormats": "Verberg ongeldige of onbekende berichtformaten",
"@hideInvalidOrUnknownMessageFormats": {},
"passwordRecoverySettings": "Wachtwoord herstel instellingen",
"@passwordRecoverySettings": {},
"youInvitedToBy": "📩 Je bent uitgenodigd via een link voor:\n{alias}",
"@youInvitedToBy": {
"placeholders": {
"alias": {}
}
},
"knock": "Kloppen",
"@knock": {},
"overview": "Overzicht",
"@overview": {},
"hidePresences": "Verberg Status Lijst?",
"@hidePresences": {},
"noOneCanJoin": "Niemand kan deelnemen",
"@noOneCanJoin": {},
"yourGlobalUserIdIs": "Je globale gebruikers-ID is: ",
"@yourGlobalUserIdIs": {},
"appLockDescription": "Vergendel de app wanneer het niet gebruikt wordt met een pincode",
"@appLockDescription": {},
"globalChatId": "Globale chat ID",
"@globalChatId": {},
"accessAndVisibility": "Toegang en zichtbaarheid",
"@accessAndVisibility": {},
"invitedBy": "📩 Uitgenodigd door: {user}",
"@invitedBy": {
"placeholders": {
"user": {}
}
},
"publicSpaces": "Publieke spaces",
"@publicSpaces": {},
"blockUsername": "Negeer gebruikersnaam",
"@blockUsername": {},
"publicChatAddresses": "Publieke chat adressen",
"@publicChatAddresses": {},
"createNewAddress": "Creëer nieuw adres",
"@createNewAddress": {},
"countChatsAndCountParticipants": "{chats} chats en {participants} deelnemers",
"@countChatsAndCountParticipants": {
"type": "text",
"placeholders": {
"chats": {},
"participants": {}
}
},
"noMoreChatsFound": "Geen chats gevonden...",
"@noMoreChatsFound": {},
"joinedChats": "Deelnemende chats",
"@joinedChats": {},
"knocking": "Kloppen",
"@knocking": {},
"space": "Space",
"@space": {},
"spaces": "Spaces",
"@spaces": {},
"unread": "Zet als ongelezen",
"@unread": {},
"databaseBuildErrorBody": "Het aanmaken van de SQlite database is mislukt. De app probeert nu een traditionele database te gebruiken. Meldt alsjeblieft deze fout aan de ontwikkelaars via deze {url}. De foutmelding is: {error}",
"@databaseBuildErrorBody": {
"type": "text",
"placeholders": {
"url": {},
"error": {}
}
},
"groupName": "Groepsnaam",
"@groupName": {},
"changeGeneralChatSettings": "Wijzig algemene chat instellingen",
"@changeGeneralChatSettings": {},
"restricted": "Beperkt",
"@restricted": {},
"searchForUsers": "Zoek naar @personen...",
"@searchForUsers": {},
"searchMore": "Zoek meer...",
"@searchMore": {},
"noPublicLinkHasBeenCreatedYet": "Publieke link is nog niet gecreëerd",
"@noPublicLinkHasBeenCreatedYet": {},
"groupCanBeFoundViaSearch": "Groep kan gevonden worden via zoeken",
"@groupCanBeFoundViaSearch": {},
"searchIn": "Zoek in chat \"{chat}\"...",
"@searchIn": {
"type": "text",
"placeholders": {
"chat": {}
}
},
"files": "Bestanden",
"@files": {},
"unreadChatsInApp": "{appname}: {unread} ongelezen chats",
"@unreadChatsInApp": {
"type": "text",
"placeholders": {
"appname": {},
"unread": {}
}
},
"noDatabaseEncryption": "Database versleuteling is niet ondersteund op dit platform",
"@noDatabaseEncryption": {},
"thereAreCountUsersBlocked": "Nu zijn er {count} personen geblokkeerd.",
"@thereAreCountUsersBlocked": {
"type": "text",
"count": {}
},
"markAsUnread": "Markeer als ongelezen",
"@markAsUnread": {},
"userLevel": "{level} - Persoon",
"@userLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"moderatorLevel": "{level} - Moderator",
"@moderatorLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"adminLevel": "{level} - Administrator",
"@adminLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"stickers": "Stickers",
"@stickers": {},
"nothingFound": "Niets gevonden...",
"@nothingFound": {},
"gallery": "Gallerij",
"@gallery": {},
"transparent": "Transparant",
"@transparent": {},
"incomingMessages": "Inkomende berichten",
"@incomingMessages": {},
"discover": "Ontdek",
"@discover": {},
"commandHint_ignore": "Negeer de gegeven matrix ID",
"@commandHint_ignore": {}
}

View file

@ -2369,7 +2369,7 @@
"reason": {}
}
},
"setChatDescription": "Изменить описание чата",
"setChatDescription": "Установить описание чата",
"@setChatDescription": {},
"setColorTheme": "Цветовая тема:",
"@setColorTheme": {},
@ -2708,5 +2708,57 @@
"files": "Файлы",
"@files": {},
"swipeRightToLeftToReply": "Для ответа проведите с права на лево",
"@swipeRightToLeftToReply": {}
"@swipeRightToLeftToReply": {},
"userLevel": "{level} - Пользователь",
"@userLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"moderatorLevel": "{level} - Модератор",
"@moderatorLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"adminLevel": "{level} - Администратор",
"@adminLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"changeGeneralChatSettings": "Изменить общие настройки чата",
"@changeGeneralChatSettings": {},
"changeTheChatPermissions": "Изменить права доступа к чату",
"@changeTheChatPermissions": {},
"changeTheDescriptionOfTheGroup": "Изменить описание чата",
"@changeTheDescriptionOfTheGroup": {},
"inviteOtherUsers": "Пригласить других пользователей в этот чат",
"@inviteOtherUsers": {},
"changeTheVisibilityOfChatHistory": "Изменить видимость истории чата",
"@changeTheVisibilityOfChatHistory": {},
"countChatsAndCountParticipants": "{chats} чатов и {participants} участников",
"@countChatsAndCountParticipants": {
"type": "text",
"placeholders": {
"chats": {},
"participants": {}
}
},
"unread": "Непрочитанные",
"@unread": {},
"space": "Пространство",
"@space": {},
"spaces": "Пространства",
"@spaces": {},
"markAsUnread": "Отметить как непрочитанное",
"@markAsUnread": {},
"goToSpace": "Перейти к пространству: {space}",
"@goToSpace": {
"type": "text",
"space": {}
}
}

View file

@ -2772,5 +2772,22 @@
"changeGeneralChatSettings": "Genel sohbet ayarlarını değiştir",
"@changeGeneralChatSettings": {},
"changeTheVisibilityOfChatHistory": "Sohbet geçmişinin görünürlüğünü değiştir",
"@changeTheVisibilityOfChatHistory": {}
"@changeTheVisibilityOfChatHistory": {},
"invitedBy": "📩 {user} davet etti",
"@invitedBy": {
"placeholders": {
"user": {}
}
},
"chatPermissionsDescription": "Bu sohbette belirli eylemler için hangi güç düzeyinin gerekli olduğunu tanımlayın. 0, 50 ve 100 güç düzeyleri genellikle kullanıcıları, moderatörleri ve yöneticileri temsil eder, ancak herhangi bir derecelendirme mümkündür.",
"@chatPermissionsDescription": {},
"changelog": "Değişiklik günlüğü",
"@changelog": {},
"updateInstalled": "🎉 Güncelleme {version} kuruldu!",
"@updateInstalled": {
"type": "text",
"placeholders": {
"version": {}
}
}
}

View file

@ -1557,7 +1557,7 @@
"type": "text",
"placeholders": {}
},
"defaultPermissionLevel": "Типовий рівень дозволів",
"defaultPermissionLevel": "Типовий рівень дозволів для нових користувачів",
"@defaultPermissionLevel": {
"type": "text",
"placeholders": {}
@ -1913,12 +1913,12 @@
},
"unverified": "Неперевірений",
"@unverified": {},
"locationDisabledNotice": "Служби визначення місцеположення вимкнені. Увімкніть їх, щоб могти надавати доступ до вашого місцеположення.",
"locationDisabledNotice": "Служби визначення розташування вимкнені. Увімкніть їх, щоб мати змогу ділитися своїм розташуванням.",
"@locationDisabledNotice": {
"type": "text",
"placeholders": {}
},
"locationPermissionDeniedNotice": "Дозвіл на розташування відхилено. Надайте можливість ділитися своїм місцеперебуванням.",
"locationPermissionDeniedNotice": "Дозвіл на розташування відхилено. Надайте можливість ділитися своїм розташуванням.",
"@locationPermissionDeniedNotice": {
"type": "text",
"placeholders": {}
@ -2708,5 +2708,86 @@
"@thereAreCountUsersBlocked": {
"type": "text",
"count": {}
}
},
"moderatorLevel": "{level} - Модератор",
"@moderatorLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"adminLevel": "{level} - Адміністратор",
"@adminLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"userLevel": "{level} - Користувач",
"@userLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"changeGeneralChatSettings": "Змінити загальні налаштування чату",
"@changeGeneralChatSettings": {},
"inviteOtherUsers": "Запросити інших користувачів до цього чату",
"@inviteOtherUsers": {},
"changeTheChatPermissions": "Змінити права доступу до чату",
"@changeTheChatPermissions": {},
"changeTheVisibilityOfChatHistory": "Змінити видимість історії чату",
"@changeTheVisibilityOfChatHistory": {},
"changeTheCanonicalRoomAlias": "Змінити основну адресу загальнодоступного чату",
"@changeTheCanonicalRoomAlias": {},
"sendRoomNotifications": "Надсилати сповіщення @room",
"@sendRoomNotifications": {},
"space": "Простір",
"@space": {},
"spaces": "Простори",
"@spaces": {},
"goToSpace": "Перейти до простору: {space}",
"@goToSpace": {
"type": "text",
"space": {}
},
"markAsUnread": "Позначити непрочитаним",
"@markAsUnread": {},
"alwaysUse24HourFormat": "ні",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
},
"invitedBy": "📩 Запрошений {user}",
"@invitedBy": {
"placeholders": {
"user": {}
}
},
"changeTheDescriptionOfTheGroup": "Змінити опис чату",
"@changeTheDescriptionOfTheGroup": {},
"updateInstalled": "🎉 Оновлення {version} встановлено!",
"@updateInstalled": {
"type": "text",
"placeholders": {
"version": {}
}
},
"changelog": "Зміни",
"@changelog": {},
"chatPermissionsDescription": "Визначте, який рівень повноважень необхідний для певних дій у цьому чаті. Рівні повноважень 0, 50 і 100 зазвичай представляють користувачів, модераторів та адміністраторів, але можливі будь-які градації.",
"@chatPermissionsDescription": {},
"countChatsAndCountParticipants": "{chats} чати та {participants} учасників",
"@countChatsAndCountParticipants": {
"type": "text",
"placeholders": {
"chats": {},
"participants": {}
}
},
"noMoreChatsFound": "Більше чатів не знайдено...",
"@noMoreChatsFound": {},
"joinedChats": "Приєднані чати",
"@joinedChats": {},
"unread": "Непрочитані",
"@unread": {}
}

View file

@ -2772,5 +2772,22 @@
"changeTheDescriptionOfTheGroup": "更改聊天描述",
"@changeTheDescriptionOfTheGroup": {},
"changeGeneralChatSettings": "更改常规聊天设置",
"@changeGeneralChatSettings": {}
"@changeGeneralChatSettings": {},
"invitedBy": "📩 邀请人 {user}",
"@invitedBy": {
"placeholders": {
"user": {}
}
},
"chatPermissionsDescription": "定义此聊天中哪个权限等级对特定操作是必需的。权限等级 0、50 和 100 通常代表用户、主持人和管理员,但你可以自定义任何等级。",
"@chatPermissionsDescription": {},
"changelog": "更新记录",
"@changelog": {},
"updateInstalled": "🎉 已安装更新 {version} ",
"@updateInstalled": {
"type": "text",
"placeholders": {
"version": {}
}
}
}

View file

@ -2736,5 +2736,32 @@
"appname": {},
"unread": {}
}
},
"adminLevel": "{level} - 管理員",
"@adminLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"userLevel": "{level} - 用戶",
"@userLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"moderatorLevel": "{level} - 管理員",
"@moderatorLevel": {
"type": "text",
"placeholders": {
"level": {}
}
},
"invitedBy": "📩 由 {user} 邀請",
"@invitedBy": {
"placeholders": {
"user": {}
}
}
}

View file

@ -3,6 +3,7 @@ import 'dart:developer';
import 'dart:io';
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:collection/collection.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
import 'package:file_picker/file_picker.dart';
@ -254,23 +255,22 @@ class ChatController extends State<ChatPageWithRoom>
// void requestHistory([_]) async {
Future<void> requestHistory() async {
if (timeline == null) return;
// Pangea#
if (!timeline!.canRequestHistory) return;
// Pangea#
Logs().v('Requesting history...');
await timeline!.requestHistory(historyCount: _loadHistoryCount);
await timeline?.requestHistory(historyCount: _loadHistoryCount);
}
void requestFuture() async {
final timeline = this.timeline;
if (timeline == null) return;
if (!timeline.canRequestFuture) return;
Logs().v('Requesting future...');
final mostRecentEventId = timeline.events.first.eventId;
await timeline.requestFuture(historyCount: _loadHistoryCount);
setReadMarker(eventId: mostRecentEventId);
}
void _updateScrollController() {
void updateScrollController() {
if (!mounted) {
return;
}
@ -289,7 +289,7 @@ class ChatController extends State<ChatPageWithRoom>
}
}
void _loadDraft() async {
void loadDraft() async {
final prefs = await SharedPreferences.getInstance();
final draft = widget.shareText ?? prefs.getString('draft_$roomId');
if (draft != null && draft.isNotEmpty) {
@ -299,12 +299,12 @@ class ChatController extends State<ChatPageWithRoom>
@override
void initState() {
scrollController.addListener(_updateScrollController);
inputFocus.addListener(_inputFocusListener);
scrollController.addListener(updateScrollController);
inputFocus.addListener(inputFocusListener);
_loadDraft();
loadDraft();
super.initState();
_displayChatDetailsColumn = ValueNotifier(
displayChatDetailsColumn = ValueNotifier(
Matrix.of(context).store.getBool(SettingKeys.displayChatDetailsColumn) ??
false,
);
@ -333,15 +333,15 @@ class ChatController extends State<ChatPageWithRoom>
await Matrix.of(context).client.roomsLoading;
});
// Pangea#
_tryLoadTimeline();
tryLoadTimeline();
if (kIsWeb) {
onFocusSub = html.window.onFocus.listen((_) => setReadMarker());
}
}
void _tryLoadTimeline() async {
void tryLoadTimeline() async {
final initialEventId = widget.eventId;
loadTimelineFuture = _getTimeline();
loadTimelineFuture = getTimeline();
try {
await loadTimelineFuture;
if (initialEventId != null) scrollToEventId(initialEventId);
@ -358,7 +358,7 @@ class ChatController extends State<ChatPageWithRoom>
return;
}
if (!mounted) return;
_showScrollUpMaterialBanner(fullyRead);
showScrollUpMaterialBanner(fullyRead);
} catch (e, s) {
ErrorReporter(context, 'Unable to load timeline').onErrorCallback(e, s);
rethrow;
@ -371,7 +371,7 @@ class ChatController extends State<ChatPageWithRoom>
scrollUpBannerEventId = null;
});
void _showScrollUpMaterialBanner(String eventId) => setState(() {
void showScrollUpMaterialBanner(String eventId) => setState(() {
scrollUpBannerEventId = eventId;
});
@ -404,7 +404,7 @@ class ChatController extends State<ChatPageWithRoom>
<Event>[];
// Pangea#
Future<void> _getTimeline({
Future<void> getTimeline({
String? eventContextId,
}) async {
await Matrix.of(context).client.roomsLoading;
@ -414,6 +414,7 @@ class ChatController extends State<ChatPageWithRoom>
eventContextId = null;
}
try {
timeline?.cancelSubscriptions();
timeline = await room.getTimeline(
onUpdate: updateView,
eventContextId: eventContextId,
@ -442,7 +443,7 @@ class ChatController extends State<ChatPageWithRoom>
);
if (!mounted) return;
if (e is TimeoutException || e is IOException) {
_showScrollUpMaterialBanner(eventContextId!);
showScrollUpMaterialBanner(eventContextId!);
}
}
timeline!.requestKeys(onlineKeyBackupOnly: false);
@ -459,10 +460,10 @@ class ChatController extends State<ChatPageWithRoom>
setReadMarker();
}
Future<void>? _setReadMarkerFuture;
Future<void>? setReadMarkerFuture;
void setReadMarker({String? eventId}) {
if (_setReadMarkerFuture != null) return;
if (setReadMarkerFuture != null) return;
if (_scrolledUp) return;
if (scrollUpBannerEventId != null) return;
if (eventId == null &&
@ -493,13 +494,13 @@ class ChatController extends State<ChatPageWithRoom>
Logs().d('Set read marker...', eventId);
// ignore: unawaited_futures
_setReadMarkerFuture = timeline
setReadMarkerFuture = timeline
.setReadMarker(
eventId: eventId,
public: AppConfig.sendPublicReadReceipts,
)
.then((_) {
_setReadMarkerFuture = null;
setReadMarkerFuture = null;
})
// #Pangea
.catchError((e, s) {
@ -531,7 +532,7 @@ class ChatController extends State<ChatPageWithRoom>
void dispose() {
timeline?.cancelSubscriptions();
timeline = null;
inputFocus.removeListener(_inputFocusListener);
inputFocus.removeListener(inputFocusListener);
onFocusSub?.cancel();
//#Pangea
choreographer.stateListener.close();
@ -556,7 +557,7 @@ class ChatController extends State<ChatPageWithRoom>
}
// then cancel the old timeline
// fixes bug with read reciepts and quick switching
loadTimelineFuture = _getTimeline(eventContextId: room.fullyRead).onError(
loadTimelineFuture = getTimeline(eventContextId: room.fullyRead).onError(
ErrorReporter(
context,
'Unable to load timeline after changing sending Client',
@ -590,7 +591,7 @@ class ChatController extends State<ChatPageWithRoom>
}) async {
// Pangea#
if (sendController.text.trim().isEmpty) return;
_storeInputTimeoutTimer?.cancel();
storeInputTimeoutTimer?.cancel();
final prefs = await SharedPreferences.getInstance();
prefs.remove('draft_$roomId');
var parseCommands = true;
@ -661,7 +662,7 @@ class ChatController extends State<ChatPageWithRoom>
setState(() {
sendController.text = pendingText;
_inputTextIsEmpty = pendingText.isEmpty;
inputTextIsEmpty = pendingText.isEmpty;
replyEvent = null;
editEvent = null;
pendingText = '';
@ -861,7 +862,7 @@ class ChatController extends State<ChatPageWithRoom>
setState(() => showEmojiPicker = !showEmojiPicker);
}
void _inputFocusListener() {
void inputFocusListener() {
if (showEmojiPicker && inputFocus.hasFocus) {
emojiPickerType = EmojiPickerType.keyboard;
setState(() => showEmojiPicker = false);
@ -875,7 +876,7 @@ class ChatController extends State<ChatPageWithRoom>
);
}
String _getSelectedEventString() {
String getSelectedEventString() {
var copyString = '';
if (selectedEvents.length == 1) {
return selectedEvents.first
@ -893,7 +894,7 @@ class ChatController extends State<ChatPageWithRoom>
}
void copyEventsAction() {
Clipboard.setData(ClipboardData(text: _getSelectedEventString()));
Clipboard.setData(ClipboardData(text: getSelectedEventString()));
setState(() {
showEmojiPicker = false;
// #Pangea
@ -1101,7 +1102,7 @@ class ChatController extends State<ChatPageWithRoom>
} else {
Matrix.of(context).shareContent = {
'msgtype': 'm.text',
'body': _getSelectedEventString(),
'body': getSelectedEventString(),
};
}
setState(() => selectedEvents.clear());
@ -1137,15 +1138,21 @@ class ChatController extends State<ChatPageWithRoom>
String eventId, {
bool highlightEvent = true,
}) async {
final eventIndex = timeline!.events
.where((event) => event.isVisibleInGui)
.toList()
.indexWhere((e) => e.eventId == eventId);
final foundEvent =
timeline!.events.firstWhereOrNull((event) => event.eventId == eventId);
final eventIndex = foundEvent == null
? -1
: timeline!.events
.where((event) => event.isVisibleInGui || event.eventId == eventId)
.toList()
.indexOf(foundEvent);
if (eventIndex == -1) {
setState(() {
timeline = null;
_scrolledUp = false;
loadTimelineFuture = _getTimeline(eventContextId: eventId).onError(
loadTimelineFuture = getTimeline(eventContextId: eventId).onError(
ErrorReporter(context, 'Unable to load timeline after scroll to ID')
.onErrorCallback,
);
@ -1166,7 +1173,7 @@ class ChatController extends State<ChatPageWithRoom>
duration: FluffyThemes.animationDuration,
preferPosition: AutoScrollPosition.middle,
);
_updateScrollController();
updateScrollController();
}
void scrollDown() async {
@ -1174,7 +1181,7 @@ class ChatController extends State<ChatPageWithRoom>
setState(() {
timeline = null;
_scrolledUp = false;
loadTimelineFuture = _getTimeline().onError(
loadTimelineFuture = getTimeline().onError(
ErrorReporter(context, 'Unable to load timeline after scroll down')
.onErrorCallback,
);
@ -1200,7 +1207,7 @@ class ChatController extends State<ChatPageWithRoom>
setState(() => showEmojiPicker = false);
if (emoji == null) return;
// make sure we don't send the same emoji twice
if (_allReactionEvents.any(
if (allReactionEvents.any(
(e) => e.content.tryGetMap('m.relates_to')?['key'] == emoji.emoji,
)) {
return;
@ -1224,7 +1231,7 @@ class ChatController extends State<ChatPageWithRoom>
);
}
late Iterable<Event> _allReactionEvents;
late Iterable<Event> allReactionEvents;
void emojiPickerBackspace() {
switch (emojiPickerType) {
@ -1245,7 +1252,7 @@ class ChatController extends State<ChatPageWithRoom>
// #Pangea
closeSelectionOverlay();
// Pangea#
_allReactionEvents = allReactionEvents;
allReactionEvents = allReactionEvents;
emojiPickerType = EmojiPickerType.reaction;
setState(() => showEmojiPicker = true);
}
@ -1459,18 +1466,18 @@ class ChatController extends State<ChatPageWithRoom>
);
}
Timer? _storeInputTimeoutTimer;
static const Duration _storeInputTimeout = Duration(milliseconds: 500);
Timer? storeInputTimeoutTimer;
static const storeInputTimeout = Duration(milliseconds: 500);
void onInputBarChanged(String text) {
if (_inputTextIsEmpty != text.isEmpty) {
if (inputTextIsEmpty != text.isEmpty) {
setState(() {
_inputTextIsEmpty = text.isEmpty;
inputTextIsEmpty = text.isEmpty;
});
}
_storeInputTimeoutTimer?.cancel();
_storeInputTimeoutTimer = Timer(_storeInputTimeout, () async {
storeInputTimeoutTimer?.cancel();
storeInputTimeoutTimer = Timer(storeInputTimeout, () async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('draft_$roomId', text);
});
@ -1509,7 +1516,7 @@ class ChatController extends State<ChatPageWithRoom>
}
}
bool _inputTextIsEmpty = true;
var inputTextIsEmpty = true;
bool get isArchived =>
{Membership.leave, Membership.ban}.contains(room.membership);
@ -1576,7 +1583,7 @@ class ChatController extends State<ChatPageWithRoom>
});
// #Pangea
MessageTextSelection textSelection = MessageTextSelection();
final textSelection = MessageTextSelection();
void showToolbar(
PangeaMessageEvent pangeaMessageEvent, {
@ -1627,14 +1634,14 @@ class ChatController extends State<ChatPageWithRoom>
}
// Pangea#
late final ValueNotifier<bool> _displayChatDetailsColumn;
late final ValueNotifier<bool> displayChatDetailsColumn;
void toggleDisplayChatDetailsColumn() async {
await Matrix.of(context).store.setBool(
SettingKeys.displayChatDetailsColumn,
!_displayChatDetailsColumn.value,
!displayChatDetailsColumn.value,
);
_displayChatDetailsColumn.value = !_displayChatDetailsColumn.value;
displayChatDetailsColumn.value = !displayChatDetailsColumn.value;
}
@override
@ -1649,7 +1656,7 @@ class ChatController extends State<ChatPageWithRoom>
duration: FluffyThemes.animationDuration,
curve: FluffyThemes.animationCurve,
child: ValueListenableBuilder(
valueListenable: _displayChatDetailsColumn,
valueListenable: displayChatDetailsColumn,
builder: (context, displayChatDetailsColumn, _) {
if (!FluffyThemes.isThreeColumnMode(context) ||
room.membership != Membership.join ||

View file

@ -678,6 +678,15 @@ class ChatListController extends State<ChatList>
final displayname =
room.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!));
final spacesWithPowerLevels = room.client.rooms
.where(
(space) =>
space.isSpace &&
space.canChangeStateEvent(EventTypes.SpaceChild) &&
!space.spaceChildren.any((c) => c.roomId == room.id),
)
.toList();
final action = await showMenu<ChatContextAction>(
context: posContext,
position: position,
@ -776,6 +785,18 @@ class ChatListController extends State<ChatList>
],
),
),
if (spacesWithPowerLevels.isNotEmpty)
PopupMenuItem(
value: ChatContextAction.addToSpace,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.group_work_outlined),
const SizedBox(width: 12),
Text(L10n.of(context)!.addToSpace),
],
),
),
PopupMenuItem(
value: ChatContextAction.leave,
child: Row(
@ -838,6 +859,25 @@ class ChatListController extends State<ChatList>
await showFutureLoadingDialog(context: context, future: room.leave);
return;
case ChatContextAction.addToSpace:
final space = await showConfirmationDialog(
context: context,
title: L10n.of(context)!.space,
actions: spacesWithPowerLevels
.map(
(space) => AlertDialogAction(
key: space,
label: space
.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!)),
),
)
.toList(),
);
if (space == null) return;
await showFutureLoadingDialog(
context: context,
future: () => space.setSpaceChild(room.id),
);
}
}
@ -1072,6 +1112,7 @@ enum ChatContextAction {
markUnread,
mute,
leave,
addToSpace,
}