mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Merge remote-tracking branch 'origin/develop' into bugfix/eric/landscape-bottom-sheet-peek
# Conflicts: # vector/src/main/java/im/vector/app/features/home/room/list/home/NewChatBottomSheet.kt
This commit is contained in:
commit
50b042ee98
1
changelog.d/7077.wip
Normal file
1
changelog.d/7077.wip
Normal file
@ -0,0 +1 @@
|
||||
[Device management] Session details screen
|
1
changelog.d/7102.bugfix
Normal file
1
changelog.d/7102.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Fixes crash when quickly double clicking FABs in the new app layout
|
@ -22,7 +22,7 @@ def markwon = "4.6.2"
|
||||
def moshi = "1.13.0"
|
||||
def lifecycle = "2.5.1"
|
||||
def flowBinding = "1.2.0"
|
||||
def flipper = "0.163.0"
|
||||
def flipper = "0.164.0"
|
||||
def epoxy = "4.6.2"
|
||||
def mavericks = "2.7.0"
|
||||
def glide = "4.13.2"
|
||||
|
@ -320,7 +320,7 @@
|
||||
<string name="settings_theme">السمة</string>
|
||||
<string name="encryption_information_decryption_error">خطأ في فكّ التعمية</string>
|
||||
<string name="encryption_information_device_name">اسم الجهاز</string>
|
||||
<string name="encryption_information_device_id">معرّف الجهاز</string>
|
||||
<string name="device_manager_session_details_session_id">معرّف الجهاز</string>
|
||||
<string name="encryption_information_device_key">مفتاح الجهاز</string>
|
||||
<string name="encryption_export_room_keys">صدّر مفاتيح الغرفة</string>
|
||||
<string name="encryption_export_room_keys_summary">صدّر المفاتيح إلى ملف محلي</string>
|
||||
|
@ -396,7 +396,7 @@
|
||||
<string name="settings_theme">Тема</string>
|
||||
<string name="encryption_information_decryption_error">Грешка при разшифроване</string>
|
||||
<string name="encryption_information_device_name">Публично име</string>
|
||||
<string name="encryption_information_device_id">Сесийно ID</string>
|
||||
<string name="device_manager_session_details_session_id">Сесийно ID</string>
|
||||
<string name="encryption_information_device_key">Ключ на устройство</string>
|
||||
<string name="encryption_export_e2e_room_keys">Експортирай E2E ключове за стая</string>
|
||||
<string name="encryption_export_room_keys">Експортиране на ключове за стая</string>
|
||||
|
@ -789,7 +789,7 @@
|
||||
<string name="encryption_export_room_keys">রুমের কুঞ্জিগুলি এক্সপোর্ট করুন</string>
|
||||
<string name="encryption_export_e2e_room_keys">শেষ থেকে শেষ রুমের কুঞ্জিগুলি এক্সপোর্ট করুন</string>
|
||||
<string name="encryption_information_device_key">সেশানের কুঞ্জি</string>
|
||||
<string name="encryption_information_device_id">আইডি</string>
|
||||
<string name="device_manager_session_details_session_id">আইডি</string>
|
||||
<string name="encryption_information_device_name">সর্বজনীন নাম</string>
|
||||
<string name="encryption_information_decryption_error">ডিক্রিপশন সমস্যা</string>
|
||||
<string name="settings_theme">থিম</string>
|
||||
|
@ -693,7 +693,7 @@
|
||||
<string name="encryption_information_decryption_error">ডিক্রিপশন সমস্যা</string>
|
||||
|
||||
<string name="encryption_information_device_name">সর্বজনীন নাম</string>
|
||||
<string name="encryption_information_device_id">আইডি</string>
|
||||
<string name="device_manager_session_details_session_id">আইডি</string>
|
||||
<string name="encryption_information_device_key">সেশানের কুঞ্জি</string>
|
||||
|
||||
<string name="encryption_export_e2e_room_keys">শেষ থেকে শেষ রুমের কুঞ্জিগুলি এক্সপোর্ট করুন</string>
|
||||
|
@ -448,7 +448,7 @@
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="encryption_information_decryption_error">Error al desxifrar</string>
|
||||
<string name="encryption_information_device_name">Nom públic</string>
|
||||
<string name="encryption_information_device_id">ID de sessió</string>
|
||||
<string name="device_manager_session_details_session_id">ID de sessió</string>
|
||||
<string name="encryption_information_device_key">Clau de sessió</string>
|
||||
<string name="encryption_export_e2e_room_keys">Exporta les claus de la sala E2E</string>
|
||||
<string name="encryption_export_room_keys">Exporta les claus de la sala</string>
|
||||
|
@ -635,7 +635,7 @@
|
||||
<string name="settings_theme">Motiv vzhledu</string>
|
||||
<string name="encryption_information_decryption_error">Chyba dešifrování</string>
|
||||
<string name="encryption_information_device_name">Veřejné jméno</string>
|
||||
<string name="encryption_information_device_id">ID relace</string>
|
||||
<string name="device_manager_session_details_session_id">ID relace</string>
|
||||
<string name="encryption_information_device_key">Klíč relace</string>
|
||||
<string name="encryption_export_e2e_room_keys">Export E2E klíčů místností</string>
|
||||
<string name="encryption_export_room_keys">Export klíčů místností</string>
|
||||
|
@ -418,7 +418,7 @@
|
||||
<string name="room_settings_unset_main_address">Als Hauptadresse aufheben</string>
|
||||
<string name="encryption_information_decryption_error">Entschlüsselungsfehler</string>
|
||||
<string name="encryption_information_device_name">Öffentlicher Name</string>
|
||||
<string name="encryption_information_device_id">Sitzungs-ID</string>
|
||||
<string name="device_manager_session_details_session_id">Sitzungs-ID</string>
|
||||
<string name="encryption_information_device_key">Sitzungsschlüssel</string>
|
||||
<string name="encryption_export_e2e_room_keys">Ende-zu-Ende-Raumschlüssel exportieren</string>
|
||||
<string name="encryption_export_room_keys">Raumschlüssel exportieren</string>
|
||||
|
@ -172,7 +172,7 @@
|
||||
<string name="settings_theme">Θέμα</string>
|
||||
<string name="encryption_information_decryption_error">Σφάλμα αποκρυπτογράφησης</string>
|
||||
<string name="encryption_information_device_name">Όνομα συσκευής</string>
|
||||
<string name="encryption_information_device_id">Αναγνωριστικό συσκευής</string>
|
||||
<string name="device_manager_session_details_session_id">Αναγνωριστικό συσκευής</string>
|
||||
<string name="encryption_export_export">Εξαγωγή</string>
|
||||
<string name="encryption_import_import">Εισαγωγή</string>
|
||||
<string name="select_room_directory">Επιλέξτε ένα ευρετήριο δωματίων</string>
|
||||
|
@ -1084,7 +1084,7 @@
|
||||
<string name="encryption_export_room_keys">Elporti ŝlosilojn de ĉambroj</string>
|
||||
<string name="encryption_export_e2e_room_keys">Elporti tutvoje ĉifrajn ŝlosilojn de ĉambroj</string>
|
||||
<string name="encryption_information_device_key">Ŝlosilo de salutaĵo</string>
|
||||
<string name="encryption_information_device_id">Identigilo de salutaĵo</string>
|
||||
<string name="device_manager_session_details_session_id">Identigilo de salutaĵo</string>
|
||||
<string name="encryption_information_device_name">Publika nomo</string>
|
||||
<string name="encryption_information_decryption_error">Eraris malĉifrado</string>
|
||||
<string name="settings_theme">Haŭto</string>
|
||||
|
@ -249,7 +249,7 @@
|
||||
<string name="room_settings_unset_main_address">Desescojer como Dirección Principal</string>
|
||||
<string name="encryption_information_decryption_error">Error en descifrar</string>
|
||||
<string name="encryption_information_device_name">Nombre del dispositivo</string>
|
||||
<string name="encryption_information_device_id">Identificación del dispositivo</string>
|
||||
<string name="device_manager_session_details_session_id">Identificación del dispositivo</string>
|
||||
<string name="encryption_information_device_key">Clave del dispositivo</string>
|
||||
<string name="encryption_export_e2e_room_keys">Exportar claves de cifrado de extremo-a-extremo de salas</string>
|
||||
<string name="encryption_export_room_keys">Exportar claves de salas</string>
|
||||
|
@ -415,7 +415,7 @@
|
||||
<string name="room_settings_unset_main_address">Dejar de Establecer como dirección principal</string>
|
||||
<string name="encryption_information_decryption_error">Error de descifrado</string>
|
||||
<string name="encryption_information_device_name">Nombre público</string>
|
||||
<string name="encryption_information_device_id">ID de sesión</string>
|
||||
<string name="device_manager_session_details_session_id">ID de sesión</string>
|
||||
<string name="encryption_information_device_key">Clave de sesión</string>
|
||||
<string name="encryption_export_e2e_room_keys">Exportar claves de salas con cifrado Extremo-a-Extremo</string>
|
||||
<string name="encryption_export_room_keys">Exportar claves de sala</string>
|
||||
|
@ -612,7 +612,7 @@
|
||||
<string name="room_settings_labs_warning_message">Need on alles katsejärgus olevad funktsionaalsused. Ole kasutamisel ettevaatlik.</string>
|
||||
<string name="encryption_information_decryption_error">Dekrüptimise viga</string>
|
||||
<string name="encryption_information_device_name">Avalik nimi</string>
|
||||
<string name="encryption_information_device_id">Sessiooni tunnus</string>
|
||||
<string name="device_manager_session_details_session_id">Sessiooni tunnus</string>
|
||||
<string name="encryption_information_device_key">Sessiooni võti</string>
|
||||
<string name="encryption_export_e2e_room_keys">Ekspordi jututubade läbiva krüptimise võtmed</string>
|
||||
<string name="encryption_export_room_keys">Ekspordi jututoa võtmed</string>
|
||||
|
@ -406,7 +406,7 @@ Kontuan izan ekintza honek aplikazioa berrabiaraziko duela eta denbora bat behar
|
||||
<string name="encryption_information_decryption_error">Deszifratze errorea</string>
|
||||
|
||||
<string name="encryption_information_device_name">Izen publikoa</string>
|
||||
<string name="encryption_information_device_id">IDa</string>
|
||||
<string name="device_manager_session_details_session_id">IDa</string>
|
||||
<string name="encryption_information_device_key">Saioaren gakoa</string>
|
||||
|
||||
<string name="encryption_export_e2e_room_keys">Esportatu E2E geletako gakoak</string>
|
||||
|
@ -678,7 +678,7 @@
|
||||
<string name="room_settings_labs_warning_message">اینها ویژگیهای آزمایشیای هستند که ممکن است به روشهای نامنتظرهای حراب شوندا. با احتیاط استفاده کنید.</string>
|
||||
<string name="room_settings_set_main_address">تنظیم به عنوان نشانی اصلی</string>
|
||||
<string name="encryption_information_device_name">نام عمومی</string>
|
||||
<string name="encryption_information_device_id">شناسهٔ نشست</string>
|
||||
<string name="device_manager_session_details_session_id">شناسهٔ نشست</string>
|
||||
<string name="encryption_information_device_key">کلید نشست</string>
|
||||
<string name="encryption_export_e2e_room_keys">برونریزی کلیدهای اتاقهای سرتاسری</string>
|
||||
<string name="encryption_export_room_keys">برونریزی کلیدهای اتاقها</string>
|
||||
|
@ -366,7 +366,7 @@
|
||||
<string name="room_settings_unset_main_address">Kumoa pääosoitteeksi asettaminen</string>
|
||||
<string name="encryption_information_decryption_error">Salauksenpurkuvirhe</string>
|
||||
<string name="encryption_information_device_name">Julkinen nimi</string>
|
||||
<string name="encryption_information_device_id">Istunnon tunnus</string>
|
||||
<string name="device_manager_session_details_session_id">Istunnon tunnus</string>
|
||||
<string name="encryption_information_device_key">Istunnon avain</string>
|
||||
<string name="encryption_export_e2e_room_keys">Vie salatun huoneen avaimet</string>
|
||||
<string name="encryption_export_room_keys">Vie huoneen avaimet</string>
|
||||
|
@ -778,7 +778,7 @@
|
||||
<string name="encryption_export_room_keys">Exporter les clés des salons</string>
|
||||
<string name="encryption_export_e2e_room_keys">Exporter les clés E2E des salons</string>
|
||||
<string name="encryption_information_device_key">Clé de la session</string>
|
||||
<string name="encryption_information_device_id">Identifiant de session</string>
|
||||
<string name="device_manager_session_details_session_id">Identifiant de session</string>
|
||||
<string name="encryption_information_device_name">Nom public</string>
|
||||
<string name="encryption_information_decryption_error">Erreur de déchiffrement</string>
|
||||
<string name="settings_theme">Thème</string>
|
||||
|
@ -346,7 +346,7 @@
|
||||
<string name="room_settings_unset_main_address">Désactiver comme adresse principale</string>
|
||||
<string name="encryption_information_decryption_error">Erreur de déchiffrement</string>
|
||||
<string name="encryption_information_device_name">Nom public</string>
|
||||
<string name="encryption_information_device_id">Identifiant de session</string>
|
||||
<string name="device_manager_session_details_session_id">Identifiant de session</string>
|
||||
<string name="encryption_information_device_key">Clé de la session</string>
|
||||
<string name="encryption_export_e2e_room_keys">Exporter les clés E2E des salons</string>
|
||||
<string name="encryption_export_room_keys">Exporter les clés des salons</string>
|
||||
|
@ -380,7 +380,7 @@
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="encryption_information_decryption_error">Fallo ao descifrar</string>
|
||||
<string name="encryption_information_device_name">Nome do dispositivo</string>
|
||||
<string name="encryption_information_device_id">ID de sesión</string>
|
||||
<string name="device_manager_session_details_session_id">ID de sesión</string>
|
||||
<string name="encryption_information_device_key">Chave do dispositivo</string>
|
||||
<string name="encryption_export_e2e_room_keys">Exportar chaves E2E da sala</string>
|
||||
<string name="encryption_export_room_keys">Exportar chaves da sala</string>
|
||||
|
@ -572,7 +572,7 @@
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="encryption_information_decryption_error">Greška u dešifriranju</string>
|
||||
<string name="encryption_information_device_name">Javni naziv</string>
|
||||
<string name="encryption_information_device_id">Identitet</string>
|
||||
<string name="device_manager_session_details_session_id">Identitet</string>
|
||||
<string name="encryption_information_device_key">Ključ sesije</string>
|
||||
<string name="encryption_export_e2e_room_keys">Izvezi sobne ključeve za E2E</string>
|
||||
<string name="encryption_export_room_keys">Izvezi sobne ključeve</string>
|
||||
|
@ -351,7 +351,7 @@
|
||||
<string name="room_settings_unset_main_address">Kiszedés fő címek közül</string>
|
||||
<string name="encryption_information_decryption_error">Visszafejtés hiba</string>
|
||||
<string name="encryption_information_device_name">Nyilvános név</string>
|
||||
<string name="encryption_information_device_id">Munkamenet-azonosító</string>
|
||||
<string name="device_manager_session_details_session_id">Munkamenet-azonosító</string>
|
||||
<string name="encryption_information_device_key">Munkamenet kulcs</string>
|
||||
<string name="encryption_export_e2e_room_keys">E2E szoba kulcsok exportálása</string>
|
||||
<string name="encryption_export_room_keys">Szoba kulcsok exportálása</string>
|
||||
|
@ -301,7 +301,7 @@ Di masa mendatang proses verifikasi ini akan dimutakhirkan.</string>
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="encryption_information_decryption_error">Kesalahan dekripsi</string>
|
||||
<string name="encryption_information_device_name">Nama perangkat</string>
|
||||
<string name="encryption_information_device_id">ID Sesi</string>
|
||||
<string name="device_manager_session_details_session_id">ID Sesi</string>
|
||||
<string name="encryption_information_device_key">Kunci perangkat</string>
|
||||
<string name="encryption_export_e2e_room_keys">Ekspor kunci ruangan terenkripsi</string>
|
||||
<string name="encryption_export_room_keys">Ekspor ruangan kunci</string>
|
||||
|
@ -193,7 +193,7 @@
|
||||
<string name="settings_theme">Þema</string>
|
||||
<string name="encryption_information_decryption_error">Afkóðunarvilla</string>
|
||||
<string name="encryption_information_device_name">Heiti tækis</string>
|
||||
<string name="encryption_information_device_id">Auðkenni setu</string>
|
||||
<string name="device_manager_session_details_session_id">Auðkenni setu</string>
|
||||
<string name="encryption_information_device_key">Dulritunarlykill setu</string>
|
||||
<string name="encryption_export_export">Flytja út</string>
|
||||
<string name="passphrase_enter_passphrase">Settu inn lykilsetningu</string>
|
||||
|
@ -430,7 +430,7 @@
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="encryption_information_decryption_error">Errore di decriptazione</string>
|
||||
<string name="encryption_information_device_name">Nome pubblico</string>
|
||||
<string name="encryption_information_device_id">ID sessione</string>
|
||||
<string name="device_manager_session_details_session_id">ID sessione</string>
|
||||
<string name="encryption_information_device_key">Chiave sessione</string>
|
||||
<string name="encryption_export_e2e_room_keys">Esporta le chiavi di crittografia E2E delle stanze</string>
|
||||
<string name="encryption_export_room_keys">Esporta le chiavi delle stanze</string>
|
||||
|
@ -542,7 +542,7 @@
|
||||
<string name="encryption_export_room_keys">יצא מפתחות חדר</string>
|
||||
<string name="encryption_export_e2e_room_keys">ייצא מפתחות חדר E2E</string>
|
||||
<string name="encryption_information_device_key">מזהה מפתח</string>
|
||||
<string name="encryption_information_device_id">מזהה מושב</string>
|
||||
<string name="device_manager_session_details_session_id">מזהה מושב</string>
|
||||
<string name="encryption_information_device_name">שם ציבורי</string>
|
||||
<string name="encryption_information_decryption_error">שגיאת פענוח</string>
|
||||
<string name="settings_theme">ערכת נושא</string>
|
||||
|
@ -197,7 +197,7 @@
|
||||
<string name="room_settings_labs_warning_message">これらは予期しない不具合が生じるかもしれない実験的機能です。慎重に使用してください。</string>
|
||||
<string name="room_settings_set_main_address">メインアドレスとして設定</string>
|
||||
<string name="room_settings_unset_main_address">メインアドレスとしての設定を解除</string>
|
||||
<string name="encryption_information_device_id">セッションID</string>
|
||||
<string name="device_manager_session_details_session_id">セッションID</string>
|
||||
<string name="font_size">文字の大きさ</string>
|
||||
<string name="tiny">とても小さい</string>
|
||||
<string name="small">小さい</string>
|
||||
|
@ -291,7 +291,7 @@
|
||||
<string name="room_settings_category_advanced_title">Talqayt</string>
|
||||
<string name="room_settings_labs_pref_title">Tinarimin</string>
|
||||
<string name="settings_theme">Asentel</string>
|
||||
<string name="encryption_information_device_id">Asulay n tqimit</string>
|
||||
<string name="device_manager_session_details_session_id">Asulay n tqimit</string>
|
||||
<string name="encryption_information_device_key">Tasarut n tɣimit</string>
|
||||
<string name="encryption_export_e2e_room_keys">Sifeḍ tisura n texxamt E2E</string>
|
||||
<string name="encryption_export_room_keys">Sifeḍ tisura n texxamt</string>
|
||||
|
@ -431,7 +431,7 @@
|
||||
<string name="settings_theme">테마</string>
|
||||
<string name="encryption_information_decryption_error">암호 복호화 오류</string>
|
||||
<string name="encryption_information_device_name">공개 이름</string>
|
||||
<string name="encryption_information_device_id">ID</string>
|
||||
<string name="device_manager_session_details_session_id">ID</string>
|
||||
<string name="encryption_information_device_key">기기 키</string>
|
||||
<string name="encryption_export_e2e_room_keys">종단간 암호화 방 키 내보내기</string>
|
||||
<string name="encryption_export_room_keys">방 키 내보내기</string>
|
||||
|
@ -909,7 +909,7 @@
|
||||
<string name="encryption_export_room_keys">ສົ່ງອອກກະແຈຫ້ອງ</string>
|
||||
<string name="encryption_export_e2e_room_keys">ສົ່ງອອກກະແຈຫ້ອງ E2E</string>
|
||||
<string name="encryption_information_device_key">ລະຫັດລະບົບ</string>
|
||||
<string name="encryption_information_device_id">ID ລະບົບ</string>
|
||||
<string name="device_manager_session_details_session_id">ID ລະບົບ</string>
|
||||
<string name="encryption_information_device_name">ຊື່ສາທາລະນະ</string>
|
||||
<string name="encryption_information_decryption_error">ການຖອດລະຫັດຜິດພາດ</string>
|
||||
<string name="settings_theme">ຫົວຂໍ້</string>
|
||||
|
@ -469,7 +469,7 @@
|
||||
<string name="settings_theme">Tēma</string>
|
||||
<string name="encryption_information_decryption_error">Atšifrēšanas kļūda</string>
|
||||
<string name="encryption_information_device_name">Ierīces nosaukums</string>
|
||||
<string name="encryption_information_device_id">Sesijas ID</string>
|
||||
<string name="device_manager_session_details_session_id">Sesijas ID</string>
|
||||
<string name="encryption_information_device_key">Sesijas atslēga</string>
|
||||
<string name="encryption_export_e2e_room_keys">Eksportēt istabas šifrēšanas atslēgas</string>
|
||||
<string name="encryption_export_room_keys">Eksportēt istabas atslēgas</string>
|
||||
|
@ -119,7 +119,7 @@
|
||||
<string name="room_settings_banned_users_title">Bannlyste brukere</string>
|
||||
<string name="room_settings_category_advanced_title">Avansert</string>
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="encryption_information_device_id">Økt-ID</string>
|
||||
<string name="device_manager_session_details_session_id">Økt-ID</string>
|
||||
<string name="encryption_information_device_key">Øktnøkkel</string>
|
||||
<string name="encryption_export_export">Eksporter</string>
|
||||
<string name="encryption_import_import">Importer</string>
|
||||
|
@ -275,7 +275,7 @@
|
||||
<string name="room_settings_unset_main_address">Niet instellen als hoofdadres</string>
|
||||
<string name="encryption_information_decryption_error">Ontsleutelingsfout</string>
|
||||
<string name="encryption_information_device_name">Publieke naam</string>
|
||||
<string name="encryption_information_device_id">Sessie ID</string>
|
||||
<string name="device_manager_session_details_session_id">Sessie ID</string>
|
||||
<string name="encryption_information_device_key">Sessiesleutel</string>
|
||||
<string name="encryption_export_e2e_room_keys">E2E-gesprekssleutels exporteren</string>
|
||||
<string name="encryption_export_room_keys">Gesprekssleutels exporteren</string>
|
||||
|
@ -310,7 +310,7 @@
|
||||
<string name="settings_theme">Preg</string>
|
||||
<string name="encryption_information_decryption_error">Noko gjekk gale med dekrypteringa</string>
|
||||
<string name="encryption_information_device_name">Offentleg namn</string>
|
||||
<string name="encryption_information_device_id">Økt-ID</string>
|
||||
<string name="device_manager_session_details_session_id">Økt-ID</string>
|
||||
<string name="encryption_information_device_key">Sesjonsnøkkel</string>
|
||||
<string name="encryption_export_e2e_room_keys">Eksporter E2E-romnøkklar</string>
|
||||
<string name="encryption_export_room_keys">Eksporter romnøkklar</string>
|
||||
|
@ -231,7 +231,7 @@
|
||||
<string name="room_settings_set_main_address">Ustaw jako główny adres</string>
|
||||
<string name="settings_theme">Motyw</string>
|
||||
<string name="encryption_information_device_name">Nazwa publiczna</string>
|
||||
<string name="encryption_information_device_id">ID sesji</string>
|
||||
<string name="device_manager_session_details_session_id">ID sesji</string>
|
||||
<string name="encryption_export_export">Eksportuj</string>
|
||||
<string name="passphrase_enter_passphrase">Wprowadź hasło</string>
|
||||
<string name="passphrase_confirm_passphrase">Potwierdź hasło</string>
|
||||
|
@ -418,7 +418,7 @@
|
||||
<string name="room_settings_unset_main_address">Des-definir como endereço principal</string>
|
||||
<string name="encryption_information_decryption_error">Erro de decriptação</string>
|
||||
<string name="encryption_information_device_name">Nome público</string>
|
||||
<string name="encryption_information_device_id">ID de sessão</string>
|
||||
<string name="device_manager_session_details_session_id">ID de sessão</string>
|
||||
<string name="encryption_information_device_key">Chave de sessão</string>
|
||||
<string name="encryption_export_e2e_room_keys">Exportar chaves de sala E2E</string>
|
||||
<string name="encryption_export_room_keys">Exportar chaves de sala</string>
|
||||
|
@ -246,7 +246,7 @@ Note que esta acção irá reiniciar a aplicação e poderá levar algum tempo.<
|
||||
|
||||
<string name="encryption_information_decryption_error">Erro de decifragem</string>
|
||||
<string name="encryption_information_device_name">Nome do dispositivo</string>
|
||||
<string name="encryption_information_device_id">ID do dispositivo</string>
|
||||
<string name="device_manager_session_details_session_id">ID do dispositivo</string>
|
||||
<string name="encryption_information_device_key">Chave do dispositivo</string>
|
||||
<string name="encryption_export_e2e_room_keys">Exportar chaves E2E da sala</string>
|
||||
<string name="encryption_export_room_keys">Exportar chaves de sala</string>
|
||||
|
@ -432,7 +432,7 @@
|
||||
<string name="room_settings_unset_main_address">Сбросить основной адрес</string>
|
||||
<string name="encryption_information_decryption_error">Ошибка дешифровки</string>
|
||||
<string name="encryption_information_device_name">Публичное имя</string>
|
||||
<string name="encryption_information_device_id">ID сессии</string>
|
||||
<string name="device_manager_session_details_session_id">ID сессии</string>
|
||||
<string name="encryption_information_device_key">Ключ сессии</string>
|
||||
<string name="encryption_export_e2e_room_keys">Экспорт E2E ключей комнаты</string>
|
||||
<string name="encryption_export_room_keys">Экспорт ключей комнаты</string>
|
||||
|
@ -388,7 +388,7 @@
|
||||
<string name="settings_theme">Vzhľad</string>
|
||||
<string name="encryption_information_decryption_error">Chyba dešifrovania</string>
|
||||
<string name="encryption_information_device_name">Verejné meno</string>
|
||||
<string name="encryption_information_device_id">ID relácie</string>
|
||||
<string name="device_manager_session_details_session_id">ID relácie</string>
|
||||
<string name="encryption_information_device_key">Kľúč relácie</string>
|
||||
<string name="encryption_export_e2e_room_keys">Exportovať šifrovacie kľúče miestnosti</string>
|
||||
<string name="encryption_export_room_keys">Exportovať kľúče miestnosti</string>
|
||||
|
@ -431,7 +431,7 @@
|
||||
<string name="settings_theme">Temë</string>
|
||||
<string name="encryption_information_decryption_error">Gabim shfshehtëzimi</string>
|
||||
<string name="encryption_information_device_name">Emër publik</string>
|
||||
<string name="encryption_information_device_id">ID Sesioni</string>
|
||||
<string name="device_manager_session_details_session_id">ID Sesioni</string>
|
||||
<string name="encryption_information_device_key">Kyç sesioni</string>
|
||||
<string name="encryption_export_e2e_room_keys">Eksporto kyçe dhome E2E</string>
|
||||
<string name="encryption_export_room_keys">Eksporto kyçe dhome</string>
|
||||
|
@ -918,7 +918,7 @@
|
||||
<string name="settings_secure_backup_enter_to_setup">Sätt upp på den här enheten</string>
|
||||
<string name="reset_secure_backup_title">Generera en ny säkerhetskopia eller sätt en ny lösenfras för din existerande säkerhetskopia.</string>
|
||||
<string name="room_settings_labs_warning_message">Detta är experimentella funktioner som kan gå sönder på oväntade sätt. Använd varsamt.</string>
|
||||
<string name="encryption_information_device_id">Sessions-ID</string>
|
||||
<string name="device_manager_session_details_session_id">Sessions-ID</string>
|
||||
<string name="encryption_information_device_key">Sessionsnyckel</string>
|
||||
<string name="encryption_export_e2e_room_keys">Exportera krypteringsnycklar</string>
|
||||
<string name="encryption_export_room_keys">Exportera rumsnycklar</string>
|
||||
|
@ -260,7 +260,7 @@
|
||||
<string name="room_settings_set_main_address">ప్రధాన చిరునామాగా సెట్ చేయండి</string>
|
||||
|
||||
<string name="encryption_information_device_name">పరికరం పేరు</string>
|
||||
<string name="encryption_information_device_id">పరికరం ID</string>
|
||||
<string name="device_manager_session_details_session_id">పరికరం ID</string>
|
||||
<string name="encryption_information_device_key">పరికరం కీ</string>
|
||||
|
||||
<string name="encryption_export_e2e_room_keys">E2E గది కీలను ఎగుమతి చేయండి</string>
|
||||
|
@ -376,7 +376,7 @@
|
||||
<string name="settings_theme">Tema</string>
|
||||
<string name="encryption_information_decryption_error">Çözme hatası</string>
|
||||
<string name="encryption_information_device_name">Görünür Ad</string>
|
||||
<string name="encryption_information_device_id">Oturum kimliği</string>
|
||||
<string name="device_manager_session_details_session_id">Oturum kimliği</string>
|
||||
<string name="encryption_information_device_key">Oturum anahtarı</string>
|
||||
<string name="encryption_export_e2e_room_keys">E2E Oda anahtarlarını dışa aktar</string>
|
||||
<string name="encryption_export_room_keys">Oda anahtarlarını dışa aktar</string>
|
||||
|
@ -354,7 +354,7 @@
|
||||
<string name="room_settings_unset_main_address">Зробити не основною адресою</string>
|
||||
<string name="encryption_information_decryption_error">Помилка розшифрування</string>
|
||||
<string name="encryption_information_device_name">Загальнодоступна назва</string>
|
||||
<string name="encryption_information_device_id">ID сеансу</string>
|
||||
<string name="device_manager_session_details_session_id">ID сеансу</string>
|
||||
<string name="encryption_information_device_key">Ключ сеансу</string>
|
||||
<string name="encryption_export_e2e_room_keys">Експортувати E2E ключі кімнати</string>
|
||||
<string name="encryption_export_room_keys">Експортувати ключі кімнати</string>
|
||||
|
@ -594,7 +594,7 @@
|
||||
<string name="deactivate_account_title">Hủy tài khoản</string>
|
||||
<string name="dialog_user_consent_submit">Xem lại ngay</string>
|
||||
<string name="encryption_information_device_key">Chìa khóa phiên</string>
|
||||
<string name="encryption_information_device_id">Mã phiên</string>
|
||||
<string name="device_manager_session_details_session_id">Mã phiên</string>
|
||||
<string name="encryption_information_device_name">Tên công khai</string>
|
||||
<string name="encryption_information_decryption_error">Lỗi giải mã</string>
|
||||
<string name="room_settings_labs_warning_message">Những chức năng này mang tính thí nghiệm có thể còn nhiều lỗi. Lưu ý khi dùng.</string>
|
||||
|
@ -242,7 +242,7 @@
|
||||
<string name="settings_password_updated">你的密码已更新</string>
|
||||
<string name="encryption_information_decryption_error">解密错误</string>
|
||||
<string name="encryption_information_device_name">公开名称</string>
|
||||
<string name="encryption_information_device_id">会话 ID</string>
|
||||
<string name="device_manager_session_details_session_id">会话 ID</string>
|
||||
<string name="encryption_information_device_key">会话密钥</string>
|
||||
<string name="encryption_import_import">导入</string>
|
||||
<string name="encryption_information_verified">已验证</string>
|
||||
|
@ -469,7 +469,7 @@
|
||||
<string name="settings_theme">主題</string>
|
||||
<string name="encryption_information_decryption_error">解密錯誤</string>
|
||||
<string name="encryption_information_device_name">公開名稱</string>
|
||||
<string name="encryption_information_device_id">工作階段 ID</string>
|
||||
<string name="device_manager_session_details_session_id">工作階段 ID</string>
|
||||
<string name="encryption_information_device_key">工作階段金鑰</string>
|
||||
<string name="encryption_export_e2e_room_keys">匯出聊天室的端到端加密金鑰</string>
|
||||
<string name="encryption_export_room_keys">匯出聊天室的加密金鑰</string>
|
||||
|
@ -1212,7 +1212,6 @@
|
||||
<string name="encryption_information_decryption_error">Decryption error</string>
|
||||
|
||||
<string name="encryption_information_device_name">Public name</string>
|
||||
<string name="encryption_information_device_id">Session ID</string>
|
||||
<string name="encryption_information_device_key">Session key</string>
|
||||
|
||||
<string name="encryption_export_e2e_room_keys">Export E2E room keys</string>
|
||||
@ -3263,8 +3262,15 @@
|
||||
</plurals>
|
||||
<string name="device_manager_current_session_title">Current Session</string>
|
||||
<string name="device_manager_session_title">Session</string>
|
||||
<string name="device_manager_device_title">Device</string>
|
||||
<!-- Examples: Last activity Yesterday at 6PM, Last activity Aug 31 at 5:47PM -->
|
||||
<string name="device_manager_session_last_activity">Last activity %1$s</string>
|
||||
<string name="device_manager_session_details_title">Session details</string>
|
||||
<string name="device_manager_session_details_description">Application, device, and activity information.</string>
|
||||
<string name="device_manager_session_details_session_name">Session name</string>
|
||||
<string name="device_manager_session_details_session_id">Session ID</string>
|
||||
<string name="device_manager_session_details_session_last_activity">Last activity</string>
|
||||
<string name="device_manager_session_details_device_ip_address">IP address</string>
|
||||
|
||||
<!-- Note to translators: %s will be replaces with selected space name -->
|
||||
<string name="home_empty_space_no_rooms_title">%s\nis looking a little empty.</string>
|
||||
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<declare-styleable name="SessionOverviewEntryView">
|
||||
<attr name="sessionOverviewEntryTitle" format="string" />
|
||||
<attr name="sessionOverviewEntryDescription" format="string" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
@ -2,8 +2,8 @@
|
||||
<resources>
|
||||
|
||||
<declare-styleable name="SessionsListHeaderView">
|
||||
<attr name="devicesListHeaderTitle" format="string" />
|
||||
<attr name="devicesListHeaderDescription" format="string" />
|
||||
<attr name="sessionsListHeaderTitle" format="string" />
|
||||
<attr name="sessionsListHeaderDescription" format="string" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
@ -1,6 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="TextAppearance.Vector.Subtitle.DevicesManagement">
|
||||
<item name="android:textColor">?vctr_content_primary</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Vector.Subtitle.Medium.DevicesManagement">
|
||||
<item name="android:textColor">?vctr_content_primary</item>
|
||||
</style>
|
||||
|
@ -340,6 +340,7 @@
|
||||
<activity android:name=".features.home.room.list.home.invites.InvitesActivity"/>
|
||||
<activity android:name=".features.home.room.list.home.release.ReleaseNotesActivity"/>
|
||||
<activity android:name=".features.settings.devices.v2.overview.SessionOverviewActivity"/>
|
||||
<activity android:name=".features.settings.devices.v2.details.SessionDetailsActivity"/>
|
||||
|
||||
<!-- Services -->
|
||||
|
||||
|
@ -88,6 +88,7 @@ import im.vector.app.features.settings.account.deactivation.DeactivateAccountVie
|
||||
import im.vector.app.features.settings.crosssigning.CrossSigningSettingsViewModel
|
||||
import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheetViewModel
|
||||
import im.vector.app.features.settings.devices.DevicesViewModel
|
||||
import im.vector.app.features.settings.devices.v2.details.SessionDetailsViewModel
|
||||
import im.vector.app.features.settings.devices.v2.overview.SessionOverviewViewModel
|
||||
import im.vector.app.features.settings.devtools.AccountDataViewModel
|
||||
import im.vector.app.features.settings.devtools.GossipingEventsPaperTrailViewModel
|
||||
@ -641,4 +642,9 @@ interface MavericksViewModelModule {
|
||||
@IntoMap
|
||||
@MavericksViewModelKey(SessionOverviewViewModel::class)
|
||||
fun sessionOverviewViewModelFactory(factory: SessionOverviewViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@MavericksViewModelKey(SessionDetailsViewModel::class)
|
||||
fun sessionDetailsViewModelFactory(factory: SessionDetailsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.core.utils
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import androidx.core.content.getSystemService
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import javax.inject.Inject
|
||||
|
||||
class CopyToClipboardUseCase @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
) {
|
||||
|
||||
fun execute(text: CharSequence) {
|
||||
context.getSystemService<ClipboardManager>()
|
||||
?.setPrimaryClip(ClipData.newPlainText("", text))
|
||||
}
|
||||
}
|
@ -19,8 +19,6 @@ package im.vector.app.core.utils
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Activity
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
@ -100,8 +98,7 @@ fun requestDisablingBatteryOptimization(activity: Activity, activityResultLaunch
|
||||
* @param toastMessage content of the toast message as a String resource
|
||||
*/
|
||||
fun copyToClipboard(context: Context, text: CharSequence, showToast: Boolean = true, @StringRes toastMessage: Int = R.string.copied_to_clipboard) {
|
||||
val clipboard = context.getSystemService<ClipboardManager>()!!
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText("", text))
|
||||
CopyToClipboardUseCase(context).execute(text)
|
||||
if (showToast) {
|
||||
context.toast(toastMessage)
|
||||
}
|
||||
|
@ -201,13 +201,12 @@ class NewHomeDetailFragment :
|
||||
private fun setupFabs() {
|
||||
showFABs()
|
||||
|
||||
views.newLayoutCreateChatButton.setOnClickListener {
|
||||
newChatBottomSheet.show(requireActivity().supportFragmentManager, NewChatBottomSheet.TAG)
|
||||
views.newLayoutCreateChatButton.debouncedClicks {
|
||||
newChatBottomSheet.takeIf { !it.isAdded }?.show(requireActivity().supportFragmentManager, NewChatBottomSheet.TAG)
|
||||
}
|
||||
|
||||
views.newLayoutOpenSpacesButton.setOnClickListener {
|
||||
// Click action for open spaces modal goes here
|
||||
spaceListBottomSheet.show(requireActivity().supportFragmentManager, SpaceListBottomSheet.TAG)
|
||||
views.newLayoutOpenSpacesButton.debouncedClicks {
|
||||
spaceListBottomSheet.takeIf { !it.isAdded }?.show(requireActivity().supportFragmentManager, SpaceListBottomSheet.TAG)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ import im.vector.app.features.navigation.Navigator
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class NewChatBottomSheet @Inject constructor() : VectorBaseBottomSheetDialogFragment<FragmentNewChatBottomSheetBinding>() {
|
||||
class NewChatBottomSheet : VectorBaseBottomSheetDialogFragment<FragmentNewChatBottomSheetBinding>() {
|
||||
|
||||
@Inject lateinit var navigator: Navigator
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import javax.inject.Inject
|
||||
|
||||
class CheckIfSectionDeviceIsVisibleUseCase @Inject constructor() {
|
||||
|
||||
fun execute(deviceInfo: DeviceInfo): Boolean {
|
||||
return deviceInfo.lastSeenIp?.isNotEmpty().orFalse()
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import javax.inject.Inject
|
||||
|
||||
class CheckIfSectionSessionIsVisibleUseCase @Inject constructor() {
|
||||
|
||||
fun execute(deviceInfo: DeviceInfo): Boolean {
|
||||
return deviceInfo.displayName?.isNotEmpty().orFalse() ||
|
||||
deviceInfo.deviceId?.isNotEmpty().orFalse() ||
|
||||
(deviceInfo.lastSeenTs ?: 0) > 0
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
|
||||
sealed class SessionDetailsAction : VectorViewModelAction {
|
||||
data class CopyToClipboard(val content: String) : SessionDetailsAction()
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.airbnb.mvrx.Mavericks
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.core.extensions.addFragment
|
||||
import im.vector.app.core.platform.SimpleFragmentActivity
|
||||
|
||||
/**
|
||||
* Display the details info about a Session.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class SessionDetailsActivity : SimpleFragmentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (isFirstCreation()) {
|
||||
addFragment(
|
||||
container = views.container,
|
||||
fragmentClass = SessionDetailsFragment::class.java,
|
||||
params = intent.getParcelableExtra(Mavericks.KEY_ARG)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newIntent(context: Context, deviceId: String): Intent {
|
||||
return Intent(context, SessionDetailsActivity::class.java).apply {
|
||||
putExtra(Mavericks.KEY_ARG, SessionDetailsArgs(deviceId))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class SessionDetailsArgs(
|
||||
val deviceId: String
|
||||
) : Parcelable
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
|
||||
@EpoxyModelClass
|
||||
abstract class SessionDetailsContentItem : VectorEpoxyModel<SessionDetailsContentItem.Holder>(R.layout.item_session_details_content) {
|
||||
|
||||
@EpoxyAttribute
|
||||
var title: String? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var description: String? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var hasDivider: Boolean = true
|
||||
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
|
||||
var onLongClickListener: View.OnLongClickListener? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.sessionDetailsContentTitle.text = title
|
||||
holder.sessionDetailsContentDescription.text = description
|
||||
holder.view.isClickable = onLongClickListener != null
|
||||
holder.view.setOnLongClickListener(onLongClickListener)
|
||||
holder.sessionDetailsContentDivider.isVisible = hasDivider
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val sessionDetailsContentTitle by bind<TextView>(R.id.sessionDetailsContentTitle)
|
||||
val sessionDetailsContentDescription by bind<TextView>(R.id.sessionDetailsContentDescription)
|
||||
val sessionDetailsContentDivider by bind<View>(R.id.sessionDetailsContentDivider)
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.date.DateFormatKind
|
||||
import im.vector.app.core.date.VectorDateFormatter
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.utils.DimensionConverter
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import javax.inject.Inject
|
||||
|
||||
class SessionDetailsController @Inject constructor(
|
||||
private val checkIfSectionSessionIsVisibleUseCase: CheckIfSectionSessionIsVisibleUseCase,
|
||||
private val checkIfSectionDeviceIsVisibleUseCase: CheckIfSectionDeviceIsVisibleUseCase,
|
||||
private val stringProvider: StringProvider,
|
||||
private val dateFormatter: VectorDateFormatter,
|
||||
private val dimensionConverter: DimensionConverter,
|
||||
) : TypedEpoxyController<DeviceInfo>() {
|
||||
|
||||
var callback: Callback? = null
|
||||
|
||||
interface Callback {
|
||||
fun onItemLongClicked(content: String)
|
||||
}
|
||||
|
||||
override fun buildModels(data: DeviceInfo?) {
|
||||
data?.let { info ->
|
||||
val hasSectionSession = hasSectionSession(data)
|
||||
if (hasSectionSession) {
|
||||
buildSectionSession(info)
|
||||
}
|
||||
|
||||
if (hasSectionDevice(data)) {
|
||||
buildSectionDevice(info, addExtraTopMargin = hasSectionSession)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildHeaderItem(@StringRes titleResId: Int, addExtraTopMargin: Boolean = false) {
|
||||
val host = this
|
||||
sessionDetailsHeaderItem {
|
||||
id(titleResId)
|
||||
title(host.stringProvider.getString(titleResId))
|
||||
addExtraTopMargin(addExtraTopMargin)
|
||||
dimensionConverter(host.dimensionConverter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildContentItem(@StringRes titleResId: Int, value: String, hasDivider: Boolean) {
|
||||
val host = this
|
||||
sessionDetailsContentItem {
|
||||
id(titleResId)
|
||||
title(host.stringProvider.getString(titleResId))
|
||||
description(value)
|
||||
hasDivider(hasDivider)
|
||||
onLongClickListener(View.OnLongClickListener {
|
||||
host.callback?.onItemLongClicked(value)
|
||||
true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasSectionSession(data: DeviceInfo): Boolean {
|
||||
return checkIfSectionSessionIsVisibleUseCase.execute(data)
|
||||
}
|
||||
|
||||
private fun buildSectionSession(data: DeviceInfo) {
|
||||
val sessionName = data.displayName
|
||||
val sessionId = data.deviceId
|
||||
val sessionLastSeenTs = data.lastSeenTs
|
||||
|
||||
buildHeaderItem(R.string.device_manager_session_title)
|
||||
|
||||
sessionName?.let {
|
||||
val hasDivider = sessionId != null || sessionLastSeenTs != null
|
||||
buildContentItem(R.string.device_manager_session_details_session_name, it, hasDivider)
|
||||
}
|
||||
sessionId?.let {
|
||||
val hasDivider = sessionLastSeenTs != null
|
||||
buildContentItem(R.string.device_manager_session_details_session_id, it, hasDivider)
|
||||
}
|
||||
sessionLastSeenTs?.let {
|
||||
val formattedDate = dateFormatter.format(it, DateFormatKind.MESSAGE_DETAIL)
|
||||
val hasDivider = false
|
||||
buildContentItem(R.string.device_manager_session_details_session_last_activity, formattedDate, hasDivider)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasSectionDevice(data: DeviceInfo): Boolean {
|
||||
return checkIfSectionDeviceIsVisibleUseCase.execute(data)
|
||||
}
|
||||
|
||||
private fun buildSectionDevice(data: DeviceInfo, addExtraTopMargin: Boolean) {
|
||||
val lastSeenIp = data.lastSeenIp
|
||||
|
||||
buildHeaderItem(R.string.device_manager_device_title, addExtraTopMargin)
|
||||
|
||||
lastSeenIp?.let {
|
||||
val hasDivider = false
|
||||
buildContentItem(R.string.device_manager_session_details_device_ip_address, it, hasDivider)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.platform.showOptimizedSnackbar
|
||||
import im.vector.app.databinding.FragmentSessionDetailsBinding
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Display the details info about a Session.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class SessionDetailsFragment :
|
||||
VectorBaseFragment<FragmentSessionDetailsBinding>() {
|
||||
|
||||
@Inject lateinit var sessionDetailsController: SessionDetailsController
|
||||
|
||||
private val viewModel: SessionDetailsViewModel by fragmentViewModel()
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSessionDetailsBinding {
|
||||
return FragmentSessionDetailsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
initToolbar()
|
||||
initSessionDetails()
|
||||
observeViewEvents()
|
||||
}
|
||||
|
||||
private fun initToolbar() {
|
||||
(activity as? AppCompatActivity)
|
||||
?.supportActionBar
|
||||
?.setTitle(R.string.device_manager_session_details_title)
|
||||
}
|
||||
|
||||
private fun initSessionDetails() {
|
||||
sessionDetailsController.callback = object : SessionDetailsController.Callback {
|
||||
override fun onItemLongClicked(content: String) {
|
||||
viewModel.handle(SessionDetailsAction.CopyToClipboard(content))
|
||||
}
|
||||
}
|
||||
views.sessionDetails.configureWith(sessionDetailsController)
|
||||
}
|
||||
|
||||
private fun observeViewEvents() {
|
||||
viewModel.observeViewEvents { viewEvent ->
|
||||
when (viewEvent) {
|
||||
SessionDetailsViewEvent.ContentCopiedToClipboard -> view?.showOptimizedSnackbar(getString(R.string.copied_to_clipboard))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
cleanUpSessionDetails()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun cleanUpSessionDetails() {
|
||||
sessionDetailsController.callback = null
|
||||
views.sessionDetails.cleanup()
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
if (state.deviceInfo is Success) {
|
||||
renderSessionDetails(state.deviceInfo.invoke())
|
||||
} else {
|
||||
hideSessionDetails()
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderSessionDetails(deviceInfo: DeviceInfo) {
|
||||
views.sessionDetails.isVisible = true
|
||||
sessionDetailsController.setData(deviceInfo)
|
||||
}
|
||||
|
||||
private fun hideSessionDetails() {
|
||||
views.sessionDetails.isGone = true
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updateMargins
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.app.core.utils.DimensionConverter
|
||||
|
||||
private const val EXTRA_TOP_MARGIN_DP = 48
|
||||
|
||||
@EpoxyModelClass
|
||||
abstract class SessionDetailsHeaderItem : VectorEpoxyModel<SessionDetailsHeaderItem.Holder>(R.layout.item_session_details_header) {
|
||||
|
||||
@EpoxyAttribute
|
||||
var title: String? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var addExtraTopMargin: Boolean = false
|
||||
|
||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
|
||||
var dimensionConverter: DimensionConverter? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.sessionDetailsHeaderTitle.text = title
|
||||
val topMargin = if (addExtraTopMargin) {
|
||||
dimensionConverter?.dpToPx(EXTRA_TOP_MARGIN_DP) ?: 0
|
||||
} else {
|
||||
0
|
||||
}
|
||||
holder.sessionDetailsHeaderTitle.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
updateMargins(top = topMargin)
|
||||
}
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val sessionDetailsHeaderTitle by bind<TextView>(R.id.sessionDetailsHeaderTitle)
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
|
||||
sealed class SessionDetailsViewEvent : VectorViewEvents {
|
||||
object ContentCopiedToClipboard : SessionDetailsViewEvent()
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
import com.airbnb.mvrx.Success
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.utils.CopyToClipboardUseCase
|
||||
import im.vector.app.features.settings.devices.v2.overview.GetDeviceFullInfoUseCase
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
class SessionDetailsViewModel @AssistedInject constructor(
|
||||
@Assisted val initialState: SessionDetailsViewState,
|
||||
private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase,
|
||||
private val copyToClipboardUseCase: CopyToClipboardUseCase,
|
||||
) : VectorViewModel<SessionDetailsViewState, SessionDetailsAction, SessionDetailsViewEvent>(initialState) {
|
||||
|
||||
companion object : MavericksViewModelFactory<SessionDetailsViewModel, SessionDetailsViewState> by hiltMavericksViewModelFactory()
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MavericksAssistedViewModelFactory<SessionDetailsViewModel, SessionDetailsViewState> {
|
||||
override fun create(initialState: SessionDetailsViewState): SessionDetailsViewModel
|
||||
}
|
||||
|
||||
init {
|
||||
observeSessionInfo(initialState.deviceId)
|
||||
}
|
||||
|
||||
private fun observeSessionInfo(deviceId: String) {
|
||||
getDeviceFullInfoUseCase.execute(deviceId)
|
||||
.onEach { setState { copy(deviceInfo = Success(it.deviceInfo)) } }
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun handle(action: SessionDetailsAction) {
|
||||
return when (action) {
|
||||
is SessionDetailsAction.CopyToClipboard -> handleCopyToClipboard(action)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCopyToClipboard(copyToClipboard: SessionDetailsAction.CopyToClipboard) {
|
||||
copyToClipboardUseCase.execute(copyToClipboard.content)
|
||||
_viewEvents.post(SessionDetailsViewEvent.ContentCopiedToClipboard)
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MavericksState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
|
||||
data class SessionDetailsViewState(
|
||||
val deviceId: String,
|
||||
val deviceInfo: Async<DeviceInfo> = Uninitialized,
|
||||
) : MavericksState {
|
||||
constructor(args: SessionDetailsArgs) : this(
|
||||
deviceId = args.deviceId
|
||||
)
|
||||
}
|
@ -24,6 +24,7 @@ import androidx.core.view.isVisible
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.date.DateFormatKind
|
||||
import im.vector.app.core.date.VectorDateFormatter
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
import im.vector.app.core.extensions.setTextWithColoredPart
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.DrawableProvider
|
||||
@ -91,13 +92,14 @@ class SessionInfoView @JvmOverloads constructor(
|
||||
private fun appendLearnMoreToVerificationStatus() {
|
||||
val status = views.sessionInfoVerificationStatusDetailTextView.text
|
||||
val learnMore = context.getString(R.string.action_learn_more)
|
||||
val stringBuilder = StringBuilder()
|
||||
stringBuilder.append(status)
|
||||
stringBuilder.append(" ")
|
||||
stringBuilder.append(learnMore)
|
||||
val statusText = buildString {
|
||||
append(status)
|
||||
append(" ")
|
||||
append(learnMore)
|
||||
}
|
||||
|
||||
views.sessionInfoVerificationStatusDetailTextView.setTextWithColoredPart(
|
||||
fullText = stringBuilder.toString(),
|
||||
fullText = statusText,
|
||||
coloredPart = learnMore,
|
||||
underline = false
|
||||
) {
|
||||
@ -172,15 +174,7 @@ class SessionInfoView @JvmOverloads constructor(
|
||||
views.sessionInfoLastActivityTextView.isGone = true
|
||||
}
|
||||
|
||||
deviceInfo.lastSeenIp
|
||||
?.takeIf { isLastSeenDetailsVisible }
|
||||
?.let { ipAddress ->
|
||||
views.sessionInfoLastIPAddressTextView.isVisible = true
|
||||
views.sessionInfoLastIPAddressTextView.text = ipAddress
|
||||
}
|
||||
?: run {
|
||||
views.sessionInfoLastIPAddressTextView.isGone = true
|
||||
}
|
||||
views.sessionInfoLastIPAddressTextView.setTextOrHide(deviceInfo.lastSeenIp?.takeIf { isLastSeenDetailsVisible })
|
||||
}
|
||||
|
||||
private fun renderDetailsButton(isDetailsButtonVisible: Boolean) {
|
||||
|
@ -53,26 +53,27 @@ class SessionsListHeaderView @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
private fun setTitle(typedArray: TypedArray) {
|
||||
val title = typedArray.getString(R.styleable.SessionsListHeaderView_devicesListHeaderTitle)
|
||||
val title = typedArray.getString(R.styleable.SessionsListHeaderView_sessionsListHeaderTitle)
|
||||
binding.sessionsListHeaderTitle.text = title
|
||||
}
|
||||
|
||||
private fun setDescription(typedArray: TypedArray) {
|
||||
val description = typedArray.getString(R.styleable.SessionsListHeaderView_devicesListHeaderDescription)
|
||||
val description = typedArray.getString(R.styleable.SessionsListHeaderView_sessionsListHeaderDescription)
|
||||
if (description.isNullOrEmpty()) {
|
||||
binding.sessionsListHeaderDescription.isVisible = false
|
||||
return
|
||||
}
|
||||
|
||||
val learnMore = context.getString(R.string.action_learn_more)
|
||||
val stringBuilder = StringBuilder()
|
||||
stringBuilder.append(description)
|
||||
stringBuilder.append(" ")
|
||||
stringBuilder.append(learnMore)
|
||||
val fullDescription = buildString {
|
||||
append(description)
|
||||
append(" ")
|
||||
append(learnMore)
|
||||
}
|
||||
|
||||
binding.sessionsListHeaderDescription.isVisible = true
|
||||
binding.sessionsListHeaderDescription.setTextWithColoredPart(
|
||||
fullText = stringBuilder.toString(),
|
||||
fullText = fullDescription,
|
||||
coloredPart = learnMore,
|
||||
underline = false
|
||||
) {
|
||||
|
@ -25,8 +25,8 @@ import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveU
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.api.util.toOptional
|
||||
import org.matrix.android.sdk.flow.unwrap
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetDeviceFullInfoUseCase @Inject constructor(
|
||||
@ -36,7 +36,7 @@ class GetDeviceFullInfoUseCase @Inject constructor(
|
||||
private val checkIfSessionIsInactiveUseCase: CheckIfSessionIsInactiveUseCase,
|
||||
) {
|
||||
|
||||
fun execute(deviceId: String): Flow<Optional<DeviceFullInfo>> {
|
||||
fun execute(deviceId: String): Flow<DeviceFullInfo> {
|
||||
return activeSessionHolder.getSafeActiveSession()?.let { session ->
|
||||
combine(
|
||||
getCurrentSessionCrossSigningInfoUseCase.execute(),
|
||||
@ -58,7 +58,7 @@ class GetDeviceFullInfoUseCase @Inject constructor(
|
||||
null
|
||||
}
|
||||
fullInfo.toOptional()
|
||||
}
|
||||
}.unwrap()
|
||||
} ?: emptyFlow()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.overview
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.TypedArray
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.res.use
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.setAttributeBackground
|
||||
import im.vector.app.databinding.ViewSessionOverviewEntryBinding
|
||||
|
||||
class SessionOverviewEntryView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private val binding = ViewSessionOverviewEntryBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
this
|
||||
)
|
||||
|
||||
init {
|
||||
initBackground()
|
||||
context.obtainStyledAttributes(
|
||||
attrs,
|
||||
R.styleable.SessionOverviewEntryView,
|
||||
0,
|
||||
0
|
||||
).use {
|
||||
setTitle(it)
|
||||
setDescription(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initBackground() {
|
||||
binding.root.setAttributeBackground(android.R.attr.selectableItemBackground)
|
||||
}
|
||||
|
||||
private fun setTitle(typedArray: TypedArray) {
|
||||
val title = typedArray.getString(R.styleable.SessionOverviewEntryView_sessionOverviewEntryTitle)
|
||||
binding.sessionsOverviewEntryTitle.text = title
|
||||
}
|
||||
|
||||
private fun setDescription(typedArray: TypedArray) {
|
||||
val description = typedArray.getString(R.styleable.SessionOverviewEntryView_sessionOverviewEntryDescription)
|
||||
binding.sessionsOverviewEntryDescription.text = description
|
||||
}
|
||||
}
|
@ -45,6 +45,8 @@ import javax.inject.Inject
|
||||
class SessionOverviewFragment :
|
||||
VectorBaseFragment<FragmentSessionOverviewBinding>() {
|
||||
|
||||
@Inject lateinit var viewNavigator: SessionOverviewViewNavigator
|
||||
|
||||
@Inject lateinit var dateFormatter: VectorDateFormatter
|
||||
|
||||
@Inject lateinit var drawableProvider: DrawableProvider
|
||||
@ -79,6 +81,7 @@ class SessionOverviewFragment :
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
updateToolbar(state.isCurrentSession)
|
||||
updateEntryDetails(state.deviceId)
|
||||
if (state.deviceInfo is Success) {
|
||||
renderSessionInfo(state.isCurrentSession, state.deviceInfo.invoke())
|
||||
} else {
|
||||
@ -93,6 +96,12 @@ class SessionOverviewFragment :
|
||||
?.setTitle(titleResId)
|
||||
}
|
||||
|
||||
private fun updateEntryDetails(deviceId: String) {
|
||||
views.sessionOverviewEntryDetails.setOnClickListener {
|
||||
viewNavigator.navigateToSessionDetails(requireContext(), deviceId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderSessionInfo(isCurrentSession: Boolean, deviceFullInfo: DeviceFullInfo) {
|
||||
views.sessionOverviewInfo.isVisible = true
|
||||
val viewState = SessionInfoViewState(
|
||||
|
@ -26,7 +26,6 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
||||
@ -54,7 +53,6 @@ class SessionOverviewViewModel @AssistedInject constructor(
|
||||
|
||||
private fun observeSessionInfo(deviceId: String) {
|
||||
getDeviceFullInfoUseCase.execute(deviceId)
|
||||
.mapNotNull { it.getOrNull() }
|
||||
.onEach { setState { copy(deviceInfo = Success(it)) } }
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.overview
|
||||
|
||||
import android.content.Context
|
||||
import im.vector.app.features.settings.devices.v2.details.SessionDetailsActivity
|
||||
import javax.inject.Inject
|
||||
|
||||
class SessionOverviewViewNavigator @Inject constructor() {
|
||||
|
||||
fun navigateToSessionDetails(context: Context, deviceId: String) {
|
||||
context.startActivity(SessionDetailsActivity.newIntent(context, deviceId))
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/encryption_information_device_id"
|
||||
android:text="@string/device_manager_session_details_session_id"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
|
21
vector/src/main/res/layout/fragment_session_details.xml
Normal file
21
vector/src/main/res/layout/fragment_session_details.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/sessionDetails"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="24dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
tools:listitem="@layout/item_session_details_content" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,10 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<im.vector.app.features.settings.devices.v2.list.SessionInfoView
|
||||
android:id="@+id/sessionOverviewInfo"
|
||||
android:layout_width="0dp"
|
||||
@ -17,4 +21,16 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<im.vector.app.features.settings.devices.v2.overview.SessionOverviewEntryView
|
||||
android:id="@+id/sessionOverviewEntryDetails"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sessionOverviewInfo"
|
||||
app:sessionOverviewEntryDescription="@string/device_manager_session_details_description"
|
||||
app:sessionOverviewEntryTitle="@string/device_manager_session_details_title" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
@ -12,8 +12,8 @@
|
||||
android:id="@+id/deviceListHeaderSectionSecurityRecommendations"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:devicesListHeaderDescription="@string/device_manager_header_section_security_recommendations_description"
|
||||
app:devicesListHeaderTitle="@string/device_manager_header_section_security_recommendations_title"
|
||||
app:sessionsListHeaderDescription="@string/device_manager_header_section_security_recommendations_description"
|
||||
app:sessionsListHeaderTitle="@string/device_manager_header_section_security_recommendations_title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
@ -60,8 +60,8 @@
|
||||
android:id="@+id/deviceListHeaderCurrentSession"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:devicesListHeaderDescription=""
|
||||
app:devicesListHeaderTitle="@string/device_manager_current_session_title"
|
||||
app:sessionsListHeaderDescription=""
|
||||
app:sessionsListHeaderTitle="@string/device_manager_current_session_title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/deviceListSecurityRecommendationsDivider" />
|
||||
@ -90,8 +90,8 @@
|
||||
android:id="@+id/deviceListHeaderOtherSessions"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:devicesListHeaderDescription="@string/settings_sessions_other_description"
|
||||
app:devicesListHeaderTitle="@string/settings_sessions_other_title"
|
||||
app:sessionsListHeaderDescription="@string/settings_sessions_other_description"
|
||||
app:sessionsListHeaderTitle="@string/settings_sessions_other_title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/deviceListDividerCurrentSession" />
|
||||
|
50
vector/src/main/res/layout/item_session_details_content.xml
Normal file
50
vector/src/main/res/layout/item_session_details_content.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="14dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sessionDetailsContentTitle"
|
||||
style="@style/TextAppearance.Vector.Body.DevicesManagement"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
app:layout_constraintEnd_toStartOf="@id/sessionDetailsContentDescription"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Session name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sessionDetailsContentDescription"
|
||||
style="@style/TextAppearance.Vector.Body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||
android:gravity="end"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/sessionDetailsContentTitle"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Element Web: Firefox on macOS" />
|
||||
|
||||
<View
|
||||
android:id="@+id/sessionDetailsContentDivider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:background="@drawable/divider_horizontal"
|
||||
app:layout_constraintEnd_toEndOf="@id/sessionDetailsContentDescription"
|
||||
app:layout_constraintStart_toStartOf="@id/sessionDetailsContentTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/sessionDetailsContentBarrier" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/sessionDetailsContentBarrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="sessionDetailsContentTitle, sessionDetailsContentDescription" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
21
vector/src/main/res/layout/item_session_details_header.xml
Normal file
21
vector/src/main/res/layout/item_session_details_header.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sessionDetailsHeaderTitle"
|
||||
style="@style/TextAppearance.Vector.Body.Medium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/layout_horizontal_margin"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Session" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
42
vector/src/main/res/layout/view_session_overview_entry.xml
Normal file
42
vector/src/main/res/layout/view_session_overview_entry.xml
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sessionsOverviewEntryTitle"
|
||||
style="@style/TextAppearance.Vector.Subtitle.DevicesManagement"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginTop="20dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Session details" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sessionsOverviewEntryDescription"
|
||||
style="@style/TextAppearance.Vector.Body.DevicesManagement"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
app:layout_constraintEnd_toEndOf="@id/sessionsOverviewEntryTitle"
|
||||
app:layout_constraintStart_toStartOf="@id/sessionsOverviewEntryTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/sessionsOverviewEntryTitle"
|
||||
tools:text="Application, device, and activity information." />
|
||||
|
||||
<View
|
||||
android:id="@+id/sessionsOverviewEntryDivider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:background="@drawable/divider_horizontal"
|
||||
app:layout_constraintEnd_toEndOf="@id/sessionsOverviewEntryTitle"
|
||||
app:layout_constraintStart_toStartOf="@id/sessionsOverviewEntryTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/sessionsOverviewEntryDescription" />
|
||||
|
||||
</merge>
|
@ -35,7 +35,7 @@
|
||||
<im.vector.app.core.preference.VectorPreference
|
||||
android:key="SETTINGS_ENCRYPTION_INFORMATION_DEVICE_ID_PREFERENCE_KEY"
|
||||
android:persistent="false"
|
||||
android:title="@string/encryption_information_device_id"
|
||||
android:title="@string/device_manager_session_details_session_id"
|
||||
tools:summary="VZRHETBEER" />
|
||||
|
||||
<im.vector.app.core.preference.VectorPreference
|
||||
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.core.utils
|
||||
|
||||
import android.content.ClipData
|
||||
import im.vector.app.test.fakes.FakeContext
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkAll
|
||||
import io.mockk.verify
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
private const val A_TEXT = "text"
|
||||
|
||||
class CopyToClipboardUseCaseTest {
|
||||
|
||||
private val fakeContext = FakeContext()
|
||||
|
||||
private val copyToClipboardUseCase = CopyToClipboardUseCase(
|
||||
context = fakeContext.instance
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
mockkStatic(ClipData::class)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
unmockkAll()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a text when executing the use case then the text is copied into the clipboard`() {
|
||||
// Given
|
||||
val clipboardManager = fakeContext.givenClipboardManager()
|
||||
clipboardManager.givenSetPrimaryClip()
|
||||
val clipData = mockk<ClipData>()
|
||||
every { ClipData.newPlainText(any(), any()) } returns clipData
|
||||
|
||||
// When
|
||||
copyToClipboardUseCase.execute(A_TEXT)
|
||||
|
||||
// Then
|
||||
clipboardManager.verifySetPrimaryClip(clipData)
|
||||
verify { ClipData.newPlainText("", A_TEXT) }
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
|
||||
private const val AN_IP_ADDRESS = "ip-address"
|
||||
|
||||
class CheckIfSectionDeviceIsVisibleUseCaseTest {
|
||||
|
||||
private val checkIfSectionDeviceIsVisibleUseCase = CheckIfSectionDeviceIsVisibleUseCase()
|
||||
|
||||
@Test
|
||||
fun `given device info with Ip address when checking is device section is visible then it returns true`() = runTest {
|
||||
// Given
|
||||
val deviceInfo = givenADeviceInfo(AN_IP_ADDRESS)
|
||||
|
||||
// When
|
||||
val result = checkIfSectionDeviceIsVisibleUseCase.execute(deviceInfo)
|
||||
|
||||
// Then
|
||||
result shouldBeEqualTo true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given device info with empty or null Ip address when checking is device section is visible then it returns false`() = runTest {
|
||||
// Given
|
||||
val deviceInfo1 = givenADeviceInfo("")
|
||||
val deviceInfo2 = givenADeviceInfo(null)
|
||||
|
||||
// When
|
||||
val result1 = checkIfSectionDeviceIsVisibleUseCase.execute(deviceInfo1)
|
||||
val result2 = checkIfSectionDeviceIsVisibleUseCase.execute(deviceInfo2)
|
||||
|
||||
// Then
|
||||
result1 shouldBeEqualTo false
|
||||
result2 shouldBeEqualTo false
|
||||
}
|
||||
|
||||
private fun givenADeviceInfo(ipAddress: String?): DeviceInfo {
|
||||
val info = mockk<DeviceInfo>()
|
||||
every { info.lastSeenIp } returns ipAddress
|
||||
return info
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
|
||||
private const val A_SESSION_NAME = "session-name"
|
||||
private const val A_SESSION_ID = "session-id"
|
||||
private const val A_LAST_SEEN_TS = 123L
|
||||
|
||||
class CheckIfSectionSessionIsVisibleUseCaseTest {
|
||||
|
||||
private val checkIfSectionSessionIsVisibleUseCase = CheckIfSectionSessionIsVisibleUseCase()
|
||||
|
||||
@Test
|
||||
fun `given device info with name, id or lastSeenTs when checking is session section is visible then it returns true`() = runTest {
|
||||
// Given
|
||||
val deviceInfoList = listOf(
|
||||
givenADeviceInfo(
|
||||
sessionName = A_SESSION_NAME,
|
||||
sessionId = null,
|
||||
lastSeenTs = null,
|
||||
),
|
||||
givenADeviceInfo(
|
||||
sessionName = null,
|
||||
sessionId = A_SESSION_ID,
|
||||
lastSeenTs = null,
|
||||
),
|
||||
givenADeviceInfo(
|
||||
sessionName = null,
|
||||
sessionId = null,
|
||||
lastSeenTs = A_LAST_SEEN_TS,
|
||||
),
|
||||
givenADeviceInfo(
|
||||
sessionName = A_SESSION_NAME,
|
||||
sessionId = A_SESSION_ID,
|
||||
lastSeenTs = null,
|
||||
),
|
||||
givenADeviceInfo(
|
||||
sessionName = A_SESSION_NAME,
|
||||
sessionId = null,
|
||||
lastSeenTs = A_LAST_SEEN_TS,
|
||||
),
|
||||
givenADeviceInfo(
|
||||
sessionName = null,
|
||||
sessionId = A_SESSION_ID,
|
||||
lastSeenTs = A_LAST_SEEN_TS,
|
||||
),
|
||||
givenADeviceInfo(
|
||||
sessionName = A_SESSION_NAME,
|
||||
sessionId = A_SESSION_ID,
|
||||
lastSeenTs = A_LAST_SEEN_TS,
|
||||
),
|
||||
)
|
||||
|
||||
deviceInfoList.forEach { deviceInfo ->
|
||||
// When
|
||||
val result = checkIfSectionSessionIsVisibleUseCase.execute(deviceInfo)
|
||||
|
||||
// Then
|
||||
result shouldBeEqualTo true
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given device info with missing session info when checking is session section is visible then it returns true`() = runTest {
|
||||
// Given
|
||||
val deviceInfoList = listOf(
|
||||
givenADeviceInfo(
|
||||
sessionName = null,
|
||||
sessionId = null,
|
||||
lastSeenTs = null,
|
||||
),
|
||||
givenADeviceInfo(
|
||||
sessionName = "",
|
||||
sessionId = "",
|
||||
lastSeenTs = null,
|
||||
),
|
||||
givenADeviceInfo(
|
||||
sessionName = "",
|
||||
sessionId = "",
|
||||
lastSeenTs = -1,
|
||||
),
|
||||
)
|
||||
|
||||
deviceInfoList.forEach { deviceInfo ->
|
||||
// When
|
||||
val result = checkIfSectionSessionIsVisibleUseCase.execute(deviceInfo)
|
||||
|
||||
// Then
|
||||
result shouldBeEqualTo false
|
||||
}
|
||||
}
|
||||
|
||||
private fun givenADeviceInfo(
|
||||
sessionName: String?,
|
||||
sessionId: String?,
|
||||
lastSeenTs: Long?,
|
||||
): DeviceInfo {
|
||||
val info = mockk<DeviceInfo>()
|
||||
every { info.displayName } returns sessionName
|
||||
every { info.deviceId } returns sessionId
|
||||
every { info.lastSeenTs } returns lastSeenTs
|
||||
return info
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.test.MvRxTestRule
|
||||
import im.vector.app.core.utils.CopyToClipboardUseCase
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
import im.vector.app.features.settings.devices.v2.overview.GetDeviceFullInfoUseCase
|
||||
import im.vector.app.test.test
|
||||
import im.vector.app.test.testDispatcher
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
|
||||
private const val A_SESSION_ID = "session-id"
|
||||
private const val A_TEXT = "text"
|
||||
|
||||
class SessionDetailsViewModelTest {
|
||||
|
||||
@get:Rule
|
||||
val mvRxTestRule = MvRxTestRule(testDispatcher = testDispatcher)
|
||||
|
||||
private val args = SessionDetailsArgs(
|
||||
deviceId = A_SESSION_ID
|
||||
)
|
||||
private val getDeviceFullInfoUseCase = mockk<GetDeviceFullInfoUseCase>()
|
||||
private val copyToClipboardUseCase = mockk<CopyToClipboardUseCase>()
|
||||
|
||||
private fun createViewModel() = SessionDetailsViewModel(
|
||||
initialState = SessionDetailsViewState(args),
|
||||
getDeviceFullInfoUseCase = getDeviceFullInfoUseCase,
|
||||
copyToClipboardUseCase = copyToClipboardUseCase,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `given the viewModel has been initialized then viewState is updated with session info`() {
|
||||
// Given
|
||||
val deviceFullInfo = mockk<DeviceFullInfo>()
|
||||
val deviceInfo = mockk<DeviceInfo>()
|
||||
every { deviceFullInfo.deviceInfo } returns deviceInfo
|
||||
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo)
|
||||
val expectedState = SessionDetailsViewState(
|
||||
deviceId = A_SESSION_ID,
|
||||
deviceInfo = Success(deviceInfo)
|
||||
)
|
||||
|
||||
// When
|
||||
val viewModel = createViewModel()
|
||||
|
||||
// Then
|
||||
viewModel.test()
|
||||
.assertLatestState { state -> state == expectedState }
|
||||
.finish()
|
||||
verify { getDeviceFullInfoUseCase.execute(A_SESSION_ID) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given copyToClipboard action when viewModel handle it then related use case is executed and viewEvent is updated`() {
|
||||
// Given
|
||||
val deviceFullInfo = mockk<DeviceFullInfo>()
|
||||
val deviceInfo = mockk<DeviceInfo>()
|
||||
every { deviceFullInfo.deviceInfo } returns deviceInfo
|
||||
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo)
|
||||
val action = SessionDetailsAction.CopyToClipboard(A_TEXT)
|
||||
every { copyToClipboardUseCase.execute(any()) } just runs
|
||||
|
||||
// When
|
||||
val viewModel = createViewModel()
|
||||
val viewModelTest = viewModel.test()
|
||||
viewModel.handle(action)
|
||||
|
||||
// Then
|
||||
viewModelTest
|
||||
.assertEvent { it is SessionDetailsViewEvent.ContentCopiedToClipboard }
|
||||
.finish()
|
||||
verify { copyToClipboardUseCase.execute(A_TEXT) }
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.amshove.kluent.shouldBeNull
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@ -72,6 +73,7 @@ class GetDeviceFullInfoUseCaseTest {
|
||||
|
||||
@Test
|
||||
fun `given current session and info for device when getting device info then the result is correct`() = runTest {
|
||||
// Given
|
||||
val currentSessionCrossSigningInfo = givenCurrentSessionCrossSigningInfo()
|
||||
val deviceInfo = DeviceInfo(
|
||||
lastSeenTs = A_TIMESTAMP
|
||||
@ -85,16 +87,16 @@ class GetDeviceFullInfoUseCaseTest {
|
||||
val isInactive = false
|
||||
every { checkIfSessionIsInactiveUseCase.execute(any()) } returns isInactive
|
||||
|
||||
// When
|
||||
val deviceFullInfo = getDeviceFullInfoUseCase.execute(A_DEVICE_ID).firstOrNull()
|
||||
|
||||
deviceFullInfo shouldBeEqualTo Optional(
|
||||
DeviceFullInfo(
|
||||
// Then
|
||||
deviceFullInfo shouldBeEqualTo DeviceFullInfo(
|
||||
deviceInfo = deviceInfo,
|
||||
cryptoDeviceInfo = cryptoDeviceInfo,
|
||||
roomEncryptionTrustLevel = trustLevel,
|
||||
isInactive = isInactive,
|
||||
)
|
||||
)
|
||||
verify { fakeActiveSessionHolder.instance.getSafeActiveSession() }
|
||||
verify { getCurrentSessionCrossSigningInfoUseCase.execute() }
|
||||
verify { getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo) }
|
||||
@ -104,16 +106,19 @@ class GetDeviceFullInfoUseCaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given current session and no info for device when getting device info then the result is null`() = runTest {
|
||||
fun `given current session and no info for device when getting device info then the result is empty`() = runTest {
|
||||
// Given
|
||||
givenCurrentSessionCrossSigningInfo()
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData = MutableLiveData(Optional(null))
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData.givenAsFlow()
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.cryptoDeviceInfoWithIdLiveData = MutableLiveData(Optional(null))
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.cryptoDeviceInfoWithIdLiveData.givenAsFlow()
|
||||
|
||||
// When
|
||||
val deviceFullInfo = getDeviceFullInfoUseCase.execute(A_DEVICE_ID).firstOrNull()
|
||||
|
||||
deviceFullInfo shouldBeEqualTo Optional(null)
|
||||
// Then
|
||||
deviceFullInfo.shouldBeNull()
|
||||
verify { fakeActiveSessionHolder.instance.getSafeActiveSession() }
|
||||
verify { fakeActiveSessionHolder.fakeSession.fakeCryptoService.getMyDevicesInfoLive(A_DEVICE_ID).asFlow() }
|
||||
verify { fakeActiveSessionHolder.fakeSession.fakeCryptoService.getLiveCryptoDeviceInfoWithId(A_DEVICE_ID).asFlow() }
|
||||
@ -121,11 +126,14 @@ class GetDeviceFullInfoUseCaseTest {
|
||||
|
||||
@Test
|
||||
fun `given no current session when getting device info then the result is empty`() = runTest {
|
||||
// Given
|
||||
fakeActiveSessionHolder.givenGetSafeActiveSessionReturns(null)
|
||||
|
||||
// When
|
||||
val deviceFullInfo = getDeviceFullInfoUseCase.execute(A_DEVICE_ID).firstOrNull()
|
||||
|
||||
deviceFullInfo shouldBeEqualTo null
|
||||
// Then
|
||||
deviceFullInfo.shouldBeNull()
|
||||
verify { fakeActiveSessionHolder.instance.getSafeActiveSession() }
|
||||
}
|
||||
|
||||
|
@ -21,22 +21,21 @@ import com.airbnb.mvrx.test.MvRxTestRule
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
import im.vector.app.test.fakes.FakeSession
|
||||
import im.vector.app.test.test
|
||||
import im.vector.app.test.testDispatcher
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.api.auth.data.SessionParams
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
|
||||
private const val A_SESSION_ID = "session-id"
|
||||
|
||||
class SessionOverviewViewModelTest {
|
||||
|
||||
@get:Rule
|
||||
val mvRxTestRule = MvRxTestRule(testDispatcher = UnconfinedTestDispatcher())
|
||||
val mvRxTestRule = MvRxTestRule(testDispatcher = testDispatcher)
|
||||
|
||||
private val args = SessionOverviewArgs(
|
||||
deviceId = A_SESSION_ID
|
||||
@ -52,17 +51,20 @@ class SessionOverviewViewModelTest {
|
||||
|
||||
@Test
|
||||
fun `given the viewModel has been initialized then viewState is updated with session info`() {
|
||||
// Given
|
||||
val sessionParams = givenIdForSession(A_SESSION_ID)
|
||||
val deviceFullInfo = mockk<DeviceFullInfo>()
|
||||
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(Optional(deviceFullInfo))
|
||||
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo)
|
||||
val expectedState = SessionOverviewViewState(
|
||||
deviceId = A_SESSION_ID,
|
||||
isCurrentSession = true,
|
||||
deviceInfo = Success(deviceFullInfo)
|
||||
)
|
||||
|
||||
// When
|
||||
val viewModel = createViewModel()
|
||||
|
||||
// Then
|
||||
viewModel.test()
|
||||
.assertLatestState { state -> state == expectedState }
|
||||
.finish()
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.overview
|
||||
|
||||
import android.content.Intent
|
||||
import im.vector.app.features.settings.devices.v2.details.SessionDetailsActivity
|
||||
import im.vector.app.test.fakes.FakeContext
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.unmockkAll
|
||||
import io.mockk.verify
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
private const val A_SESSION_ID = "session_id"
|
||||
|
||||
class SessionOverviewViewNavigatorTest {
|
||||
|
||||
private val context = FakeContext()
|
||||
private val sessionOverviewViewNavigator = SessionOverviewViewNavigator()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockkObject(SessionDetailsActivity)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
unmockkAll()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a session id when navigating to details then it starts the correct activity`() {
|
||||
// Given
|
||||
val intent = givenIntentForSessionDetails(A_SESSION_ID)
|
||||
context.givenStartActivity(intent)
|
||||
|
||||
// When
|
||||
sessionOverviewViewNavigator.navigateToSessionDetails(context.instance, A_SESSION_ID)
|
||||
|
||||
// Then
|
||||
verify {
|
||||
context.instance.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun givenIntentForSessionDetails(sessionId: String): Intent {
|
||||
val intent = mockk<Intent>()
|
||||
every { SessionDetailsActivity.newIntent(context.instance, sessionId) } returns intent
|
||||
return intent
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.test.fakes
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.verify
|
||||
|
||||
class FakeClipboardManager {
|
||||
val instance = mockk<ClipboardManager>()
|
||||
|
||||
fun givenSetPrimaryClip() {
|
||||
every { instance.setPrimaryClip(any()) } just runs
|
||||
}
|
||||
|
||||
fun verifySetPrimaryClip(clipData: ClipData) {
|
||||
verify { instance.setPrimaryClip(clipData) }
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
|
||||
package im.vector.app.test.fakes
|
||||
|
||||
import android.content.ClipboardManager
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@ -74,4 +75,10 @@ class FakeContext(
|
||||
fun givenStartActivity(intent: Intent) {
|
||||
every { instance.startActivity(intent) } just runs
|
||||
}
|
||||
|
||||
fun givenClipboardManager(): FakeClipboardManager {
|
||||
val fakeClipboardManager = FakeClipboardManager()
|
||||
givenService(Context.CLIPBOARD_SERVICE, ClipboardManager::class.java, fakeClipboardManager.instance)
|
||||
return fakeClipboardManager
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user