Merge branch 'develop' into feature/conversations

This commit is contained in:
Philipp Neumann 2021-05-11 09:41:04 +02:00 committed by GitHub
commit f7d7362a85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
546 changed files with 25760 additions and 2118 deletions

View File

@ -7,15 +7,6 @@
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />

View File

@ -2,16 +2,33 @@ Changes in Element 1.1.7 (2021-XX-XX)
===================================================
Features ✨:
-
- Spaces beta
Improvements 🙌:
- Priority conversations for Android 11+ (#2734)
- Add ability to install APK from directly from Element (#2381)
- Delete and react to stickers (#3250)
- Compress video before sending (#442)
- Improve file too big error detection (#3245)
- User can now select video when selecting Gallery to send attachments to a room
- Add option to record a video from the camera
- Add the public icon on the rooms in the room list (#3292)
Bugfix 🐛:
- Message states cosmetic changes (#3007)
- Fix exception in rxSingle (#3180)
- Do not invite the current user when creating a room (#3123)
- Fix color issues when the system theme is changed (#2738)
- Fix issues on Android 11 (#3067)
- Fix issue when opening encrypted files (#3186)
- Fix wording issue (#3242)
- Fix missing sender information after edits (#3184)
- Fix read marker not updating automatically (#3267)
- Sent video does not contains duration (#3272)
- Properly clean the back stack if the user cancel registration when waiting for email validation
- Fix read marker visibility/position when filtering some events
- Fix user invitation in case of restricted profile api (#3306)
Translations 🗣:
-
@ -21,12 +38,23 @@ SDK API changes ⚠️:
Build 🧱:
- Upgrade to gradle 7
- https://github.com/Piasy/BigImageViewer is now hosted on mavenCentral()
- Upgrade Realm to version 10.4.0
Test:
-
Other changes:
- New store descriptions
- `master` branch has been renamed to `main`. To apply change to your dev environment, run:
```sh
git branch -m master main
git fetch origin
git branch -u origin/main main
# And optionally
git remote prune origin
```
- Allow cleartext (non-SSL) connections to Matrix servers on LAN hosts (#3166)
Changes in Element 1.1.6 (2021-04-16)
===================================================

View File

@ -17,20 +17,6 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
buildscript {
repositories {
maven {
url 'https://jitpack.io'
content {
// PhotoView
includeGroupByRegex 'com\\.github\\.chrisbanes'
}
}
jcenter()
}
}
android {
compileSdkVersion 30

View File

@ -45,25 +45,20 @@ allprojects {
// PFLockScreen-Android
includeGroupByRegex 'com\\.github\\.vector-im'
//Chat effects
// Chat effects
includeGroupByRegex 'com\\.github\\.jetradarmobile'
includeGroupByRegex 'nl\\.dionsegijn'
}
}
maven {
url "https://dl.bintray.com/piasy/maven"
content {
includeGroupByRegex "com\\.github\\.piasy"
}
}
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
// Jitsi repo
maven {
url "https://github.com/vector-im/jitsi_libre_maven/raw/master/android-sdk-3.1.0"
url "https://github.com/vector-im/jitsi_libre_maven/raw/main/android-sdk-3.1.0"
// Note: to test Jitsi release you can use a local file like this:
// url "file:///Users/bmarty/workspaces/jitsi_libre_maven/android-sdk-3.1.0"
}
google()
mavenCentral()
jcenter()
}

View File

@ -0,0 +1,2 @@
Canvis principals d'aquesta versió: millora de rendiment i correcció d'errors!
Registre de canvis complet: https://github.com/vector-im/element-android/releases/tag/v1.1.2

View File

@ -0,0 +1,2 @@
Canvis principals d'aquesta versió: millora de rendiment i correcció d'errors!
Registre de canvis complet: https://github.com/vector-im/element-android/releases/tag/v1.1.3

View File

@ -0,0 +1,2 @@
Hauptänderungen in dieser Version: Leistungsverbesserung und Fehlerbehebungen!
Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.1.2

View File

@ -0,0 +1,2 @@
Hauptänderungen in dieser Version: Leistungsverbesserung und Fehlerbehebungen!
Vollständiges Änderungsprotokoll: https://github.com/vector-im/element-android/releases/tag/v1.1.3

View File

@ -0,0 +1,2 @@
Põhilised muutused selles versioonis: jõudluse parandused ja pisikohendused.
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.2

View File

@ -0,0 +1,2 @@
Põhilised muutused selles versioonis: jõudluse parandused ja pisikohendused.
Kogu ingliskeelne muudatuste logi: https://github.com/vector-im/element-android/releases/tag/v1.1.3

View File

@ -0,0 +1,2 @@
Principaux changements pour cette version : amélioration des performances et corrections de bugs !
Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.1.2

View File

@ -0,0 +1,2 @@
Principaux changements pour cette version : amélioration des performances et corrections de bugs !
Intégralité des changements : https://github.com/vector-im/element-android/releases/tag/v1.1.3

View File

@ -1,30 +1,30 @@
Element est une nouvelle application de messagerie et de collaboration qui :
Element est une nouvelle application de messagerie et de collaboration qui :
1) Vous place aux commandes de votre vie privée
2) Vous permet de communiquer avec n'importe qui du réseau Matrix, et plus encore par des intégrations d'autres applications comme Slack ou Discord
3) Vous protège de la publicité et de la collecte de données
4) Vous sécurise grâce à du chiffrement bout-à-bout, avec de la signature croisée pour authentifier les autres utilisateurs
1. Vous permet de préserver votre vie privée
2. Vous permet de communiquer avec nimporte qui sur réseau Matrix, et plus encore grâce aux intégrations dautres applications telles que Slack ou Discord
3. Vous protège de la publicité et de la collecte de données
4. Vous protège grâce au chiffrement de bout-à-bout et à la signature croisée pour authentifier les autres utilisateurs
Element est complètement différent des autres applications de messagerie et de collaboration puisque l'application est décentralisée et open-source.
Element est complètement différente des autres applications de messagerie et de collaboration puisque lapplication est décentralisée et open-source.
Element vous permet d'héberger vous-même -ou de choisir un hôte- vous permettant d'assurer votre vie privée, la propriété et le contrôle de vos données et de vos conversations. Cela vous offre l'accès à un réseau ouvert, vous n'êtes donc pas condamné à parler à d'autres utilisateurs d'Element seulement. Et c'est très sécurisé.
Element vous permet dhéberger vous-même ou de choisir un hôte vous permettant dassurer votre vie privée, la propriété et le contrôle de vos données et de vos conversations. Cela vous donne accès à un réseau ouvert. Vous nêtes donc pas condamné à parler à dautres utilisateurs dElement seulement. Et c'est très sécurisé.
Element peut faire tout ça car il est basé sur Matrix, le protocole standard pour la communication ouverte et décentralisée.
Element peut faire tout ça car elle est basée sur Matrix, le protocole standard pour la communication ouverte et décentralisée.
Element vous donne le contrôle en vous laissant choisir qui héberge vos conversations. Depuis l'application Element, vous pouvez choisir votre hôte de différentes manières :
Element vous donne le contrôle en vous laissant choisir qui héberge vos conversations. Depuis l'application Element, vous pouvez choisir votre hôte de différentes manières :
1) Créer un compte gratuit sur le serveur public matrix.org hébergé par les développeurs de Matrix, ou choisir parler les milliers de serveurs public hébergés par des bénévoles
2) Héberger vous-même votre compte en installant un serveur sur votre propre machine
3) Créer un compte sur un serveur personnalisé en souscrivant sur la plateforme d'hébergement « Element Matrix Services » (EMS)
1. Créer un compte gratuit sur le serveur public matrix.org hébergé par les développeurs de Matrix, ou choisir parmi les milliers de serveurs public hébergés par des bénévoles
2. Héberger vous-même votre compte en installant un serveur sur votre propre machine
3. Créer un compte sur un serveur personnalisé en souscrivant sur la plateforme d'hébergement « Element Matrix Services » (EMS)
<b>Pourquoi choisir Element ?</b>
<b>POSSÉDEZ VOS DONNÉES</b> : Vous décidez où conserver vos données et vos messages. Vous les possédez et vous les contrôlez, et non une MEGACORP qui mine vos données ou les donnent à des tiers
<b>VOS DONNÉES VOUS APPARTIENNENT</b> : vous décidez où stocker vos données et messages. Ils vous appartiennent et vous les maîtrisez. Aucune multinationale ne viendra extraire vos données pour les envoyer au plus offrant.
<b>UNE MESSAGERIE OUVERTE ET COLLABORATIVE</b> : Vous pouvez discuter avec n'importe qui sur le réseau Matrix, qu'ils utilisent Element ou une autre application basée sur Matrix, et même s'ils utilisent un système de messagerie différent comment Slack, Discord, IRC ou XMPP.
<b>MESSAGERIE ET COLLABORATION OUVERTES</b> : vous pouvez discuter avec tout le réseau Matrix, quils utilisent Element ou une autre application Matrix, même sils utilisent une autre plateforme de messagerie telle que Slack, IRC ou XMPP.
<b>SUPER SÉCURISÉ</b> : Un réel chiffrement bout-à-bout (seulement ceux deux la conversation peuvent déchiffrer les messages), et une signature croisée pour vérifier les appareils des participants de la conversation.
<b>ULTRA SÉCURISÉ</b> : chiffrement de bout en bout (seuls les membres dune conversation peuvent déchiffrer les messages), et signature croisée pour vérifier les appareils de vos interlocuteurs.
<b>COMMUNICATION COMPLÈTE</b> : Messagerie, appels vocaux et vidéo, transfert de fichiers, partage d'écran et un tas d'intégrations, robots et widgets. Construisez des salons, des communautés, restez en contact et accomplissez de grandes choses.
<b>TOUTES VOS COMMUNICATIONS</b> : messagerie, appels audio et vidéo, partage de fichier, partage décran et un grand nombre dintégrations, robots et widgets. Participez à des salons, des communautés, restez en contact et faites avancer vos projets.
<b>PARTOUT OÙ VOUS ÊTES</b> : Restez connectés peu import où vous êtes avec la synchronisation complète de l'historique des messages sur tous vos appareils et sur le web sur https://app.element.io.
<b>PARTOUT AVEC VOUS</b> : votre historique reste synchronisé entre tous vos appareils et sur le web sur https://element.io/app.

View File

@ -0,0 +1,2 @@
Modifiche principali in questa versione: prestazioni migliorate e correzione di errori!
Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.2

View File

@ -0,0 +1,2 @@
Modifiche principali in questa versione: prestazioni migliorate e correzioni di errori!
Cronologia completa: https://github.com/vector-im/element-android/releases/tag/v1.1.3

View File

@ -0,0 +1,2 @@
今回の新バージョンでは、主にバグの修正と改善が行われています。メッセージの送信がより速くなりました。
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.10

View File

@ -0,0 +1,2 @@
今回の新バージョンでは、主にUIユーザーインターフェースとUXユーザーエクスペリエンスの向上が図られています。友達を招待したり、QRコードを読み取って素早くDMを作成できるようになりました。
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.11

View File

@ -0,0 +1,2 @@
このバージョンの主な変更点: URLプレビュー、新しい絵文字、新しいルーム設定機能、それにクリスマスには雪が
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.12

View File

@ -0,0 +1,2 @@
このバージョンの主な変更点: URLプレビュー、新しい絵文字、新しいルーム設定機能、それにクリスマスには雪が
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.13

View File

@ -0,0 +1,2 @@
このバージョンの主な変更点: 部屋の許可、自動のテーマ切替、そして多くのバグを修正しました。
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.14

View File

@ -0,0 +1,2 @@
このバージョンの主な変更点: ソーシャルログインに対応しました。
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.15

View File

@ -0,0 +1,2 @@
このバージョンの主な変更点: パフォーマンスの向上とバグの修正!
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.15 and https://github.com/vector-im/element-android/releases/tag/v1.0.16

View File

@ -0,0 +1,2 @@
このバージョンの主な変更点: バグの修正!
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.0.17

View File

@ -0,0 +1,2 @@
このバージョンの主な変更点: パフォーマンスの向上とバグの修正!
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.1.0

View File

@ -0,0 +1,2 @@
このバージョンの主な変更点: パフォーマンスの向上とバグの修正!
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.1.1

View File

@ -0,0 +1,2 @@
このバージョンの主な変更点: パフォーマンスの向上とバグの修正!
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.1.2

View File

@ -0,0 +1,2 @@
このバージョンの主な変更点: パフォーマンスの向上とバグの修正!
すべての変更履歴はこちら: https://github.com/vector-im/element-android/releases/tag/v1.1.3

View File

@ -0,0 +1,30 @@
Elementはまったく新しいタイプのメッセンジャーアプリです。
1. あなた自身がプライバシーをコントロールすることを可能にします。
2. Matrixネットワークにいる誰とでも通信できることはもちろん、Slackなどのアプリとの連携によって他のネットワークとも通信ができます。
3. 広告、データ収集、バックドア、ユーザーの囲い込みから逃れることができます。
4. エンドツーエンド暗号化とクロス署名によってあなたを保護します。
Elementは非中央集権型でオープンソースであるため、他のメッセンジャーアプリとは完全に異なっています。
Elementはあなた自身でサーバーをホストすることも、サーバーを選ぶこともできます。これによってあなたのデータと会話に関するプライバシーや所有権はあなた自身で管理できるようになります。さらに、あなたは他のElementユーザーと話せるだけでなくオープンネットワークへのアクセスも可能です。とてもセキュアです。
Elementは、オープンな分散型通信の標準規格であるMatrixで動作するため、これらすべてを実現することができています。
Elementではあなたの会話をどのサーバーでホストするか決めることができます。アプリでは、さまざまな方法で選択できます。
1. matrix.orgの公開サーバーで無料のアカウントを取得します。
2. あなた自身のハードウェアでサーバーを動かし、アカウントを管理します。
3. Element Matrix Servicesのホスティングプラットフォームに登録することで、カスタムサーバー上のアカウントを取得できます。
<b>なぜElementを選ぶべきなのか</b>
<b>データの所有権</b>: 自分でデータやメッセージを保管する場所を決めることができます。あなたが所有権を持ってコントロールすることで、第三者にあなたのデータを渡したり、ビッグデータを収集する巨大テック企業に依存する必要がなくなります。
<b>開かれたネットワークと共同作業</b>: Matrixネットワーク内の他の誰とでも、あるいはElementや他のMatrixアプリを使っているかどうかに関わらず、またSlack、IRC、XMPPのような他のメッセージングシステムを使っているかどうかに関わらず、チャットすることができます。
<b>はるかに安全</b>: 本物のエンドツーエンド暗号化(会話に参加している者のみがメッセージを読める)と会話参加者の真正性を確認するためクロス署名によって。
<b>完全なるコミュニケーションの訪れ</b>: テキスト、音声通話、ビデオ通話、ファイル共有、画面共有、連携機能、ボット、ウィジェットなどのコミュニケーションに必要な機能の全てが実装されています。ルームやコミュニティを立ち上げて連絡を取り合い、物事をスムーズに成し遂げることができます。
<b>いつでもどこでも!</b>: すべてのデバイスとウェブhttps://app.element.ioでメッセージの履歴が完全に同期されるため、どこにいても連絡を取ることができます。

View File

@ -0,0 +1 @@
安全な分散型チャットとVoIP。あなたの情報が第三者から守られます。

View File

@ -0,0 +1 @@
Elementエレメントメッセンジャー

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: URL-forhåndsvisning, nytt Emoji-tastatur, nye rominnstillingsmuligheter og snø til jul!
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.12

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: URL-forhåndsvisning, nytt Emoji-tastatur, nye rominnstillingsmuligheter og snø til jul!
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.13

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: Rediger romtillatelser, automatisk lys/mørkt tema og en haug med feilrettinger.
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.14

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: Sosial innloggingsstøtte.
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.15

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: Sosial innloggingsstøtte.
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.15 og https://github.com/vector-im/element-android/releases/tag/v1.0.16

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: Feilrettinger!
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.17

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: forbedring av VoIP (lyd og videosamtaler i DM) og feilrettinger!
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.0

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: forbedring av ytelsen og feilrettinger!
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.1

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: forbedring av ytelsen og feilrettinger!
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.2

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: forbedring av ytelsen og feilrettinger!
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.3

View File

@ -0,0 +1,30 @@
Element er en ny type messenger og samarbeidsapp som:
1. Gir deg kontrollen for å bevare personvernet ditt
2. Lar deg kommunisere med hvem som helst i Matrix-nettverket, og til og med ved å integrere med apper som Slack
3. Beskytter deg mot reklame, datamining og inngjerdede hager
4. Sikrer deg gjennom end-to-end-kryptering, med kryssignering for å bekrefte andre
Element er helt forskjellig fra andre meldings- og samarbeidsapper fordi det er desentralisert og åpen kildekode.
Element lar deg selv være vert - eller velge en vert - slik at du har personvern, eierskap og kontroll over dataene og samtalene dine. Det gir deg tilgang til et åpent nettverk; slik at du ikke bare holder på å snakke med bare andre Element-brukere. Og det er veldig sikkert.
Element er i stand til å gjøre alt dette fordi det opererer på Matrix - standarden for åpen, desentralisert kommunikasjon.
Element setter deg i kontroll ved å la deg velge hvem som er vert for samtalene dine. Fra Element-appen kan du velge å være vert på forskjellige måter:
1. Få en gratis konto på matrix.org-serveren som er vert for Matrix-utviklerne, eller velg blant tusenvis av offentlige servere som er vert for frivillige
2. Vær vert for kontoen din ved å kjøre en server på din egen maskinvare
3. Registrer deg for en konto på en tilpasset server ved å bare abonnere på Hosting Matrix Services-vertsplattformen
<b> Hvorfor velge Element? </b>
<b> EGNE DATA DINE </b>: Du bestemmer hvor du vil oppbevare dataene og meldingene dine. Du eier den og kontrollerer den, ikke noe MEGACORP som utvinner dataene dine eller gir tilgang til tredjeparter.
<b> ÅPEN MELDING OG SAMARBEID </b>: Du kan chatte med alle andre i Matrix-nettverket, enten de bruker Element eller en annen Matrix-app, og selv om de bruker et annet meldingssystem som Slack, IRC eller XMPP.
<b> SUPER-SECURE </b>: Ekte end-to-end-kryptering (bare de i samtalen kan dekryptere meldinger), og kryssignering for å verifisere enhetene til samtaledeltakerne.
<b> KOMPLETT KOMMUNIKASJON </b>: Meldinger, tale- og videosamtaler, fildeling, skjermdeling og en hel haug med integrasjoner, bots og widgets. Bygg rom, lokalsamfunn, hold kontakten og få ting gjort.
<b> ALT DER DU ER </b>: Hold kontakten uansett hvor du er med fullt synkronisert meldingslogg på alle enhetene dine og på nettet på https://app.element.io.

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: Bugfikser!
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.0.17

View File

@ -0,0 +1,2 @@
Hovedendringene i denne versjonen: Forbedringer i ytelse og bugfikser!
Full endringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.1

View File

@ -0,0 +1,2 @@
Основные изменения в этой версии: улучшение производительности и исправления ошибок!
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.2

View File

@ -0,0 +1,2 @@
Основные изменения в этой версии: улучшение производительности и исправления ошибок!
Полный список изменений: https://github.com/vector-im/element-android/releases/tag/v1.1.3

View File

@ -0,0 +1,2 @@
Huvudsakliga ändringar i den här versionen: prestandaförbättringar och buggfixar!
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.2

View File

@ -0,0 +1,2 @@
Huvudsakliga ändringar i den här versionen: prestandaförbättringar och buggfixar!
Full ändringslogg: https://github.com/vector-im/element-android/releases/tag/v1.1.3

View File

@ -0,0 +1,2 @@
Основні зміни в цій версії: поліпшення продуктивності та виправлення помилок!
Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.1.2

View File

@ -0,0 +1,2 @@
Основні зміни в цій версії: поліпшення продуктивності та виправлення помилок!
Повний журнал змін: https://github.com/vector-im/element-android/releases/tag/v1.1.3

View File

@ -0,0 +1,2 @@
此版本中的主要變更:效能改進與錯誤修復!
完整變更紀錄https://github.com/vector-im/element-android/releases/tag/v1.1.2

View File

@ -0,0 +1,2 @@
此版本中的主要變更:效能改進與錯誤修復!
完整變更紀錄https://github.com/vector-im/element-android/releases/tag/v1.1.3

View File

@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams
import org.matrix.android.sdk.api.session.sync.SyncState
import org.matrix.android.sdk.api.session.user.model.User
import org.matrix.android.sdk.api.session.widgets.model.Widget
@ -66,6 +67,13 @@ class RxSession(private val session: Session) {
}
}
fun liveSpaceSummaries(queryParams: SpaceSummaryQueryParams): Observable<List<RoomSummary>> {
return session.spaceService().getSpaceSummariesLive(queryParams).asObservable()
.startWithCallable {
session.spaceService().getSpaceSummaries(queryParams)
}
}
fun liveBreadcrumbs(queryParams: RoomSummaryQueryParams): Observable<List<RoomSummary>> {
return session.getBreadcrumbsLive(queryParams).asObservable()
.startWithCallable {

View File

@ -6,13 +6,10 @@ apply plugin: 'realm-android'
buildscript {
repositories {
// mavenCentral()
//noinspection GrDeprecatedAPIUsage
jcenter()
mavenCentral()
}
dependencies {
// Stick to this version until https://github.com/realm/realm-java/issues/7402 is fixed
classpath "io.realm:realm-gradle-plugin:10.3.1"
classpath "io.realm:realm-gradle-plugin:10.4.0"
}
}
@ -168,8 +165,11 @@ dependencies {
implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'com.facebook.stetho:stetho-okhttp3:1.6.0'
// Video compression
implementation 'com.otaliastudios:transcoder:0.10.3'
// Phone number https://github.com/google/libphonenumber
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.21'
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.22'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.5.1'
@ -187,7 +187,7 @@ dependencies {
androidTestImplementation 'androidx.test:rules:1.3.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'org.amshove.kluent:kluent-android:1.61'
androidTestImplementation 'org.amshove.kluent:kluent-android:1.65'
androidTestImplementation 'io.mockk:mockk-android:1.11.0'
androidTestImplementation "androidx.arch.core:core-testing:$arch_version"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"

View File

@ -18,6 +18,8 @@ package org.matrix.android.sdk.internal.crypto
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@ -29,8 +31,6 @@ import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
import org.matrix.android.sdk.internal.crypto.model.event.RoomKeyContent
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
@ -54,7 +54,7 @@ class PreShareKeysTest : InstrumentedTest {
&& it.getClearType() == EventType.ROOM_KEY
}
assertEquals(0, preShareCount, "Bob should not have receive any key from alice at this point")
assertEquals("Bob should not have receive any key from alice at this point", 0, preShareCount)
Log.d("#Test", "Room Key Received from alice $preShareCount")
// Force presharing of new outbound key
@ -78,14 +78,14 @@ class PreShareKeysTest : InstrumentedTest {
}
val content = latest?.getClearContent().toModel<RoomKeyContent>()
assertNotNull(content, "Bob should have received and decrypted a room key event from alice")
assertEquals(e2eRoomID, content.roomId, "Wrong room")
assertNotNull("Bob should have received and decrypted a room key event from alice", content)
assertEquals("Wrong room", e2eRoomID, content!!.roomId)
val megolmSessionId = content.sessionId!!
val sharedIndex = aliceSession.cryptoService().getSharedWithInfo(e2eRoomID, megolmSessionId)
.getObject(bobSession.myUserId, bobSession.sessionParams.deviceId)
assertEquals(0, sharedIndex, "The session received by bob should match what alice sent")
assertEquals("The session received by bob should match what alice sent", 0, sharedIndex)
// Just send a real message as test
val sentEvent = mTestHelper.sendTextMessage(aliceSession.getRoom(e2eRoomID)!!, "Allo", 1).first()

View File

@ -16,6 +16,7 @@
package org.matrix.android.sdk.session.room.timeline
import org.junit.Assert.fail
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@ -29,7 +30,6 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import java.util.concurrent.CountDownLatch
import kotlin.test.fail
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
@ -80,6 +80,7 @@ class TimelineWithManyMembersTest : InstrumentedTest {
return@createEventListener true
} else {
fail("User " + session.myUserId + " decrypted as " + body + " CryptoError: " + it.root.mCryptoError)
false
}
} ?: return@createEventListener false
}

View File

@ -0,0 +1,222 @@
/*
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.session.space
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.session.space.JoinSpaceResult
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.SessionTestParams
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class SpaceCreationTest : InstrumentedTest {
private val commonTestHelper = CommonTestHelper(context())
@Test
fun createSimplePublicSpace() {
val session = commonTestHelper.createAccount("Hubble", SessionTestParams(true))
val roomName = "My Space"
val topic = "A public space for test"
var spaceId: String = ""
commonTestHelper.waitWithLatch {
GlobalScope.launch {
spaceId = session.spaceService().createSpace(roomName, topic, null, true)
// wait a bit to let the summary update it self :/
it.countDown()
}
}
val syncedSpace = session.spaceService().getSpace(spaceId)
commonTestHelper.waitWithLatch {
commonTestHelper.retryPeriodicallyWithLatch(it) {
syncedSpace?.asRoom()?.roomSummary()?.name != null
}
}
assertEquals("Room name should be set", roomName, syncedSpace?.asRoom()?.roomSummary()?.name)
assertEquals("Room topic should be set", topic, syncedSpace?.asRoom()?.roomSummary()?.topic)
// assertEquals(topic, syncedSpace.asRoom().roomSummary()?., "Room topic should be set")
assertNotNull("Space should be found by Id", syncedSpace)
val creationEvent = syncedSpace!!.asRoom().getStateEvent(EventType.STATE_ROOM_CREATE)
val createContent = creationEvent?.content.toModel<RoomCreateContent>()
assertEquals("Room type should be space", RoomType.SPACE, createContent?.type)
var powerLevelsContent: PowerLevelsContent? = null
commonTestHelper.waitWithLatch { latch ->
commonTestHelper.retryPeriodicallyWithLatch(latch) {
val toModel = syncedSpace.asRoom().getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)?.content.toModel<PowerLevelsContent>()
powerLevelsContent = toModel
toModel != null
}
}
assertEquals("Space-rooms should be created with a power level for events_default of 100", 100, powerLevelsContent?.eventsDefault)
val guestAccess = syncedSpace.asRoom().getStateEvent(EventType.STATE_ROOM_GUEST_ACCESS)?.content
?.toModel<RoomGuestAccessContent>()?.guestAccess
assertEquals("Public space room should be peekable by guest", GuestAccess.CanJoin, guestAccess)
val historyVisibility = syncedSpace.asRoom().getStateEvent(EventType.STATE_ROOM_HISTORY_VISIBILITY)?.content
?.toModel<RoomHistoryVisibilityContent>()?.historyVisibility
assertEquals("Public space room should be world readable", RoomHistoryVisibility.WORLD_READABLE, historyVisibility)
commonTestHelper.signOutAndClose(session)
}
@Test
fun testJoinSimplePublicSpace() {
val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
val bobSession = commonTestHelper.createAccount("bob", SessionTestParams(true))
val roomName = "My Space"
val topic = "A public space for test"
val spaceId: String
runBlocking {
spaceId = aliceSession.spaceService().createSpace(roomName, topic, null, true)
// wait a bit to let the summary update it self :/
delay(400)
}
// Try to join from bob, it's a public space no need to invite
val joinResult: JoinSpaceResult
runBlocking {
joinResult = bobSession.spaceService().joinSpace(spaceId)
}
assertEquals(JoinSpaceResult.Success, joinResult)
val spaceBobPov = bobSession.spaceService().getSpace(spaceId)
assertEquals("Room name should be set", roomName, spaceBobPov?.asRoom()?.roomSummary()?.name)
assertEquals("Room topic should be set", topic, spaceBobPov?.asRoom()?.roomSummary()?.topic)
commonTestHelper.signOutAndClose(aliceSession)
commonTestHelper.signOutAndClose(bobSession)
}
@Test
fun testSimplePublicSpaceWithChildren() {
val aliceSession = commonTestHelper.createAccount("alice", SessionTestParams(true))
val bobSession = commonTestHelper.createAccount("bob", SessionTestParams(true))
val roomName = "My Space"
val topic = "A public space for test"
val spaceId: String = runBlocking { aliceSession.spaceService().createSpace(roomName, topic, null, true) }
val syncedSpace = aliceSession.spaceService().getSpace(spaceId)
// create a room
var firstChild: String? = null
commonTestHelper.waitWithLatch {
GlobalScope.launch {
firstChild = aliceSession.createRoom(CreateRoomParams().apply {
this.name = "FirstRoom"
this.topic = "Description of first room"
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
})
it.countDown()
}
}
commonTestHelper.waitWithLatch {
GlobalScope.launch {
syncedSpace?.addChildren(firstChild!!, listOf(aliceSession.sessionParams.homeServerHost ?: ""), "a", true, suggested = true)
it.countDown()
}
}
var secondChild: String? = null
commonTestHelper.waitWithLatch {
GlobalScope.launch {
secondChild = aliceSession.createRoom(CreateRoomParams().apply {
this.name = "SecondRoom"
this.topic = "Description of second room"
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
})
it.countDown()
}
}
commonTestHelper.waitWithLatch {
GlobalScope.launch {
syncedSpace?.addChildren(secondChild!!, listOf(aliceSession.sessionParams.homeServerHost ?: ""), "b", false, suggested = true)
it.countDown()
}
}
// Try to join from bob, it's a public space no need to invite
var joinResult: JoinSpaceResult? = null
commonTestHelper.waitWithLatch {
GlobalScope.launch {
joinResult = bobSession.spaceService().joinSpace(spaceId)
// wait a bit to let the summary update it self :/
it.countDown()
}
}
assertEquals(JoinSpaceResult.Success, joinResult)
val spaceBobPov = bobSession.spaceService().getSpace(spaceId)
assertEquals("Room name should be set", roomName, spaceBobPov?.asRoom()?.roomSummary()?.name)
assertEquals("Room topic should be set", topic, spaceBobPov?.asRoom()?.roomSummary()?.topic)
// check if bob has joined automatically the first room
val bobMembershipFirstRoom = bobSession.getRoomSummary(firstChild!!)?.membership
assertEquals("Bob should have joined this room", Membership.JOIN, bobMembershipFirstRoom)
RoomSummaryQueryParams.Builder()
val childCount = bobSession.getRoomSummaries(
roomSummaryQueryParams {
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(spaceId)
}
).size
assertEquals("Unexpected number of joined children", 1, childCount)
commonTestHelper.signOutAndClose(aliceSession)
commonTestHelper.signOutAndClose(bobSession)
}
}

View File

@ -0,0 +1,472 @@
/*
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.session.space
import android.util.Log
import androidx.lifecycle.Observer
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.SessionTestParams
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class SpaceHierarchyTest : InstrumentedTest {
private val commonTestHelper = CommonTestHelper(context())
@Test
fun createCanonicalChildRelation() {
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
val spaceName = "My Space"
val topic = "A public space for test"
var spaceId: String = ""
commonTestHelper.waitWithLatch {
GlobalScope.launch {
spaceId = session.spaceService().createSpace(spaceName, topic, null, true)
it.countDown()
}
}
val syncedSpace = session.spaceService().getSpace(spaceId)
var roomId: String = ""
commonTestHelper.waitWithLatch {
GlobalScope.launch {
roomId = session.createRoom(CreateRoomParams().apply { name = "General" })
it.countDown()
}
}
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
commonTestHelper.waitWithLatch {
GlobalScope.launch {
syncedSpace!!.addChildren(roomId, viaServers, null, true)
it.countDown()
}
}
commonTestHelper.waitWithLatch {
GlobalScope.launch {
session.spaceService().setSpaceParent(roomId, spaceId, true, viaServers)
it.countDown()
}
}
Thread.sleep(9000)
val parents = session.getRoom(roomId)?.roomSummary()?.spaceParents
val canonicalParents = session.getRoom(roomId)?.roomSummary()?.spaceParents?.filter { it.canonical == true }
parents?.forEach {
Log.d("## TEST", "parent : $it")
}
assertNotNull(parents)
assertEquals(1, parents!!.size)
assertEquals(spaceName, parents.first().roomSummary?.name)
assertNotNull(canonicalParents)
assertEquals(1, canonicalParents!!.size)
assertEquals(spaceName, canonicalParents.first().roomSummary?.name)
}
// @Test
// fun testCreateChildRelations() {
// val session = commonTestHelper.createAccount("Jhon", SessionTestParams(true))
// val spaceName = "My Space"
// val topic = "A public space for test"
// Log.d("## TEST", "Before")
//
// var spaceId = ""
// commonTestHelper.waitWithLatch {
// GlobalScope.launch {
// spaceId = session.spaceService().createSpace(spaceName, topic, null, true)
// it.countDown()
// }
// }
//
// Log.d("## TEST", "created space $spaceId ${Thread.currentThread()}")
// val syncedSpace = session.spaceService().getSpace(spaceId)
//
// val children = listOf("General" to true /*canonical*/, "Random" to false)
//
// // val roomIdList = children.map {
// // runBlocking {
// // session.createRoom(CreateRoomParams().apply { name = it.first })
// // } to it.second
// // }
// val roomIdList = mutableListOf<Pair<String, Boolean>>()
// commonTestHelper.waitWithLatch {
// GlobalScope.launch {
// children.forEach {
// val rID = session.createRoom(CreateRoomParams().apply { name = it.first })
// roomIdList.add(rID to it.second)
// }
// it.countDown()
// }
// }
//
// val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
//
// commonTestHelper.waitWithLatch {
// GlobalScope.launch {
// roomIdList.forEach { entry ->
// syncedSpace!!.addChildren(entry.first, viaServers, null, true)
// }
// it.countDown()
// }
// }
//
// commonTestHelper.waitWithLatch {
// GlobalScope.launch {
// roomIdList.forEach {
// session.spaceService().setSpaceParent(it.first, spaceId, it.second, viaServers)
// }
// it.countDown()
// }
// }
//
// roomIdList.forEach {
// val parents = session.getRoom(it.first)?.roomSummary()?.spaceParents
// val canonicalParents = session.getRoom(it.first)?.roomSummary()?.spaceParents?.filter { it.canonical == true }
//
// assertNotNull(parents)
// assertEquals("Unexpected number of parent", 1, parents!!.size)
// assertEquals("Unexpected parent name", spaceName, parents.first().roomSummary?.name)
// assertEquals("Parent of ${it.first} should be canonical ${it.second}", if (it.second) 1 else 0, canonicalParents?.size ?: 0)
// }
// }
@Test
fun testFilteringBySpace() {
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
Triple("A1", true /*auto-join*/, true/*canonical*/),
Triple("A2", true, true)
))
val spaceBInfo = createPublicSpace(session, "SpaceB", listOf(
Triple("B1", true /*auto-join*/, true/*canonical*/),
Triple("B2", true, true),
Triple("B3", true, true)
))
val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
Triple("C1", true /*auto-join*/, true/*canonical*/),
Triple("C2", true, true)
))
// add C as a subspace of A
val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
commonTestHelper.waitWithLatch {
GlobalScope.launch {
spaceA!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
session.spaceService().setSpaceParent(spaceCInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
it.countDown()
}
}
// Create orphan rooms
var orphan1 = ""
commonTestHelper.waitWithLatch {
GlobalScope.launch {
orphan1 = session.createRoom(CreateRoomParams().apply { name = "O1" })
it.countDown()
}
}
var orphan2 = ""
commonTestHelper.waitWithLatch {
GlobalScope.launch {
orphan2 = session.createRoom(CreateRoomParams().apply { name = "O2" })
it.countDown()
}
}
val allRooms = session.getRoomSummaries(roomSummaryQueryParams { excludeType = listOf(RoomType.SPACE) })
assertEquals("Unexpected number of rooms", 9, allRooms.size)
val orphans = session.getFlattenRoomSummaryChildrenOf(null)
assertEquals("Unexpected number of orphan rooms", 2, orphans.size)
assertTrue("O1 should be an orphan", orphans.any { it.roomId == orphan1 })
assertTrue("O2 should be an orphan ${orphans.map { it.name }}", orphans.any { it.roomId == orphan2 })
val aChildren = session.getFlattenRoomSummaryChildrenOf(spaceAInfo.spaceId)
assertEquals("Unexpected number of flatten child rooms", 4, aChildren.size)
assertTrue("A1 should be a child of A", aChildren.any { it.name == "A1" })
assertTrue("A2 should be a child of A", aChildren.any { it.name == "A2" })
assertTrue("CA should be a grand child of A", aChildren.any { it.name == "C1" })
assertTrue("A1 should be a grand child of A", aChildren.any { it.name == "C2" })
// Add a non canonical child and check that it does not appear as orphan
commonTestHelper.waitWithLatch {
GlobalScope.launch {
val a3 = session.createRoom(CreateRoomParams().apply { name = "A3" })
spaceA!!.addChildren(a3, viaServers, null, false)
it.countDown()
}
}
Thread.sleep(2_000)
val orphansUpdate = session.getRoomSummaries(roomSummaryQueryParams {
activeSpaceFilter = ActiveSpaceFilter.ActiveSpace(null)
})
assertEquals("Unexpected number of orphan rooms ${orphansUpdate.map { it.name }}", 2, orphansUpdate.size)
}
@Test
fun testBreakCycle() {
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
Triple("A1", true /*auto-join*/, true/*canonical*/),
Triple("A2", true, true)
))
val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
Triple("C1", true /*auto-join*/, true/*canonical*/),
Triple("C2", true, true)
))
// add C as a subspace of A
val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
commonTestHelper.waitWithLatch {
GlobalScope.launch {
spaceA!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
session.spaceService().setSpaceParent(spaceCInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
it.countDown()
}
}
// add back A as subspace of C
commonTestHelper.waitWithLatch {
GlobalScope.launch {
val spaceC = session.spaceService().getSpace(spaceCInfo.spaceId)
spaceC!!.addChildren(spaceAInfo.spaceId, viaServers, null, true)
it.countDown()
}
}
Thread.sleep(1000)
// A -> C -> A
val aChildren = session.getFlattenRoomSummaryChildrenOf(spaceAInfo.spaceId)
assertEquals("Unexpected number of flatten child rooms ${aChildren.map { it.name }}", 4, aChildren.size)
assertTrue("A1 should be a child of A", aChildren.any { it.name == "A1" })
assertTrue("A2 should be a child of A", aChildren.any { it.name == "A2" })
assertTrue("CA should be a grand child of A", aChildren.any { it.name == "C1" })
assertTrue("A1 should be a grand child of A", aChildren.any { it.name == "C2" })
}
@Test
fun testLiveFlatChildren() {
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
Triple("A1", true /*auto-join*/, true/*canonical*/),
Triple("A2", true, true)
))
val spaceBInfo = createPublicSpace(session, "SpaceB", listOf(
Triple("B1", true /*auto-join*/, true/*canonical*/),
Triple("B2", true, true),
Triple("B3", true, true)
))
// add B as a subspace of A
val spaceA = session.spaceService().getSpace(spaceAInfo.spaceId)
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
runBlocking {
spaceA!!.addChildren(spaceBInfo.spaceId, viaServers, null, true)
session.spaceService().setSpaceParent(spaceBInfo.spaceId, spaceAInfo.spaceId, true, viaServers)
}
val flatAChildren = runBlocking(Dispatchers.Main) {
session.getFlattenRoomSummaryChildrenOfLive(spaceAInfo.spaceId)
}
commonTestHelper.waitWithLatch { latch ->
val childObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(children: List<RoomSummary>?) {
// Log.d("## TEST", "Space A flat children update : ${children?.map { it.name }}")
System.out.println("## TEST | Space A flat children update : ${children?.map { it.name }}")
if (children?.any { it.name == "C1" } == true && children.any { it.name == "C2" }) {
// B1 has been added live!
latch.countDown()
flatAChildren.removeObserver(this)
}
}
}
val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
Triple("C1", true /*auto-join*/, true/*canonical*/),
Triple("C2", true, true)
))
// add C as subspace of B
runBlocking {
val spaceB = session.spaceService().getSpace(spaceBInfo.spaceId)
spaceB!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
}
// C1 and C2 should be in flatten child of A now
GlobalScope.launch(Dispatchers.Main) { flatAChildren.observeForever(childObserver) }
}
// Test part one of the rooms
val bRoomId = spaceBInfo.roomIds.first()
val bRoom = session.getRoom(bRoomId)
commonTestHelper.waitWithLatch { latch ->
val childObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(children: List<RoomSummary>?) {
System.out.println("## TEST | Space A flat children update : ${children?.map { it.name }}")
if (children?.any { it.roomId == bRoomId } == false) {
// B1 has been added live!
latch.countDown()
flatAChildren.removeObserver(this)
}
}
}
// part from b room
runBlocking {
bRoom!!.leave(null)
}
// The room should have disapear from flat children
GlobalScope.launch(Dispatchers.Main) { flatAChildren.observeForever(childObserver) }
}
}
data class TestSpaceCreationResult(
val spaceId: String,
val roomIds: List<String>
)
private fun createPublicSpace(session: Session,
spaceName: String,
childInfo: List<Triple<String, Boolean, Boolean?>>
/** Name, auto-join, canonical*/
): TestSpaceCreationResult {
var spaceId = ""
commonTestHelper.waitWithLatch {
GlobalScope.launch {
spaceId = session.spaceService().createSpace(spaceName, "Test Topic", null, true)
it.countDown()
}
}
val syncedSpace = session.spaceService().getSpace(spaceId)
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
val roomIds =
childInfo.map { entry ->
var roomId = ""
commonTestHelper.waitWithLatch {
GlobalScope.launch {
roomId = session.createRoom(CreateRoomParams().apply { name = entry.first })
it.countDown()
}
}
roomId
}
roomIds.forEachIndexed { index, roomId ->
runBlocking {
syncedSpace!!.addChildren(roomId, viaServers, null, childInfo[index].second)
val canonical = childInfo[index].third
if (canonical != null) {
session.spaceService().setSpaceParent(roomId, spaceId, canonical, viaServers)
}
}
}
return TestSpaceCreationResult(spaceId, roomIds)
}
@Test
fun testRootSpaces() {
val session = commonTestHelper.createAccount("John", SessionTestParams(true))
val spaceAInfo = createPublicSpace(session, "SpaceA", listOf(
Triple("A1", true /*auto-join*/, true/*canonical*/),
Triple("A2", true, true)
))
val spaceBInfo = createPublicSpace(session, "SpaceB", listOf(
Triple("B1", true /*auto-join*/, true/*canonical*/),
Triple("B2", true, true),
Triple("B3", true, true)
))
val spaceCInfo = createPublicSpace(session, "SpaceC", listOf(
Triple("C1", true /*auto-join*/, true/*canonical*/),
Triple("C2", true, true)
))
val viaServers = listOf(session.sessionParams.homeServerHost ?: "")
// add C as subspace of B
runBlocking {
val spaceB = session.spaceService().getSpace(spaceBInfo.spaceId)
spaceB!!.addChildren(spaceCInfo.spaceId, viaServers, null, true)
}
Thread.sleep(2000)
// + A
// a1, a2
// + B
// b1, b2, b3
// + C
// + c1, c2
val rootSpaces = session.spaceService().getRootSpaceSummaries()
assertEquals("Unexpected number of root spaces ${rootSpaces.map { it.name }}", 2, rootSpaces.size)
}
}

View File

@ -41,7 +41,7 @@ data class MatrixError(
// For M_LIMIT_EXCEEDED
@Json(name = "retry_after_ms") val retryAfterMillis: Long? = null,
// For M_UNKNOWN_TOKEN
@Json(name = "soft_logout") val isSoftLogout: Boolean = false,
@Json(name = "soft_logout") val isSoftLogout: Boolean? = null,
// For M_INVALID_PEPPER
// {"error": "pepper does not match 'erZvr'", "lookup_pepper": "pQgMS", "algorithm": "sha256", "errcode": "M_INVALID_PEPPER"}
@Json(name = "lookup_pepper") val newLookupPepper: String? = null,

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.query
sealed class ActiveSpaceFilter {
object None : ActiveSpaceFilter()
data class ActiveSpace(val currentSpaceId: String?) : ActiveSpaceFilter()
data class ExcludeSpace(val spaceId: String) : ActiveSpaceFilter()
}

View File

@ -48,6 +48,7 @@ import org.matrix.android.sdk.api.session.search.SearchService
import org.matrix.android.sdk.api.session.securestorage.SecureStorageService
import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService
import org.matrix.android.sdk.api.session.signout.SignOutService
import org.matrix.android.sdk.api.session.space.SpaceService
import org.matrix.android.sdk.api.session.sync.FilterService
import org.matrix.android.sdk.api.session.sync.SyncState
import org.matrix.android.sdk.api.session.terms.TermsService
@ -227,6 +228,11 @@ interface Session :
*/
fun thirdPartyService(): ThirdPartyService
/**
* Returns the space service associated with the session
*/
fun spaceService(): SpaceService
/**
* Add a listener to the session.
* @param listener the listener to add.
@ -249,13 +255,13 @@ interface Session :
/**
* A global session listener to get notified for some events.
*/
interface Listener {
interface Listener : SessionLifecycleObserver {
/**
* Possible cases:
* - The access token is not valid anymore,
* - a M_CONSENT_NOT_GIVEN error has been received from the homeserver
*/
fun onGlobalError(globalError: GlobalError)
fun onGlobalError(session: Session, globalError: GlobalError)
}
val sharedSecretStorageService: SharedSecretStorageService

View File

@ -14,20 +14,19 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session
package org.matrix.android.sdk.api.session
import androidx.annotation.MainThread
/**
* This defines methods associated with some lifecycle events of a session.
* A list of SessionLifecycle will be injected into [DefaultSession]
*/
internal interface SessionLifecycleObserver {
interface SessionLifecycleObserver {
/*
Called when the session is opened
*/
@MainThread
fun onSessionStarted() {
fun onSessionStarted(session: Session) {
// noop
}
@ -35,7 +34,7 @@ internal interface SessionLifecycleObserver {
Called when the session is cleared
*/
@MainThread
fun onClearCache() {
fun onClearCache(session: Session) {
// noop
}
@ -43,7 +42,7 @@ internal interface SessionLifecycleObserver {
Called when the session is closed
*/
@MainThread
fun onSessionStopped() {
fun onSessionStopped(session: Session) {
// noop
}
}

View File

@ -31,6 +31,8 @@ interface ContentUploadStateTracker {
sealed class State {
object Idle : State()
object EncryptingThumbnail : State()
object CompressingImage : State()
data class CompressingVideo(val percent: Float) : State()
data class UploadingThumbnail(val current: Long, val total: Long) : State()
data class Encrypting(val current: Long, val total: Long) : State()
data class Uploading(val current: Long, val total: Long) : State()

View File

@ -28,6 +28,8 @@ import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.json.JSONObject
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.failure.MatrixError
import timber.log.Timber
typealias Content = JsonDict
@ -90,6 +92,16 @@ data class Event(
@Transient
var sendState: SendState = SendState.UNKNOWN
@Transient
var sendStateDetails: String? = null
fun sendStateError(): MatrixError? {
return sendStateDetails?.let {
val matrixErrorAdapter = MoshiProvider.providesMoshi().adapter(MatrixError::class.java)
tryOrNull { matrixErrorAdapter.fromJson(it) }
}
}
/**
* The `age` value transcoded in a timestamp based on the device clock when the SDK received
* the event from the home server.

View File

@ -52,6 +52,10 @@ object EventType {
const val STATE_ROOM_GUEST_ACCESS = "m.room.guest_access"
const val STATE_ROOM_POWER_LEVELS = "m.room.power_levels"
const val STATE_SPACE_CHILD = "m.space.child"
const val STATE_SPACE_PARENT = "m.space.parent"
/**
* Note that this Event has been deprecated, see
* - https://matrix.org/docs/spec/client_server/r0.6.1#historical-events
@ -74,6 +78,7 @@ object EventType {
const val CALL_NEGOTIATE = "m.call.negotiate"
const val CALL_REJECT = "m.call.reject"
const val CALL_HANGUP = "m.call.hangup"
// This type is not processed by the client, just sent to the server
const val CALL_REPLACES = "m.call.replaces"

View File

@ -29,14 +29,19 @@ import java.io.File
*/
interface FileService {
enum class FileState {
IN_CACHE,
DOWNLOADING,
UNKNOWN
sealed class FileState {
/**
* The original file is in cache, but the decrypted files can be deleted for security reason.
* To decrypt the file again, call [downloadFile], the encrypted file will not be downloaded again
* @param decryptedFileInCache true if the decrypted file is available. Always true for clear files.
*/
data class InCache(val decryptedFileInCache: Boolean) : FileState()
object Downloading : FileState()
object Unknown : FileState()
}
/**
* Download a file.
* Download a file if necessary and ensure that if the file is encrypted, the file is decrypted.
* Result will be a decrypted file, stored in the cache folder. url parameter will be used to create unique filename to avoid name collision.
*/
suspend fun downloadFile(fileName: String,

View File

@ -66,6 +66,7 @@ interface ProfileService {
/**
* Get the combined profile information for this user.
* This may return keys which are not limited to displayname or avatar_url.
* If server is configured as limit_profile_requests_to_users_who_share_rooms: true then response can be HTTP 403.
* @param userId the userId param to look for
*
*/

View File

@ -66,12 +66,13 @@ interface PushersService {
/**
* Directly ask the push gateway to send a push to this device
* If successful, the push gateway has accepted the request. In this case, the app should receive a Push with the provided eventId.
* In case of error, PusherRejected will be thrown. In this case it means that the pushkey is not valid.
*
* @param url the push gateway url (full path)
* @param appId the application id
* @param pushkey the FCM token
* @param eventId the eventId which will be sent in the Push message. Use a fake eventId.
* @param callback callback to know if the push gateway has accepted the request. In this case, the app should receive a Push with the provided eventId.
* In case of error, PusherRejected failure can happen. In this case it means that the pushkey is not valid.
*/
suspend fun testPush(url: String,
appId: String,

View File

@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineService
import org.matrix.android.sdk.api.session.room.typing.TypingService
import org.matrix.android.sdk.api.session.room.uploads.UploadsService
import org.matrix.android.sdk.api.session.search.SearchResult
import org.matrix.android.sdk.api.session.space.Space
import org.matrix.android.sdk.api.util.Optional
/**
@ -91,4 +92,9 @@ interface Room :
beforeLimit: Int,
afterLimit: Int,
includeProfile: Boolean): SearchResult
/**
* Use this room as a Space, if the type is correct.
*/
fun asSpace(): Space?
}

View File

@ -20,6 +20,7 @@ import androidx.lifecycle.LiveData
import androidx.paging.PagedList
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
@ -177,13 +178,15 @@ interface RoomService {
* TODO Doc
*/
fun getPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
pagedListConfig: PagedList.Config = defaultPagedListConfig): LiveData<PagedList<RoomSummary>>
pagedListConfig: PagedList.Config = defaultPagedListConfig,
sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): LiveData<PagedList<RoomSummary>>
/**
* TODO Doc
*/
fun getFilteredPagedRoomSummariesLive(queryParams: RoomSummaryQueryParams,
pagedListConfig: PagedList.Config = defaultPagedListConfig): UpdatableFilterLivePageResult
pagedListConfig: PagedList.Config = defaultPagedListConfig,
sortOrder: RoomSortOrder = RoomSortOrder.ACTIVITY): UpdatableLivePageResult
/**
* TODO Doc
@ -197,4 +200,12 @@ interface RoomService {
.setEnablePlaceholders(false)
.setPrefetchDistance(10)
.build()
fun getFlattenRoomSummaryChildrenOf(spaceId: String?, memberships: List<Membership> = Membership.activeMemberships()) : List<RoomSummary>
/**
* Returns all the children of this space, as LiveData
*/
fun getFlattenRoomSummaryChildrenOfLive(spaceId: String?,
memberships: List<Membership> = Membership.activeMemberships()): LiveData<List<RoomSummary>>
}

View File

@ -0,0 +1,23 @@
/*
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.room
enum class RoomSortOrder {
NAME,
ACTIVITY,
NONE
}

View File

@ -16,15 +16,35 @@
package org.matrix.android.sdk.api.session.room
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.RoomCategoryFilter
import org.matrix.android.sdk.api.query.RoomTagQueryFilter
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams
fun roomSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = {}): RoomSummaryQueryParams {
return RoomSummaryQueryParams.Builder().apply(init).build()
}
fun spaceSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = {}): SpaceSummaryQueryParams {
return RoomSummaryQueryParams.Builder()
.apply(init)
.apply {
includeType = listOf(RoomType.SPACE)
excludeType = null
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
}
.build()
}
enum class RoomCategoryFilter {
ONLY_DM,
ONLY_ROOMS,
ALL
}
/**
* This class can be used to filter room summaries to use with:
* [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService]
@ -35,7 +55,11 @@ data class RoomSummaryQueryParams(
val canonicalAlias: QueryStringValue,
val memberships: List<Membership>,
val roomCategoryFilter: RoomCategoryFilter?,
val roomTagQueryFilter: RoomTagQueryFilter?
val roomTagQueryFilter: RoomTagQueryFilter?,
val excludeType: List<String?>?,
val includeType: List<String?>?,
val activeSpaceFilter: ActiveSpaceFilter?,
var activeGroupId: String? = null
) {
class Builder {
@ -46,6 +70,10 @@ data class RoomSummaryQueryParams(
var memberships: List<Membership> = Membership.all()
var roomCategoryFilter: RoomCategoryFilter? = RoomCategoryFilter.ALL
var roomTagQueryFilter: RoomTagQueryFilter? = null
var excludeType: List<String?>? = listOf(RoomType.SPACE)
var includeType: List<String?>? = null
var activeSpaceFilter: ActiveSpaceFilter = ActiveSpaceFilter.None
var activeGroupId: String? = null
fun build() = RoomSummaryQueryParams(
roomId = roomId,
@ -53,7 +81,11 @@ data class RoomSummaryQueryParams(
canonicalAlias = canonicalAlias,
memberships = memberships,
roomCategoryFilter = roomCategoryFilter,
roomTagQueryFilter = roomTagQueryFilter
roomTagQueryFilter = roomTagQueryFilter,
excludeType = excludeType,
includeType = includeType,
activeSpaceFilter = activeSpaceFilter,
activeGroupId = activeGroupId
)
}
}

View File

@ -20,8 +20,16 @@ import androidx.lifecycle.LiveData
import androidx.paging.PagedList
import org.matrix.android.sdk.api.session.room.model.RoomSummary
interface UpdatableFilterLivePageResult {
interface UpdatableLivePageResult {
val livePagedList: LiveData<PagedList<RoomSummary>>
fun updateQuery(queryParams: RoomSummaryQueryParams)
fun updateQuery(builder: (RoomSummaryQueryParams) -> RoomSummaryQueryParams)
val liveBoundaries: LiveData<ResultBoundaries>
}
data class ResultBoundaries(
val frontLoaded: Boolean = false,
val endLoaded: Boolean = false,
val zeroItemLoaded: Boolean = false
)

View File

@ -17,7 +17,7 @@
package org.matrix.android.sdk.api.session.room.alias
sealed class RoomAliasError : Throwable() {
object AliasEmpty : RoomAliasError()
object AliasIsBlank : RoomAliasError()
object AliasNotAvailable : RoomAliasError()
object AliasInvalid : RoomAliasError()
}

View File

@ -21,7 +21,7 @@ import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.session.room.alias.RoomAliasError
sealed class CreateRoomFailure : Failure.FeatureFailure() {
object CreatedWithTimeout : CreateRoomFailure()
data class CreatedWithTimeout(val roomID: String) : CreateRoomFailure()
data class CreatedWithFederationFailure(val matrixError: MatrixError) : CreateRoomFailure()
data class AliasError(val aliasError: RoomAliasError) : CreateRoomFailure()
}

View File

@ -28,43 +28,43 @@ data class PowerLevelsContent(
/**
* The level required to ban a user. Defaults to 50 if unspecified.
*/
@Json(name = "ban") val ban: Int = Role.Moderator.value,
@Json(name = "ban") val ban: Int? = null,
/**
* The level required to kick a user. Defaults to 50 if unspecified.
*/
@Json(name = "kick") val kick: Int = Role.Moderator.value,
@Json(name = "kick") val kick: Int? = null,
/**
* The level required to invite a user. Defaults to 50 if unspecified.
*/
@Json(name = "invite") val invite: Int = Role.Moderator.value,
@Json(name = "invite") val invite: Int? = null,
/**
* The level required to redact an event. Defaults to 50 if unspecified.
*/
@Json(name = "redact") val redact: Int = Role.Moderator.value,
@Json(name = "redact") val redact: Int? = null,
/**
* The default level required to send message events. Can be overridden by the events key. Defaults to 0 if unspecified.
*/
@Json(name = "events_default") val eventsDefault: Int = Role.Default.value,
@Json(name = "events_default") val eventsDefault: Int? = null,
/**
* The level required to send specific event types. This is a mapping from event type to power level required.
*/
@Json(name = "events") val events: Map<String, Int> = emptyMap(),
@Json(name = "events") val events: Map<String, Int>? = null,
/**
* The default power level for every user in the room, unless their user_id is mentioned in the users key. Defaults to 0 if unspecified.
*/
@Json(name = "users_default") val usersDefault: Int = Role.Default.value,
@Json(name = "users_default") val usersDefault: Int? = null,
/**
* The power levels for specific users. This is a mapping from user_id to power level for that user.
*/
@Json(name = "users") val users: Map<String, Int> = emptyMap(),
@Json(name = "users") val users: Map<String, Int>? = null,
/**
* The default level required to send state events. Can be overridden by the events key. Defaults to 50 if unspecified.
*/
@Json(name = "state_default") val stateDefault: Int = Role.Moderator.value,
@Json(name = "state_default") val stateDefault: Int? = null,
/**
* The power level requirements for specific notification types. This is a mapping from key to power level for that notifications key.
*/
@Json(name = "notifications") val notifications: Map<String, Any> = emptyMap()
@Json(name = "notifications") val notifications: Map<String, Any>? = null
) {
/**
* Return a copy of this content with a new power level for the specified user
@ -74,7 +74,7 @@ data class PowerLevelsContent(
*/
fun setUserPowerLevel(userId: String, powerLevel: Int?): PowerLevelsContent {
return copy(
users = users.toMutableMap().apply {
users = users.orEmpty().toMutableMap().apply {
if (powerLevel == null || powerLevel == usersDefault) {
remove(userId)
} else {
@ -91,7 +91,7 @@ data class PowerLevelsContent(
* @return the level, default to Moderator if the key is not found
*/
fun notificationLevel(key: String): Int {
return when (val value = notifications[key]) {
return when (val value = notifications.orEmpty()[key]) {
// the first implementation was a string value
is String -> value.toInt()
is Double -> value.toInt()
@ -107,3 +107,12 @@ data class PowerLevelsContent(
const val NOTIFICATIONS_ROOM_KEY = "room"
}
}
// Fallback to default value, defined in the Matrix specification
fun PowerLevelsContent.banOrDefault() = ban ?: Role.Moderator.value
fun PowerLevelsContent.kickOrDefault() = kick ?: Role.Moderator.value
fun PowerLevelsContent.inviteOrDefault() = invite ?: Role.Moderator.value
fun PowerLevelsContent.redactOrDefault() = redact ?: Role.Moderator.value
fun PowerLevelsContent.eventsDefaultOrDefault() = eventsDefault ?: Role.Default.value
fun PowerLevelsContent.usersDefaultOrDefault() = usersDefault ?: Role.Default.value
fun PowerLevelsContent.stateDefaultOrDefault() = stateDefault ?: Role.Moderator.value

View File

@ -40,7 +40,7 @@ data class RoomGuestAccessContent(
}
@JsonClass(generateAdapter = false)
enum class GuestAccess {
@Json(name = "can_join") CanJoin,
@Json(name = "forbidden") Forbidden
enum class GuestAccess(val value: String) {
@Json(name = "can_join") CanJoin("can_join"),
@Json(name = "forbidden") Forbidden("forbidden")
}

View File

@ -24,9 +24,10 @@ import com.squareup.moshi.JsonClass
* Enum for [RoomJoinRulesContent] : https://matrix.org/docs/spec/client_server/r0.4.0#m-room-join-rules
*/
@JsonClass(generateAdapter = false)
enum class RoomJoinRules {
@Json(name = "public") PUBLIC,
@Json(name = "invite") INVITE,
@Json(name = "knock") KNOCK,
@Json(name = "private") PRIVATE
enum class RoomJoinRules(val value: String) {
@Json(name = "public") PUBLIC("public"),
@Json(name = "invite") INVITE("invite"),
@Json(name = "knock") KNOCK("knock"),
@Json(name = "private") PRIVATE("private"),
@Json(name = "restricted") RESTRICTED("restricted")
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.matrix.android.sdk.api.session.room.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class RoomJoinRulesAllowEntry(
/**
* space: The room ID of the space to check the membership of.
*/
@Json(name = "space") val spaceID: String,
/**
* via: A list of servers which may be used to peek for membership of the space.
*/
@Json(name = "via") val via: List<String>
)

View File

@ -1,5 +1,6 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -26,14 +27,19 @@ import timber.log.Timber
*/
@JsonClass(generateAdapter = true)
data class RoomJoinRulesContent(
@Json(name = "join_rule") val _joinRules: String? = null
@Json(name = "join_rule") val _joinRules: String? = null,
/**
* If the allow key is an empty list (or not a list at all), then the room reverts to standard public join rules
*/
@Json(name = "allow") val allowList: List<RoomJoinRulesAllowEntry>? = null
) {
val joinRules: RoomJoinRules? = when (_joinRules) {
"public" -> RoomJoinRules.PUBLIC
"invite" -> RoomJoinRules.INVITE
"knock" -> RoomJoinRules.KNOCK
"public" -> RoomJoinRules.PUBLIC
"invite" -> RoomJoinRules.INVITE
"knock" -> RoomJoinRules.KNOCK
"private" -> RoomJoinRules.PRIVATE
else -> {
"restricted" -> RoomJoinRules.RESTRICTED
else -> {
Timber.w("Invalid value for RoomJoinRules: `$_joinRules`")
null
}

View File

@ -26,7 +26,7 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
* This class holds some data of a room.
* It can be retrieved by [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService]
*/
data class RoomSummary constructor(
data class RoomSummary(
val roomId: String,
// Computed display name
val displayName: String = "",
@ -35,7 +35,9 @@ data class RoomSummary constructor(
val avatarUrl: String = "",
val canonicalAlias: String? = null,
val aliases: List<String> = emptyList(),
val joinRules: RoomJoinRules? = null,
val isDirect: Boolean = false,
val directUserId: String? = null,
val joinedMembersCount: Int? = 0,
val invitedMembersCount: Int? = 0,
val latestPreviewableEvent: TimelineEvent? = null,
@ -54,7 +56,11 @@ data class RoomSummary constructor(
val inviterId: String? = null,
val breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS,
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel? = null,
val hasFailedSending: Boolean = false
val hasFailedSending: Boolean = false,
val roomType: String? = null,
val spaceParents: List<SpaceParentInfo>? = null,
val spaceChildren: List<SpaceChildInfo>? = null,
val flattenParentIds: List<String> = emptyList()
) {
val isVersioned: Boolean
@ -69,6 +75,9 @@ data class RoomSummary constructor(
val isFavorite: Boolean
get() = hasTag(RoomTag.ROOM_TAG_FAVOURITE)
val isPublic: Boolean
get() = joinRules == RoomJoinRules.PUBLIC
fun hasTag(tag: String) = tags.any { it.name == tag }
val canStartCall: Boolean

View File

@ -47,7 +47,7 @@ data class RoomThirdPartyInviteContent(
/**
* Keys with which the token may be signed.
*/
@Json(name = "public_keys") val publicKeys: List<PublicKeys>? = emptyList()
@Json(name = "public_keys") val publicKeys: List<PublicKeys>?
)
@JsonClass(generateAdapter = true)

View File

@ -0,0 +1,22 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.room.model
object RoomType {
const val SPACE = "m.space"
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.room.model
data class SpaceChildInfo(
val childRoomId: String,
// We might not know this child at all,
// i.e we just know it exists but no info on type/name/etc..
val isKnown: Boolean,
val roomType: String?,
val name: String?,
val topic: String?,
val avatarUrl: String?,
val order: String?,
val activeMemberCount: Int?,
val autoJoin: Boolean,
val viaServers: List<String>,
val parentRoomId: String?,
val suggested: Boolean?
)

View File

@ -0,0 +1,24 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.room.model
data class SpaceParentInfo(
val parentId: String?,
val roomSummary: RoomSummary?,
val canonical: Boolean?,
val viaServers: List<String>
)

View File

@ -18,13 +18,15 @@ package org.matrix.android.sdk.api.session.room.model.create
import android.net.Uri
import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
// TODO Give a way to include other initial states
class CreateRoomParams {
open class CreateRoomParams {
/**
* A public visibility indicates that the room will be shown in the published room list.
* A private visibility will hide the room from the published room list.
@ -68,6 +70,11 @@ class CreateRoomParams {
*/
val invite3pids = mutableListOf<ThreePid>()
/**
* Initial Guest Access
*/
var guestAccess: GuestAccess? = null
/**
* If set to true, when the room will be created, if cross-signing is enabled and we can get keys for every invited users,
* the encryption will be enabled on the created room
@ -111,6 +118,17 @@ class CreateRoomParams {
}
}
var roomType: String? = null // RoomType.MESSAGING
set(value) {
field = value
if (value != null) {
creationContent[CREATION_CONTENT_KEY_ROOM_TYPE] = value
} else {
// This is the default value, we remove the field
creationContent.remove(CREATION_CONTENT_KEY_ROOM_TYPE)
}
}
/**
* The power level content to override in the default power level event
*/
@ -136,7 +154,12 @@ class CreateRoomParams {
algorithm = MXCRYPTO_ALGORITHM_MEGOLM
}
var roomVersion: String? = null
var joinRuleRestricted: List<RoomJoinRulesAllowEntry>? = null
companion object {
private const val CREATION_CONTENT_KEY_M_FEDERATE = "m.federate"
private const val CREATION_CONTENT_KEY_ROOM_TYPE = "type"
}
}

View File

@ -26,5 +26,7 @@ import com.squareup.moshi.JsonClass
data class RoomCreateContent(
@Json(name = "creator") val creator: String? = null,
@Json(name = "room_version") val roomVersion: String? = null,
@Json(name = "predecessor") val predecessor: Predecessor? = null
@Json(name = "predecessor") val predecessor: Predecessor? = null,
// Defines the room type, see #RoomType (user extensible)
@Json(name = "type") val type: String? = null
)

View File

@ -47,3 +47,10 @@ data class FileInfo(
*/
@Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null
)
/**
* Get the url of the encrypted thumbnail or of the thumbnail
*/
fun FileInfo.getThumbnailUrl(): String? {
return thumbnailFile?.url ?: thumbnailUrl
}

View File

@ -40,7 +40,7 @@ data class ImageInfo(
/**
* Size of the image in bytes.
*/
@Json(name = "size") val size: Int = 0,
@Json(name = "size") val size: Long = 0,
/**
* Metadata about the image referred to in thumbnail_url.
@ -57,3 +57,10 @@ data class ImageInfo(
*/
@Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null
)
/**
* Get the url of the encrypted thumbnail or of the thumbnail
*/
fun ImageInfo.getThumbnailUrl(): String? {
return thumbnailFile?.url ?: thumbnailUrl
}

View File

@ -37,3 +37,10 @@ data class LocationInfo(
*/
@Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null
)
/**
* Get the url of the encrypted thumbnail or of the thumbnail
*/
fun LocationInfo.getThumbnailUrl(): String? {
return thumbnailFile?.url ?: thumbnailUrl
}

View File

@ -62,3 +62,10 @@ data class VideoInfo(
*/
@Json(name = "thumbnail_file") val thumbnailFile: EncryptedFileInfo? = null
)
/**
* Get the url of the encrypted thumbnail or of the thumbnail
*/
fun VideoInfo.getThumbnailUrl(): String? {
return thumbnailFile?.url ?: thumbnailUrl
}

View File

@ -16,6 +16,8 @@
package org.matrix.android.sdk.api.session.room.peeking
import org.matrix.android.sdk.api.util.MatrixItem
sealed class PeekResult {
data class Success(
val roomId: String,
@ -24,7 +26,9 @@ sealed class PeekResult {
val topic: String?,
val avatarUrl: String?,
val numJoinedMembers: Int?,
val viaServers: List<String>
val roomType: String?,
val viaServers: List<String>,
val someMembers: List<MatrixItem.UserItem>?
) : PeekResult()
data class PeekingNotAllowed(
@ -34,4 +38,6 @@ sealed class PeekResult {
) : PeekResult()
object UnknownAlias : PeekResult()
fun isSuccess() = this is Success
}

View File

@ -18,6 +18,13 @@
package org.matrix.android.sdk.api.session.room.powerlevels
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.banOrDefault
import org.matrix.android.sdk.api.session.room.model.eventsDefaultOrDefault
import org.matrix.android.sdk.api.session.room.model.inviteOrDefault
import org.matrix.android.sdk.api.session.room.model.kickOrDefault
import org.matrix.android.sdk.api.session.room.model.redactOrDefault
import org.matrix.android.sdk.api.session.room.model.stateDefaultOrDefault
import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault
/**
* This class is an helper around PowerLevelsContent.
@ -31,9 +38,9 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
* @return the power level
*/
fun getUserPowerLevelValue(userId: String): Int {
return powerLevelsContent.users.getOrElse(userId) {
powerLevelsContent.usersDefault
}
return powerLevelsContent.users
?.get(userId)
?: powerLevelsContent.usersDefaultOrDefault()
}
/**
@ -45,7 +52,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
fun getUserRole(userId: String): Role {
val value = getUserPowerLevelValue(userId)
// I think we should use powerLevelsContent.usersDefault, but Ganfra told me that it was like that on riot-Web
return Role.fromValue(value, powerLevelsContent.eventsDefault)
return Role.fromValue(value, powerLevelsContent.eventsDefaultOrDefault())
}
/**
@ -59,11 +66,11 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
fun isUserAllowedToSend(userId: String, isState: Boolean, eventType: String?): Boolean {
return if (userId.isNotEmpty()) {
val powerLevel = getUserPowerLevelValue(userId)
val minimumPowerLevel = powerLevelsContent.events[eventType]
val minimumPowerLevel = powerLevelsContent.events?.get(eventType)
?: if (isState) {
powerLevelsContent.stateDefault
powerLevelsContent.stateDefaultOrDefault()
} else {
powerLevelsContent.eventsDefault
powerLevelsContent.eventsDefaultOrDefault()
}
powerLevel >= minimumPowerLevel
} else false
@ -76,7 +83,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToInvite(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
return powerLevel >= powerLevelsContent.invite
return powerLevel >= powerLevelsContent.inviteOrDefault()
}
/**
@ -86,7 +93,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToBan(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
return powerLevel >= powerLevelsContent.ban
return powerLevel >= powerLevelsContent.banOrDefault()
}
/**
@ -96,7 +103,7 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToKick(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
return powerLevel >= powerLevelsContent.kick
return powerLevel >= powerLevelsContent.kickOrDefault()
}
/**
@ -106,6 +113,6 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
*/
fun isUserAbleToRedact(userId: String): Boolean {
val powerLevel = getUserPowerLevelValue(userId)
return powerLevel >= powerLevelsContent.redact
return powerLevel >= powerLevelsContent.redactOrDefault()
}
}

View File

@ -20,6 +20,6 @@ data class RoomAggregateNotificationCount(
val notificationCount: Int,
val highlightCount: Int
) {
val totalCount = notificationCount + highlightCount
val totalCount = notificationCount
val isHighlight = highlightCount > 0
}

View File

@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.RelationType
import org.matrix.android.sdk.api.session.events.model.getRelationContent
import org.matrix.android.sdk.api.session.events.model.isEdition
import org.matrix.android.sdk.api.session.events.model.isReply
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
@ -151,6 +152,10 @@ fun TimelineEvent.isReply(): Boolean {
return root.isReply()
}
fun TimelineEvent.isEdition(): Boolean {
return root.isEdition()
}
fun TimelineEvent.getTextEditableContent(): String? {
val lastContent = getLastMessageContent()
return if (isReply()) {

View File

@ -0,0 +1,35 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.space
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomType
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
class CreateSpaceParams : CreateRoomParams() {
init {
// Space-rooms are distinguished from regular messaging rooms by the m.room.type of m.space
roomType = RoomType.SPACE
// Space-rooms should be created with a power level for events_default of 100,
// to prevent the rooms accidentally/maliciously clogging up with messages from random members of the space.
powerLevelContentOverride = PowerLevelsContent(
eventsDefault = 100
)
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.space
sealed class JoinSpaceResult {
object Success : JoinSpaceResult()
data class Fail(val error: Throwable) : JoinSpaceResult()
/** Success fully joined the space, but failed to join all or some of it's rooms */
data class PartialSuccess(val failedRooms: Map<String, Throwable>) : JoinSpaceResult()
fun isSuccess() = this is Success || this is PartialSuccess
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.space
import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.model.RoomSummary
interface Space {
fun asRoom(): Room
val spaceId: String
suspend fun leave(reason: String? = null)
/**
* A current snapshot of [RoomSummary] associated with the space
*/
fun spaceSummary(): RoomSummary?
suspend fun addChildren(roomId: String,
viaServers: List<String>,
order: String?,
autoJoin: Boolean = false,
suggested: Boolean? = false)
suspend fun removeChildren(roomId: String)
@Throws
suspend fun setChildrenOrder(roomId: String, order: String?)
@Throws
suspend fun setChildrenAutoJoin(roomId: String, autoJoin: Boolean)
@Throws
suspend fun setChildrenSuggested(roomId: String, suggested: Boolean)
// fun getChildren() : List<IRoomSummary>
}

View File

@ -0,0 +1,87 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.space
import android.net.Uri
import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
import org.matrix.android.sdk.internal.session.space.peeking.SpacePeekResult
typealias SpaceSummaryQueryParams = RoomSummaryQueryParams
interface SpaceService {
/**
* Create a space asynchronously
* @return the spaceId of the created space
*/
suspend fun createSpace(params: CreateSpaceParams): String
/**
* Just a shortcut for space creation for ease of use
*/
suspend fun createSpace(name: String, topic: String?, avatarUri: Uri?, isPublic: Boolean): String
/**
* Get a space from a roomId
* @param spaceId the roomId to look for.
* @return a space with spaceId or null if room type is not space
*/
fun getSpace(spaceId: String): Space?
/**
* Try to resolve (peek) rooms and subspace in this space.
* Use this call get preview of children of this space, particularly useful to get a
* preview of rooms that you did not join yet.
*/
suspend fun peekSpace(spaceId: String): SpacePeekResult
/**
* Get's information of a space by querying the server
*/
suspend fun querySpaceChildren(spaceId: String,
suggestedOnly: Boolean? = null,
autoJoinedOnly: Boolean? = null): Pair<RoomSummary, List<SpaceChildInfo>>
/**
* Get a live list of space summaries. This list is refreshed as soon as the data changes.
* @return the [LiveData] of List[SpaceSummary]
*/
fun getSpaceSummariesLive(queryParams: SpaceSummaryQueryParams): LiveData<List<RoomSummary>>
fun getSpaceSummaries(spaceSummaryQueryParams: SpaceSummaryQueryParams): List<RoomSummary>
suspend fun joinSpace(spaceIdOrAlias: String,
reason: String? = null,
viaServers: List<String> = emptyList()): JoinSpaceResult
suspend fun rejectInvite(spaceId: String, reason: String?)
// fun getSpaceParentsOfRoom(roomId: String) : List<SpaceSummary>
/**
* Let this room declare that it has a parent.
* @param canonical true if it should be the main parent of this room
* In practice, well behaved rooms should only have one canonical parent, but given this is not enforced:
* if multiple are present the client should select the one with the lowest room ID, as determined via a lexicographic utf-8 ordering.
*/
suspend fun setSpaceParent(childRoomId: String, parentSpaceId: String, canonical: Boolean, viaServers: List<String>)
fun getRootSpaceSummaries(): List<RoomSummary>
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.space.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
/**
* "content": {
* "via": ["example.com"],
* "order": "abcd",
* "default": true
* }
*/
@JsonClass(generateAdapter = true)
data class SpaceChildContent(
/**
* Key which gives a list of candidate servers that can be used to join the room
* Children where via is not present are ignored.
*/
@Json(name = "via") val via: List<String>? = null,
/**
* The order key is a string which is used to provide a default ordering of siblings in the room list.
* (Rooms are sorted based on a lexicographic ordering of order values; rooms with no order come last.
* orders which are not strings, or do not consist solely of ascii characters in the range \x20 (space) to \x7F (~),
* or consist of more than 50 characters, are forbidden and should be ignored if received.)
*/
@Json(name = "order") val order: String? = null,
/**
* The auto_join flag on a child listing allows a space admin to list the sub-spaces and rooms in that space which should
* be automatically joined by members of that space.
* (This is not a force-join, which are descoped for a future MSC; the user can subsequently part these room if they desire.)
*/
@Json(name = "auto_join") val autoJoin: Boolean? = false,
/**
* If `suggested` is set to `true`, that indicates that the child should be advertised to
* members of the space by the client. This could be done by showing them eagerly
* in the room list. This is should be ignored if `auto_join` is set to `true`.
*/
@Json(name = "suggested") val suggested: Boolean? = false
) {
/**
* Orders which are not strings, or do not consist solely of ascii characters in the range \x20 (space) to \x7F (~),
* or consist of more than 50 characters, are forbidden and should be ignored if received.)
*/
fun validOrder(): String? {
return order
?.takeIf { it.length <= 50 }
?.takeIf { ORDER_VALID_CHAR_REGEX.matches(it) }
}
companion object {
private val ORDER_VALID_CHAR_REGEX = "[ -~]+".toRegex()
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.api.session.space.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
/**
* Rooms can claim parents via the m.space.parent state event.
* {
* "type": "m.space.parent",
* "state_key": "!space:example.com",
* "content": {
* "via": ["example.com"],
* "canonical": true,
* }
* }
*/
@JsonClass(generateAdapter = true)
data class SpaceParentContent(
/**
* Key which gives a list of candidate servers that can be used to join the parent.
* Parents where via is not present are ignored.
*/
@Json(name = "via") val via: List<String>? = null,
/**
* Canonical determines whether this is the main parent for the space.
* When a user joins a room with a canonical parent, clients may switch to view the room
* in the context of that space, peeking into it in order to find other rooms and group them together.
* In practice, well behaved rooms should only have one canonical parent, but given this is not enforced:
* if multiple are present the client should select the one with the lowest room ID, as determined via a lexicographic utf-8 ordering.
*/
@Json(name = "canonical") val canonical: Boolean? = false
)

Some files were not shown because too many files have changed in this diff Show More