diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index c14f47d..3776fd5 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -6,6 +6,11 @@ "longPressToRecordVoiceMessage": "Long press to record voice message.", "pause": "Pause", "resume": "Resume", + "newSubSpace": "New sub space", + "moveToDifferentSpace": "Move to different space", + "moveUp": "Move up", + "moveDown": "Move down", + "removeFromSpaceDescription": "The chat will be removed from the space but still appear in your chat list.", "endPoll": "End poll", "anonymousPoll": "Anonymous", "publicPoll": "Public", diff --git a/assets/l10n/intl_ru.arb b/assets/l10n/intl_ru.arb index 58b3139..01996ee 100644 --- a/assets/l10n/intl_ru.arb +++ b/assets/l10n/intl_ru.arb @@ -6,6 +6,11 @@ "noMessagesYet": "Нет сообщений", "longPressToRecordVoiceMessage": "Зажмите, чтобы записать голосовое сообщение.", "pause": "Пауза", + "newSubSpace": "Новое подпространство", + "moveToDifferentSpace": "Перенести в другое пространство", + "moveUp": "Вверх", + "moveDown": "Вниз", + "removeFromSpaceDescription": "Эта комната будет удалена из пространства, но останется в Вашем списке чатов.", "resume": "Продолжить", "anonymousPoll": "Анонимный", "publicPoll": "Открытый", diff --git a/lib/generated/l10n/l10n.dart b/lib/generated/l10n/l10n.dart index 7d1a5ea..10cda94 100644 --- a/lib/generated/l10n/l10n.dart +++ b/lib/generated/l10n/l10n.dart @@ -223,6 +223,36 @@ abstract class L10n { /// **'Resume'** String get resume; + /// No description provided for @newSubSpace. + /// + /// In en, this message translates to: + /// **'New sub space'** + String get newSubSpace; + + /// No description provided for @moveToDifferentSpace. + /// + /// In en, this message translates to: + /// **'Move to different space'** + String get moveToDifferentSpace; + + /// No description provided for @moveUp. + /// + /// In en, this message translates to: + /// **'Move up'** + String get moveUp; + + /// No description provided for @moveDown. + /// + /// In en, this message translates to: + /// **'Move down'** + String get moveDown; + + /// No description provided for @removeFromSpaceDescription. + /// + /// In en, this message translates to: + /// **'The chat will be removed from the space but still appear in your chat list.'** + String get removeFromSpaceDescription; + /// No description provided for @endPoll. /// /// In en, this message translates to: diff --git a/lib/generated/l10n/l10n_ar.dart b/lib/generated/l10n/l10n_ar.dart index 129d998..7dbad83 100644 --- a/lib/generated/l10n/l10n_ar.dart +++ b/lib/generated/l10n/l10n_ar.dart @@ -24,6 +24,22 @@ class L10nAr extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_be.dart b/lib/generated/l10n/l10n_be.dart index 47ea2b6..fbc64d4 100644 --- a/lib/generated/l10n/l10n_be.dart +++ b/lib/generated/l10n/l10n_be.dart @@ -24,6 +24,22 @@ class L10nBe extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_bn.dart b/lib/generated/l10n/l10n_bn.dart index bbd7340..81ad17d 100644 --- a/lib/generated/l10n/l10n_bn.dart +++ b/lib/generated/l10n/l10n_bn.dart @@ -24,6 +24,22 @@ class L10nBn extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_bo.dart b/lib/generated/l10n/l10n_bo.dart index 5ca3f14..b4af5c3 100644 --- a/lib/generated/l10n/l10n_bo.dart +++ b/lib/generated/l10n/l10n_bo.dart @@ -24,6 +24,22 @@ class L10nBo extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_ca.dart b/lib/generated/l10n/l10n_ca.dart index 16bb4b1..d1fb8a6 100644 --- a/lib/generated/l10n/l10n_ca.dart +++ b/lib/generated/l10n/l10n_ca.dart @@ -24,6 +24,22 @@ class L10nCa extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_cs.dart b/lib/generated/l10n/l10n_cs.dart index bd2a35c..c0cdcea 100644 --- a/lib/generated/l10n/l10n_cs.dart +++ b/lib/generated/l10n/l10n_cs.dart @@ -24,6 +24,22 @@ class L10nCs extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_de.dart b/lib/generated/l10n/l10n_de.dart index 4a353ff..51ab151 100644 --- a/lib/generated/l10n/l10n_de.dart +++ b/lib/generated/l10n/l10n_de.dart @@ -24,6 +24,22 @@ class L10nDe extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_el.dart b/lib/generated/l10n/l10n_el.dart index 18d28c0..f649d09 100644 --- a/lib/generated/l10n/l10n_el.dart +++ b/lib/generated/l10n/l10n_el.dart @@ -24,6 +24,22 @@ class L10nEl extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_en.dart b/lib/generated/l10n/l10n_en.dart index 04c491b..4a5fa02 100644 --- a/lib/generated/l10n/l10n_en.dart +++ b/lib/generated/l10n/l10n_en.dart @@ -24,6 +24,22 @@ class L10nEn extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_eo.dart b/lib/generated/l10n/l10n_eo.dart index 62a3a8a..d9e1f12 100644 --- a/lib/generated/l10n/l10n_eo.dart +++ b/lib/generated/l10n/l10n_eo.dart @@ -24,6 +24,22 @@ class L10nEo extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_es.dart b/lib/generated/l10n/l10n_es.dart index e80a010..533be37 100644 --- a/lib/generated/l10n/l10n_es.dart +++ b/lib/generated/l10n/l10n_es.dart @@ -24,6 +24,22 @@ class L10nEs extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_et.dart b/lib/generated/l10n/l10n_et.dart index afda2ec..da47eea 100644 --- a/lib/generated/l10n/l10n_et.dart +++ b/lib/generated/l10n/l10n_et.dart @@ -24,6 +24,22 @@ class L10nEt extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_eu.dart b/lib/generated/l10n/l10n_eu.dart index a4c5eb4..1bde741 100644 --- a/lib/generated/l10n/l10n_eu.dart +++ b/lib/generated/l10n/l10n_eu.dart @@ -24,6 +24,22 @@ class L10nEu extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_fa.dart b/lib/generated/l10n/l10n_fa.dart index a796961..43464c6 100644 --- a/lib/generated/l10n/l10n_fa.dart +++ b/lib/generated/l10n/l10n_fa.dart @@ -24,6 +24,22 @@ class L10nFa extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_fi.dart b/lib/generated/l10n/l10n_fi.dart index 0accfcc..aae290d 100644 --- a/lib/generated/l10n/l10n_fi.dart +++ b/lib/generated/l10n/l10n_fi.dart @@ -24,6 +24,22 @@ class L10nFi extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_fil.dart b/lib/generated/l10n/l10n_fil.dart index 20010ed..222201e 100644 --- a/lib/generated/l10n/l10n_fil.dart +++ b/lib/generated/l10n/l10n_fil.dart @@ -24,6 +24,22 @@ class L10nFil extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_fr.dart b/lib/generated/l10n/l10n_fr.dart index 33e4d5a..283460f 100644 --- a/lib/generated/l10n/l10n_fr.dart +++ b/lib/generated/l10n/l10n_fr.dart @@ -24,6 +24,22 @@ class L10nFr extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_ga.dart b/lib/generated/l10n/l10n_ga.dart index 94b2051..9febce3 100644 --- a/lib/generated/l10n/l10n_ga.dart +++ b/lib/generated/l10n/l10n_ga.dart @@ -24,6 +24,22 @@ class L10nGa extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_gl.dart b/lib/generated/l10n/l10n_gl.dart index 1f4e199..268efdb 100644 --- a/lib/generated/l10n/l10n_gl.dart +++ b/lib/generated/l10n/l10n_gl.dart @@ -24,6 +24,22 @@ class L10nGl extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_he.dart b/lib/generated/l10n/l10n_he.dart index 3d32ec7..aaab0d9 100644 --- a/lib/generated/l10n/l10n_he.dart +++ b/lib/generated/l10n/l10n_he.dart @@ -24,6 +24,22 @@ class L10nHe extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_hi.dart b/lib/generated/l10n/l10n_hi.dart index a12d291..1528cac 100644 --- a/lib/generated/l10n/l10n_hi.dart +++ b/lib/generated/l10n/l10n_hi.dart @@ -24,6 +24,22 @@ class L10nHi extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_hr.dart b/lib/generated/l10n/l10n_hr.dart index 02d5df4..9f01e8b 100644 --- a/lib/generated/l10n/l10n_hr.dart +++ b/lib/generated/l10n/l10n_hr.dart @@ -24,6 +24,22 @@ class L10nHr extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_hu.dart b/lib/generated/l10n/l10n_hu.dart index bb01c3e..c2dc2ba 100644 --- a/lib/generated/l10n/l10n_hu.dart +++ b/lib/generated/l10n/l10n_hu.dart @@ -24,6 +24,22 @@ class L10nHu extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_ia.dart b/lib/generated/l10n/l10n_ia.dart index c3fed88..6a83aaa 100644 --- a/lib/generated/l10n/l10n_ia.dart +++ b/lib/generated/l10n/l10n_ia.dart @@ -24,6 +24,22 @@ class L10nIa extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_id.dart b/lib/generated/l10n/l10n_id.dart index 12c4c3b..b162b23 100644 --- a/lib/generated/l10n/l10n_id.dart +++ b/lib/generated/l10n/l10n_id.dart @@ -24,6 +24,22 @@ class L10nId extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_ie.dart b/lib/generated/l10n/l10n_ie.dart index 7d3b20a..7ee3897 100644 --- a/lib/generated/l10n/l10n_ie.dart +++ b/lib/generated/l10n/l10n_ie.dart @@ -24,6 +24,22 @@ class L10nIe extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_it.dart b/lib/generated/l10n/l10n_it.dart index 2be51c0..4c6a77f 100644 --- a/lib/generated/l10n/l10n_it.dart +++ b/lib/generated/l10n/l10n_it.dart @@ -24,6 +24,22 @@ class L10nIt extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_ja.dart b/lib/generated/l10n/l10n_ja.dart index e3fe6bb..e3c855f 100644 --- a/lib/generated/l10n/l10n_ja.dart +++ b/lib/generated/l10n/l10n_ja.dart @@ -24,6 +24,22 @@ class L10nJa extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_ka.dart b/lib/generated/l10n/l10n_ka.dart index 3010bdd..eb09a4d 100644 --- a/lib/generated/l10n/l10n_ka.dart +++ b/lib/generated/l10n/l10n_ka.dart @@ -24,6 +24,22 @@ class L10nKa extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_ko.dart b/lib/generated/l10n/l10n_ko.dart index 7b80318..bad2623 100644 --- a/lib/generated/l10n/l10n_ko.dart +++ b/lib/generated/l10n/l10n_ko.dart @@ -24,6 +24,22 @@ class L10nKo extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_lt.dart b/lib/generated/l10n/l10n_lt.dart index 0a81214..3f437b6 100644 --- a/lib/generated/l10n/l10n_lt.dart +++ b/lib/generated/l10n/l10n_lt.dart @@ -24,6 +24,22 @@ class L10nLt extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_lv.dart b/lib/generated/l10n/l10n_lv.dart index 5b32b8a..572f204 100644 --- a/lib/generated/l10n/l10n_lv.dart +++ b/lib/generated/l10n/l10n_lv.dart @@ -24,6 +24,22 @@ class L10nLv extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_nb.dart b/lib/generated/l10n/l10n_nb.dart index e4df751..56fb2a8 100644 --- a/lib/generated/l10n/l10n_nb.dart +++ b/lib/generated/l10n/l10n_nb.dart @@ -24,6 +24,22 @@ class L10nNb extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_nl.dart b/lib/generated/l10n/l10n_nl.dart index e4be809..893028d 100644 --- a/lib/generated/l10n/l10n_nl.dart +++ b/lib/generated/l10n/l10n_nl.dart @@ -24,6 +24,22 @@ class L10nNl extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_pl.dart b/lib/generated/l10n/l10n_pl.dart index 0d1522d..0df608c 100644 --- a/lib/generated/l10n/l10n_pl.dart +++ b/lib/generated/l10n/l10n_pl.dart @@ -24,6 +24,22 @@ class L10nPl extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_pt.dart b/lib/generated/l10n/l10n_pt.dart index 9ac3270..681ce6e 100644 --- a/lib/generated/l10n/l10n_pt.dart +++ b/lib/generated/l10n/l10n_pt.dart @@ -24,6 +24,22 @@ class L10nPt extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_ro.dart b/lib/generated/l10n/l10n_ro.dart index 27570ba..30fe5af 100644 --- a/lib/generated/l10n/l10n_ro.dart +++ b/lib/generated/l10n/l10n_ro.dart @@ -24,6 +24,22 @@ class L10nRo extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_ru.dart b/lib/generated/l10n/l10n_ru.dart index b3cab54..95528bf 100644 --- a/lib/generated/l10n/l10n_ru.dart +++ b/lib/generated/l10n/l10n_ru.dart @@ -24,6 +24,22 @@ class L10nRu extends L10n { @override String get resume => 'Продолжить'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'Завершить опрос'; @@ -91,7 +107,7 @@ class L10nRu extends L10n { @override String get cleanExifDescription => - 'Удалять метаданные EXIF (модель камеры, геолокация, время) из изображений еред отправкой.'; + 'Удалять метаданные EXIF (модель камеры, геолокация, время) из изображений перед отправкой.'; @override String get repeatPassword => 'Повторите пароль'; diff --git a/lib/generated/l10n/l10n_sk.dart b/lib/generated/l10n/l10n_sk.dart index eaf5a91..db59bd9 100644 --- a/lib/generated/l10n/l10n_sk.dart +++ b/lib/generated/l10n/l10n_sk.dart @@ -24,6 +24,22 @@ class L10nSk extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_sl.dart b/lib/generated/l10n/l10n_sl.dart index 36b0412..3ed0849 100644 --- a/lib/generated/l10n/l10n_sl.dart +++ b/lib/generated/l10n/l10n_sl.dart @@ -24,6 +24,22 @@ class L10nSl extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_sr.dart b/lib/generated/l10n/l10n_sr.dart index ed06706..e3955ed 100644 --- a/lib/generated/l10n/l10n_sr.dart +++ b/lib/generated/l10n/l10n_sr.dart @@ -24,6 +24,22 @@ class L10nSr extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_sv.dart b/lib/generated/l10n/l10n_sv.dart index 72be4e4..8c80e17 100644 --- a/lib/generated/l10n/l10n_sv.dart +++ b/lib/generated/l10n/l10n_sv.dart @@ -24,6 +24,22 @@ class L10nSv extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_ta.dart b/lib/generated/l10n/l10n_ta.dart index 2406198..8981c25 100644 --- a/lib/generated/l10n/l10n_ta.dart +++ b/lib/generated/l10n/l10n_ta.dart @@ -24,6 +24,22 @@ class L10nTa extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_te.dart b/lib/generated/l10n/l10n_te.dart index 64c73fb..6b5ece6 100644 --- a/lib/generated/l10n/l10n_te.dart +++ b/lib/generated/l10n/l10n_te.dart @@ -24,6 +24,22 @@ class L10nTe extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_th.dart b/lib/generated/l10n/l10n_th.dart index ea57c24..dd42ebb 100644 --- a/lib/generated/l10n/l10n_th.dart +++ b/lib/generated/l10n/l10n_th.dart @@ -24,6 +24,22 @@ class L10nTh extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_tr.dart b/lib/generated/l10n/l10n_tr.dart index 91dbd9d..75e2758 100644 --- a/lib/generated/l10n/l10n_tr.dart +++ b/lib/generated/l10n/l10n_tr.dart @@ -24,6 +24,22 @@ class L10nTr extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_uk.dart b/lib/generated/l10n/l10n_uk.dart index 4964ed8..a692a7b 100644 --- a/lib/generated/l10n/l10n_uk.dart +++ b/lib/generated/l10n/l10n_uk.dart @@ -24,6 +24,22 @@ class L10nUk extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_vi.dart b/lib/generated/l10n/l10n_vi.dart index 1bcb6d4..330b6a5 100644 --- a/lib/generated/l10n/l10n_vi.dart +++ b/lib/generated/l10n/l10n_vi.dart @@ -24,6 +24,22 @@ class L10nVi extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/generated/l10n/l10n_zh.dart b/lib/generated/l10n/l10n_zh.dart index 0550d1a..2a9aece 100644 --- a/lib/generated/l10n/l10n_zh.dart +++ b/lib/generated/l10n/l10n_zh.dart @@ -24,6 +24,22 @@ class L10nZh extends L10n { @override String get resume => 'Resume'; + @override + String get newSubSpace => 'New sub space'; + + @override + String get moveToDifferentSpace => 'Move to different space'; + + @override + String get moveUp => 'Move up'; + + @override + String get moveDown => 'Move down'; + + @override + String get removeFromSpaceDescription => + 'The chat will be removed from the space but still appear in your chat list.'; + @override String get endPoll => 'End poll'; diff --git a/lib/pages/chat_list/chat_list_item.dart b/lib/pages/chat_list/chat_list_item.dart index ffa49a4..5c64552 100644 --- a/lib/pages/chat_list/chat_list_item.dart +++ b/lib/pages/chat_list/chat_list_item.dart @@ -1,9 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:extera_next/generated/l10n/l10n.dart'; import 'package:matrix/matrix.dart'; import 'package:extera_next/config/app_config.dart'; +import 'package:extera_next/generated/l10n/l10n.dart'; +import 'package:extera_next/pages/chat_list/unread_bubble.dart'; import 'package:extera_next/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:extera_next/utils/room_status_extension.dart'; import 'package:extera_next/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; @@ -35,32 +36,6 @@ class ChatListItem extends StatelessWidget { super.key, }); - Future archiveAction(BuildContext context) async { - { - if ([Membership.leave, Membership.ban].contains(room.membership)) { - final forgetResult = await showFutureLoadingDialog( - context: context, - future: () => room.forget(), - ); - return forgetResult.isValue; - } - final confirmed = await showOkCancelAlertDialog( - context: context, - title: L10n.of(context).areYouSure, - okLabel: L10n.of(context).leave, - cancelLabel: L10n.of(context).cancel, - message: L10n.of(context).archiveRoomDescription, - isDestructive: true, - ); - if (confirmed != OkCancelResult.ok) return false; - final leaveResult = await showFutureLoadingDialog( - context: context, - future: () => room.leave(), - ); - return leaveResult.isValue; - } - } - @override Widget build(BuildContext context) { final theme = Theme.of(context); @@ -69,14 +44,9 @@ class ChatListItem extends StatelessWidget { final typingText = room.getLocalizedTypingText(context); final lastEvent = room.lastEvent; final ownMessage = lastEvent?.senderId == room.client.userID; - final unread = room.isUnread || room.membership == Membership.invite; + final unread = room.isUnread; final directChatMatrixId = room.directChatMatrixID; final isDirectChat = directChatMatrixId != null; - final unreadBubbleSize = unread || room.hasNewMessages - ? room.notificationCount > 0 - ? 20.0 - : 14.0 - : 0.0; final hasNotifications = room.notificationCount > 0; final backgroundColor = activeChat ? theme.colorScheme.secondaryContainer : null; @@ -93,8 +63,6 @@ class ChatListItem extends StatelessWidget { : room.getState(EventTypes.RoomMember, lastEvent.senderId) == null; final space = this.space; - final inviterMxId = room.getState(EventTypes.RoomMember, room.client.userID!)?.senderId; - return Padding( padding: const EdgeInsets.symmetric( horizontal: 8, @@ -116,9 +84,7 @@ class ChatListItem extends StatelessWidget { duration: FluffyThemes.animationDuration, curve: FluffyThemes.animationCurve, scale: hovered ? 1.1 : 1.0, - child: - (!AppConfig.hideAvatarsInInvites || room.membership != Membership.invite) - ? SizedBox( + child: SizedBox( width: Avatar.defaultSize, height: Avatar.defaultSize, child: Stack( @@ -195,7 +161,7 @@ class ChatListItem extends StatelessWidget { ), ], ), - ) : null, + ), ), ), title: Row( @@ -232,13 +198,12 @@ class ChatListItem extends StatelessWidget { color: theme.colorScheme.primary, ), ), - if (!room.isSpace && - lastEvent != null && - room.membership != Membership.invite) + if (!room.isSpace && room.membership != Membership.invite) Padding( padding: const EdgeInsets.only(left: 4.0), child: Text( - lastEvent.originServerTs.localizedTimeShort(context), + room.latestEventReceivedTime + .localizedTimeShort(context), style: TextStyle( fontSize: 12, color: theme.colorScheme.outline, @@ -253,7 +218,7 @@ class ChatListItem extends StatelessWidget { children: [ if (typingText.isEmpty && ownMessage && - (room.lastEvent?.status.isSending ?? false)) ...[ + room.lastEvent?.status.isSending == true) ...[ const SizedBox( width: 16, height: 16, @@ -321,7 +286,7 @@ class ChatListItem extends StatelessWidget { ), builder: (context, snapshot) => Text( room.membership == Membership.invite - ? "${room + ? room .getState( EventTypes.RoomMember, room.client.userID!, @@ -331,9 +296,9 @@ class ChatListItem extends StatelessWidget { (isDirectChat ? L10n.of(context).newChatRequest : L10n.of(context) - .inviteGroupChat)}${inviterMxId != null ? " ($inviterMxId)" : ""}" + .inviteGroupChat) : snapshot.data ?? - L10n.of(context).emptyChat, + L10n.of(context).noMessagesYet, softWrap: false, maxLines: room.notificationCount >= 1 ? 2 : 1, overflow: TextOverflow.ellipsis, @@ -349,48 +314,33 @@ class ChatListItem extends StatelessWidget { ), ), const SizedBox(width: 8), - AnimatedContainer( - duration: FluffyThemes.animationDuration, - curve: FluffyThemes.animationCurve, - alignment: Alignment.center, - padding: const EdgeInsets.symmetric(horizontal: 7), - height: unreadBubbleSize, - width: !hasNotifications && !unread && !room.hasNewMessages - ? 0 - : (unreadBubbleSize - 9) * - room.notificationCount.toString().length + - 9, - decoration: BoxDecoration( - color: room.highlightCount > 0 || - room.membership == Membership.invite - ? theme.colorScheme.error - : hasNotifications || room.markedUnread - ? theme.colorScheme.primary - : theme.colorScheme.primaryContainer, - borderRadius: BorderRadius.circular(7), - ), - child: hasNotifications - ? Text( - room.notificationCount.toString(), - style: TextStyle( - color: room.highlightCount > 0 || - room.membership == Membership.invite - ? theme.colorScheme.onError - : hasNotifications - ? theme.colorScheme.onPrimary - : theme.colorScheme.onPrimaryContainer, - fontSize: 13, - fontWeight: FontWeight.w500, - ), - textAlign: TextAlign.center, - ) - : const SizedBox.shrink(), - ), + UnreadBubble(room: room), ], ), onTap: onTap, trailing: onForget == null - ? null + ? room.membership == Membership.invite + ? IconButton( + tooltip: L10n.of(context).decline, + icon: const Icon(Icons.delete_forever_outlined), + color: theme.colorScheme.error, + onPressed: () async { + final consent = await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).decline, + message: L10n.of(context).areYouSure, + okLabel: L10n.of(context).yes, + isDestructive: true, + ); + if (consent != OkCancelResult.ok) return; + if (!context.mounted) return; + await showFutureLoadingDialog( + context: context, + future: room.leave, + ); + }, + ) + : null : IconButton( icon: const Icon(Icons.delete_outlined), onPressed: onForget, diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 10698d5..fc5e330 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -1,27 +1,40 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:collection/collection.dart'; -import 'package:extera_next/generated/l10n/l10n.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart' as sdk; import 'package:matrix/matrix.dart'; import 'package:extera_next/config/app_config.dart'; import 'package:extera_next/config/themes.dart'; -import 'package:extera_next/pages/chat_list/chat_list_item.dart'; -import 'package:extera_next/pages/chat_list/search_title.dart'; +import 'package:extera_next/generated/l10n/l10n.dart'; +import 'package:extera_next/pages/chat_list/unread_bubble.dart'; import 'package:extera_next/utils/localized_exception_extension.dart'; +import 'package:extera_next/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:extera_next/utils/stream_extension.dart'; +import 'package:extera_next/utils/string_color.dart'; import 'package:extera_next/widgets/adaptive_dialogs/public_room_dialog.dart'; import 'package:extera_next/widgets/adaptive_dialogs/show_modal_action_popup.dart'; import 'package:extera_next/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; import 'package:extera_next/widgets/adaptive_dialogs/show_text_input_dialog.dart'; import 'package:extera_next/widgets/avatar.dart'; import 'package:extera_next/widgets/future_loading_dialog.dart'; +import 'package:extera_next/widgets/hover_builder.dart'; import 'package:extera_next/widgets/matrix.dart'; enum AddRoomType { chat, subspace } +enum SpaceChildAction { edit, moveToSpace, removeFromSpace } + +enum SpaceActions { + settings, + invite, + members, + leave, +} + class SpaceView extends StatefulWidget { final String spaceId; final void Function() onBack; @@ -45,7 +58,7 @@ class SpaceView extends StatefulWidget { } class _SpaceViewState extends State { - final List _discoveredChildren = []; + final List _discoveredChildren = []; final TextEditingController _filterController = TextEditingController(); String? _nextBatch; bool _noMoreRooms = false; @@ -58,9 +71,28 @@ class _SpaceViewState extends State { } void _loadHierarchy() async { - final room = Matrix.of(context).client.getRoomById(widget.spaceId); + final matrix = Matrix.of(context); + final room = matrix.client.getRoomById(widget.spaceId); if (room == null) return; + final cacheKey = 'spaces_history_cache${room.id}'; + if (_discoveredChildren.isEmpty) { + final cachedChildren = matrix.store.getStringList(cacheKey); + if (cachedChildren != null) { + try { + _discoveredChildren.addAll( + cachedChildren.map( + (jsonString) => + SpaceRoomsChunk$2.fromJson(jsonDecode(jsonString)), + ), + ); + } catch (e, s) { + Logs().e('Unable to json decode spaces hierarchy cache!', e, s); + matrix.store.remove(cacheKey); + } + } + } + setState(() { _isLoading = true; }); @@ -74,16 +106,25 @@ class _SpaceViewState extends State { ); if (!mounted) return; setState(() { + if (_nextBatch == null) _discoveredChildren.clear(); _nextBatch = hierarchy.nextBatch; if (hierarchy.nextBatch == null) { _noMoreRooms = true; } _discoveredChildren.addAll( - hierarchy.rooms - .where((c) => room.client.getRoomById(c.roomId) == null), + hierarchy.rooms.where((room) => room.roomId != widget.spaceId), ); _isLoading = false; }); + + if (_nextBatch == null) { + matrix.store.setStringList( + cacheKey, + _discoveredChildren + .map((child) => jsonEncode(child.toJson())) + .toList(), + ); + } } catch (e, s) { Logs().w('Unable to load hierarchy', e, s); if (!mounted) return; @@ -95,7 +136,7 @@ class _SpaceViewState extends State { } } - void _joinChildRoom(SpaceRoomsChunk item) async { + void _joinChildRoom(SpaceRoomsChunk$2 item) async { final client = Matrix.of(context).client; final space = client.getRoomById(widget.spaceId); @@ -111,9 +152,7 @@ class _SpaceViewState extends State { ), ); if (mounted && joined == true) { - setState(() { - _discoveredChildren.remove(item); - }); + setState(() {}); } } @@ -129,6 +168,10 @@ class _SpaceViewState extends State { await space?.postLoad(); context.push('/rooms/${widget.spaceId}/invite'); break; + case SpaceActions.members: + await space?.postLoad(); + context.push('/rooms/${widget.spaceId}/details/members'); + break; case SpaceActions.leave: final confirmed = await showOkCancelAlertDialog( context: context, @@ -151,27 +194,11 @@ class _SpaceViewState extends State { } } - void _addChatOrSubspace() async { - final roomType = await showModalActionPopup( - context: context, - title: L10n.of(context).addChatOrSubSpace, - actions: [ - AdaptiveModalAction( - value: AddRoomType.subspace, - label: L10n.of(context).createNewSpace, - ), - AdaptiveModalAction( - value: AddRoomType.chat, - label: L10n.of(context).createGroup, - ), - ], - ); - if (roomType == null) return; - + void _addChatOrSubspace(AddRoomType roomType) async { final names = await showTextInputDialog( context: context, title: roomType == AddRoomType.subspace - ? L10n.of(context).createNewSpace + ? L10n.of(context).newSubSpace : L10n.of(context).createGroup, hintText: roomType == AddRoomType.subspace ? L10n.of(context).spaceName @@ -196,29 +223,169 @@ class _SpaceViewState extends State { late final String roomId; final activeSpace = client.getRoomById(widget.spaceId)!; await activeSpace.postLoad(); + final isPublicSpace = activeSpace.joinRules == JoinRules.public; if (roomType == AddRoomType.subspace) { roomId = await client.createSpace( name: names, - visibility: activeSpace.joinRules == JoinRules.public - ? sdk.Visibility.public - : sdk.Visibility.private, + visibility: + isPublicSpace ? sdk.Visibility.public : sdk.Visibility.private, ); } else { roomId = await client.createGroupChat( + enableEncryption: !isPublicSpace, groupName: names, - preset: activeSpace.joinRules == JoinRules.public + preset: isPublicSpace ? CreateRoomPreset.publicChat : CreateRoomPreset.privateChat, - visibility: activeSpace.joinRules == JoinRules.public - ? sdk.Visibility.public - : sdk.Visibility.private, + visibility: + isPublicSpace ? sdk.Visibility.public : sdk.Visibility.private, + initialState: isPublicSpace + ? null + : [ + StateEvent( + content: { + 'join_rule': 'restricted', + 'allow': [ + { + 'room_id': widget.spaceId, + 'type': 'm.room_membership', + }, + ], + }, + type: EventTypes.RoomJoinRules, + ), + ], ); } await activeSpace.setSpaceChild(roomId); }, ); if (result.error != null) return; + setState(() { + _nextBatch = null; + _discoveredChildren.clear(); + }); + _loadHierarchy(); + } + + void _showSpaceChildEditMenu(BuildContext posContext, String roomId) async { + final overlay = + Overlay.of(posContext).context.findRenderObject() as RenderBox; + + final button = posContext.findRenderObject() as RenderBox; + + final position = RelativeRect.fromRect( + Rect.fromPoints( + button.localToGlobal(const Offset(0, -65), ancestor: overlay), + button.localToGlobal( + button.size.bottomRight(Offset.zero) + const Offset(-50, 0), + ancestor: overlay, + ), + ), + Offset.zero & overlay.size, + ); + + final action = await showMenu( + context: posContext, + position: position, + items: [ + PopupMenuItem( + value: SpaceChildAction.moveToSpace, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.move_down_outlined), + const SizedBox(width: 12), + Text(L10n.of(context).moveToDifferentSpace), + ], + ), + ), + PopupMenuItem( + value: SpaceChildAction.edit, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.edit_outlined), + const SizedBox(width: 12), + Text(L10n.of(context).edit), + ], + ), + ), + PopupMenuItem( + value: SpaceChildAction.removeFromSpace, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.group_remove_outlined), + const SizedBox(width: 12), + Text(L10n.of(context).removeFromSpace), + ], + ), + ), + ], + ); + if (action == null) return; + if (!mounted) return; + final space = Matrix.of(context).client.getRoomById(widget.spaceId); + if (space == null) return; + switch (action) { + case SpaceChildAction.edit: + context.push('/rooms/${widget.spaceId}/details'); + case SpaceChildAction.moveToSpace: + final spacesWithPowerLevels = space.client.rooms + .where( + (room) => + room.isSpace && + room.canChangeStateEvent(EventTypes.SpaceChild) && + room.id != widget.spaceId, + ) + .toList(); + final newSpace = await showModalActionPopup( + context: context, + title: L10n.of(context).space, + actions: spacesWithPowerLevels + .map( + (space) => AdaptiveModalAction( + value: space, + label: space + .getLocalizedDisplayname(MatrixLocals(L10n.of(context))), + ), + ) + .toList(), + ); + if (newSpace == null) return; + final result = await showFutureLoadingDialog( + context: context, + future: () async { + await newSpace.setSpaceChild(newSpace.id); + await space.removeSpaceChild(roomId); + }, + ); + if (result.isError) return; + if (!mounted) return; + _nextBatch = null; + _loadHierarchy(); + return; + + case SpaceChildAction.removeFromSpace: + final consent = await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).removeFromSpace, + message: L10n.of(context).removeFromSpaceDescription, + ); + if (consent != OkCancelResult.ok) return; + if (!mounted) return; + final result = await showFutureLoadingDialog( + context: context, + future: () => space.removeSpaceChild(roomId), + ); + if (result.isError) return; + if (!mounted) return; + _nextBatch = null; + _loadHierarchy(); + return; + } } @override @@ -228,6 +395,11 @@ class _SpaceViewState extends State { final room = Matrix.of(context).client.getRoomById(widget.spaceId); final displayname = room?.getLocalizedDisplayname() ?? L10n.of(context).nothingFound; + const avatarSize = Avatar.defaultSize / 1.5; + final isAdmin = room?.canChangeStateEvent( + EventTypes.SpaceChild, + ) == + true; return Scaffold( appBar: AppBar( leading: FluffyThemes.isColumnMode(context) @@ -242,6 +414,7 @@ class _SpaceViewState extends State { title: ListTile( contentPadding: EdgeInsets.zero, leading: Avatar( + size: avatarSize, mxContent: room?.avatar, name: displayname, border: BorderSide(width: 1, color: theme.dividerColor), @@ -252,19 +425,40 @@ class _SpaceViewState extends State { maxLines: 1, overflow: TextOverflow.ellipsis, ), - subtitle: room == null - ? null - : Text( - L10n.of(context).countChatsAndCountParticipants( - room.spaceChildren.length, - room.summary.mJoinedMemberCount ?? 1, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), ), actions: [ + if (isAdmin) + PopupMenuButton( + icon: const Icon(Icons.add_outlined), + onSelected: _addChatOrSubspace, + tooltip: L10n.of(context).addChatOrSubSpace, + itemBuilder: (context) => [ + PopupMenuItem( + value: AddRoomType.chat, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.group_add_outlined), + const SizedBox(width: 12), + Text(L10n.of(context).newGroup), + ], + ), + ), + PopupMenuItem( + value: AddRoomType.subspace, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.workspaces_outlined), + const SizedBox(width: 12), + Text(L10n.of(context).newSubSpace), + ], + ), + ), + ], + ), PopupMenuButton( + useRootNavigator: true, onSelected: _onSpaceAction, itemBuilder: (context) => [ PopupMenuItem( @@ -289,6 +483,21 @@ class _SpaceViewState extends State { ], ), ), + PopupMenuItem( + value: SpaceActions.members, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.group_outlined), + const SizedBox(width: 12), + Text( + L10n.of(context).countParticipants( + room?.summary.mJoinedMemberCount ?? 1, + ), + ), + ], + ), + ), PopupMenuItem( value: SpaceActions.leave, child: Row( @@ -304,16 +513,6 @@ class _SpaceViewState extends State { ), ], ), - floatingActionButton: room?.canChangeStateEvent( - EventTypes.SpaceChild, - ) == - true - ? FloatingActionButton.extended( - onPressed: _addChatOrSubspace, - label: Text(L10n.of(context).group), - icon: const Icon(Icons.group_add_outlined), - ) - : null, body: room == null ? const Center( child: Icon( @@ -331,9 +530,11 @@ class _SpaceViewState extends State { .whereType() .toSet(); - final joinedRooms = room.client.rooms - .where((room) => childrenIds.remove(room.id)) - .toList(); + final joinedRooms = Map.fromEntries( + room.client.rooms + .where((room) => childrenIds.remove(room.id)) + .map((room) => MapEntry(room.id, room)), + ); final joinedParents = room.spaceParents .map((parent) { @@ -348,7 +549,6 @@ class _SpaceViewState extends State { slivers: [ SliverAppBar( floating: true, - toolbarHeight: 72, scrolledUnderElevation: 0, backgroundColor: Colors.transparent, automaticallyImplyLeading: false, @@ -358,11 +558,6 @@ class _SpaceViewState extends State { textInputAction: TextInputAction.search, decoration: InputDecoration( filled: true, - fillColor: theme.colorScheme.secondaryContainer, - border: OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(99), - ), contentPadding: EdgeInsets.zero, hintText: L10n.of(context).search, hintStyle: TextStyle( @@ -422,42 +617,11 @@ class _SpaceViewState extends State { }, ), SliverList.builder( - itemCount: joinedRooms.length, + itemCount: _discoveredChildren.length + 1, itemBuilder: (context, i) { - final joinedRoom = joinedRooms[i]; - return ChatListItem( - joinedRoom, - filter: filter, - onTap: () => widget.onChatTab(joinedRoom), - onLongPress: (context) => widget.onChatContext( - joinedRoom, - context, - ), - activeChat: widget.activeChat == joinedRoom.id, - ); - }, - ), - SliverList.builder( - itemCount: _discoveredChildren.length + 2, - itemBuilder: (context, i) { - if (i == 0) { - return SearchTitle( - title: L10n.of(context).discover, - icon: const Icon(Icons.explore_outlined), - ); - } - i--; if (i == _discoveredChildren.length) { if (_noMoreRooms) { - return Padding( - padding: const EdgeInsets.all(12.0), - child: Center( - child: Text( - L10n.of(context).noMoreChatsFound, - style: const TextStyle(fontSize: 13), - ), - ), - ); + return const SizedBox.shrink(); } return Padding( padding: const EdgeInsets.symmetric( @@ -467,11 +631,7 @@ class _SpaceViewState extends State { child: TextButton( onPressed: _isLoading ? null : _loadHierarchy, child: _isLoading - ? LinearProgressIndicator( - borderRadius: BorderRadius.circular( - AppConfig.borderRadius, - ), - ) + ? const CircularProgressIndicator.adaptive() : Text(L10n.of(context).loadMore), ), ); @@ -483,6 +643,7 @@ class _SpaceViewState extends State { if (!displayname.toLowerCase().contains(filter)) { return const SizedBox.shrink(); } + final joinedRoom = joinedRooms[item.roomId]; return Padding( padding: const EdgeInsets.symmetric( horizontal: 8, @@ -492,51 +653,83 @@ class _SpaceViewState extends State { borderRadius: BorderRadius.circular(AppConfig.borderRadius), clipBehavior: Clip.hardEdge, - child: ListTile( - visualDensity: - const VisualDensity(vertical: -0.5), - contentPadding: - const EdgeInsets.symmetric(horizontal: 8), - onTap: () => _joinChildRoom(item), - leading: Avatar( - mxContent: item.avatarUrl, - name: displayname, - borderRadius: item.roomType == 'm.space' - ? BorderRadius.circular( - AppConfig.borderRadius / 2, - ) + color: joinedRoom != null && + widget.activeChat == joinedRoom.id + ? theme.colorScheme.secondaryContainer + : Colors.transparent, + child: HoverBuilder( + builder: (context, hovered) => ListTile( + visualDensity: + const VisualDensity(vertical: -0.5), + contentPadding: + const EdgeInsets.symmetric(horizontal: 8), + onTap: joinedRoom != null + ? () => widget.onChatTab(joinedRoom) + : () => _joinChildRoom(item), + onLongPress: isAdmin + ? () => _showSpaceChildEditMenu( + context, + item.roomId, + ) : null, - ), - title: Row( - children: [ - Expanded( - child: Text( - displayname, - maxLines: 1, - overflow: TextOverflow.ellipsis, + leading: hovered && isAdmin + ? SizedBox.square( + dimension: avatarSize, + child: IconButton( + splashRadius: avatarSize, + iconSize: 14, + style: IconButton.styleFrom( + foregroundColor: theme.colorScheme + .onTertiaryContainer, + backgroundColor: theme + .colorScheme.tertiaryContainer, + ), + onPressed: () => + _showSpaceChildEditMenu( + context, + item.roomId, + ), + icon: const Icon(Icons.edit_outlined), + ), + ) + : Avatar( + size: avatarSize, + mxContent: item.avatarUrl, + name: '#', + backgroundColor: + theme.colorScheme.surfaceContainer, + textColor: item.name?.darkColor ?? + theme.colorScheme.onSurface, + border: item.roomType == 'm.space' + ? BorderSide( + color: theme.colorScheme + .surfaceContainerHighest, + ) + : null, + borderRadius: item.roomType == 'm.space' + ? BorderRadius.circular( + AppConfig.borderRadius / 4, + ) + : null, + ), + title: Row( + children: [ + Expanded( + child: Opacity( + opacity: joinedRoom == null ? 0.5 : 1, + child: Text( + displayname, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), ), - ), - Text( - item.numJoinedMembers.toString(), - style: TextStyle( - fontSize: 13, - color: theme.textTheme.bodyMedium!.color, - ), - ), - const SizedBox(width: 4), - const Icon( - Icons.people_outlined, - size: 14, - ), - ], - ), - subtitle: Text( - item.topic ?? - L10n.of(context).countParticipants( - item.numJoinedMembers, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, + if (joinedRoom != null) + UnreadBubble(room: joinedRoom) + else + const Icon(Icons.chevron_right_outlined), + ], + ), ), ), ), @@ -550,10 +743,4 @@ class _SpaceViewState extends State { ), ); } -} - -enum SpaceActions { - settings, - invite, - leave, -} +} \ No newline at end of file diff --git a/lib/pages/chat_list/unread_bubble.dart b/lib/pages/chat_list/unread_bubble.dart new file mode 100644 index 0000000..b244e6e --- /dev/null +++ b/lib/pages/chat_list/unread_bubble.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; + +import 'package:matrix/matrix.dart'; + +import 'package:extera_next/config/themes.dart'; + +class UnreadBubble extends StatelessWidget { + final Room room; + const UnreadBubble({required this.room, super.key}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final unread = room.isUnread; + final hasNotifications = room.notificationCount > 0; + final unreadBubbleSize = unread || room.hasNewMessages + ? room.notificationCount > 0 + ? 20.0 + : 14.0 + : 0.0; + return AnimatedContainer( + duration: FluffyThemes.animationDuration, + curve: FluffyThemes.animationCurve, + alignment: Alignment.center, + padding: const EdgeInsets.symmetric(horizontal: 7), + height: unreadBubbleSize, + width: !hasNotifications && !unread && !room.hasNewMessages + ? 0 + : (unreadBubbleSize - 9) * room.notificationCount.toString().length + + 9, + decoration: BoxDecoration( + color: room.highlightCount > 0 + ? theme.colorScheme.error + : hasNotifications || room.markedUnread + ? theme.colorScheme.primary + : theme.colorScheme.primaryContainer, + borderRadius: BorderRadius.circular(7), + ), + child: hasNotifications + ? Text( + room.notificationCount.toString(), + style: TextStyle( + color: room.highlightCount > 0 + ? theme.colorScheme.onError + : hasNotifications + ? theme.colorScheme.onPrimary + : theme.colorScheme.onPrimaryContainer, + fontSize: 13, + fontWeight: FontWeight.w500, + ), + textAlign: TextAlign.center, + ) + : const SizedBox.shrink(), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/adaptive_dialogs/public_room_dialog.dart b/lib/widgets/adaptive_dialogs/public_room_dialog.dart index 2add953..c604248 100644 --- a/lib/widgets/adaptive_dialogs/public_room_dialog.dart +++ b/lib/widgets/adaptive_dialogs/public_room_dialog.dart @@ -30,7 +30,9 @@ class PublicRoomDialog extends StatelessWidget { final result = await showFutureLoadingDialog( context: context, future: () async { - if (chunk != null && client.getRoomById(chunk.roomId) != null) { + if (chunk != null && + client.getRoomById(chunk.roomId) != null && + client.getRoomById(chunk.roomId)?.membership != Membership.leave) { return chunk.roomId; } final roomId = chunk != null && knock diff --git a/lib/widgets/avatar.dart b/lib/widgets/avatar.dart index 293b557..c2a0895 100644 --- a/lib/widgets/avatar.dart +++ b/lib/widgets/avatar.dart @@ -18,6 +18,8 @@ class Avatar extends StatelessWidget { final BorderRadius? borderRadius; final IconData? icon; final BorderSide? border; + final Color? backgroundColor; + final Color? textColor; const Avatar({ this.mxContent, @@ -30,6 +32,8 @@ class Avatar extends StatelessWidget { this.borderRadius, this.border, this.icon, + this.backgroundColor, + this.textColor, super.key, }); @@ -71,14 +75,16 @@ class Avatar extends StatelessWidget { height: size, placeholder: (_) => noPic ? Container( - decoration: BoxDecoration(color: name?.lightColorAvatar), + decoration: BoxDecoration( + color: backgroundColor ?? name?.lightColorAvatar, + ), alignment: Alignment.center, child: Text( fallbackLetters, textAlign: TextAlign.center, style: TextStyle( fontFamily: 'RobotoMono', - color: Colors.white, + color: textColor ?? Colors.white, fontWeight: FontWeight.bold, fontSize: (size / 2.5).roundToDouble(), ), diff --git a/pubspec.lock b/pubspec.lock index 431f0cc..20451ab 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1201,9 +1201,11 @@ packages: matrix: dependency: "direct main" description: - path: "/home/officialdakari/repos/matrix-dart-sdk" - relative: false - source: path + path: "." + ref: main + resolved-ref: f678376e3a4825a6e1a00d89585d6bae0843950c + url: "https://git.extera.xyz/OfficialDakari/matrix-dart-sdk.git" + source: git version: "3.0.1" meta: dependency: transitive