Compare commits

...

933 Commits

Author SHA1 Message Date
Benoit Marty
f2c8d4ad02
Merge pull request #549 from vector-im/feature/third_party_invite
Fix rendering issue of accepted third party invitation event
2019-09-06 16:36:30 +02:00
Benoit Marty
be524472ec
Merge pull request #546 from vector-im/feature/cleanup
Cleanup
2019-09-06 16:25:08 +02:00
Benoit Marty
1b82a1a24d Cleanup 2019-09-06 15:52:29 +02:00
Benoit Marty
cf0b331c3b Handle invite to the current user rendering 2019-09-06 15:48:42 +02:00
Benoit Marty
2a92a3dc80 Fix rendering issue of accepted third party invitation event 2019-09-06 14:34:52 +02:00
Benoit Marty
012840abba Progress in initial sync dialog is decreasing for a step and should not (#532) 2019-09-05 18:14:05 +02:00
Benoit Marty
a5975a099e Cleanup and document DefaultInitialSyncProgressService 2019-09-05 17:23:09 +02:00
Benoit Marty
38da4b9ee5 Cleanup and document DefaultInitialSyncProgressService 2019-09-05 17:02:03 +02:00
Benoit Marty
242e60fcaa Rename CryptoManager to DefaultCryptoService 2019-09-05 16:14:34 +02:00
Benoit Marty
a23be05cbf Better type 2019-09-05 16:04:41 +02:00
Benoit Marty
ed39b02924 Avoid using keyword for variable names 2019-09-05 16:04:41 +02:00
Benoit Marty
fe931b5361
Merge pull request #418 from Dominaezzz/kotlinify-1
Some more kotlinification
2019-09-05 16:02:30 +02:00
Benoit Marty
90d9cd0587
Merge pull request #416 from Dominaezzz/kt-remove_java_util
Remove most usages of the java.util package
2019-09-05 15:33:03 +02:00
Benoit Marty
9cedb18921
Merge pull request #538 from vector-im/feature/log_mgmt
Reduce release build log level
2019-09-05 15:24:04 +02:00
Benoit Marty
e89ba7b87b Update wording 2019-09-05 15:23:38 +02:00
Benoit Marty
902657c22a
Merge pull request #537 from vector-im/feature/fix_crash
Fix crash due to missing informationData (#535)
2019-09-02 15:31:28 +02:00
Valere
eec2abf164 Reduce release build log level 2019-09-02 14:33:53 +02:00
Benoit Marty
6879cc8ca8 Fix crash due to missing informationData (#535) 2019-09-02 14:24:36 +02:00
Benoit Marty
fd6bbbd3b5 Fix issue with version name (Fixes #533) 2019-08-30 15:57:39 +02:00
Benoit Marty
0ff0b014a9 Version++ (0.5.0) 2019-08-30 15:07:04 +02:00
Benoit Marty
fdc9e84dd5 Merge branch 'release/0.4.0' into develop 2019-08-30 15:04:43 +02:00
Benoit Marty
58f878fca9 Prepare version 0.4.0 2019-08-30 15:04:28 +02:00
Benoit Marty
88095e4bd9 Add entry in change file 2019-08-30 14:54:15 +02:00
Benoit Marty
47d22a3d5e Import translation from Riot and MatrixSDK 2019-08-30 11:21:43 +02:00
Valere
28e82cb8ea
Merge pull request #531 from vector-im/feature/fix_crash_530
Fix / EmojiCompat not initialized
2019-08-29 17:46:51 +02:00
Valere
35817245cb refactoring, code review 2019-08-29 17:27:49 +02:00
Valere
75266f42bb Fix / EmojiCompat not initialized 2019-08-29 16:49:22 +02:00
Benoit Marty
95c4c9ce56
Merge pull request #527 from vector-im/feature/privacy
Privacy: remove log of notifiable event (#519)
2019-08-29 12:16:34 +02:00
Benoit Marty
ce5570105d Privacy: remove log of notifiable event (#519) 2019-08-29 10:36:45 +02:00
Benoit Marty
188a9aebfa
Merge pull request #525 from vector-im/feature/read_receipt_cleanup
Feature/read receipt cleanup
2019-08-29 10:19:06 +02:00
Benoit Marty
c95223f5d2 Add long click support on unsupported event 2019-08-28 18:17:37 +02:00
Benoit Marty
ef0362ba9c Display Read Receipt on unsupported events 2019-08-28 17:31:31 +02:00
Benoit Marty
ea242f6737 Hide ReadReceipt View when it is not relevant 2019-08-28 17:17:37 +02:00
Valere
cbc08d834b
Merge pull request #522 from vector-im/feature/fix_e2e_reply
Fix / regression on e2e reply and edit of reply
2019-08-28 10:38:22 +02:00
Valere
0ab6b33fb6
Merge branch 'develop' into feature/fix_e2e_reply 2019-08-28 10:38:12 +02:00
Valere
1b394527b6 cleaning + code review 2019-08-28 10:22:51 +02:00
Valere
a8f1388721
Merge pull request #520 from vector-im/feature/read_receipts_511
Improve read receipt design
2019-08-28 10:17:56 +02:00
Valere
166be4e289 Improve read receipt design 2019-08-28 09:56:10 +02:00
Valere
b49ccefe63
Merge pull request #521 from vector-im/feature/fix_dome_video_wont_play
Some video won't play
2019-08-28 03:43:35 -04:00
Valere
825760d17e Fix / regression on e2e reply and edit of reply 2019-08-27 17:05:04 +02:00
Valere
b5af62c3ea Some video won't play
VideoView fails to play some remote uri video on some device. For now video is downloaded locally in internal cache then played. This offers basic support before full media preview implementation
2019-08-27 16:50:02 +02:00
Valere
a51d96bf00
Merge pull request #325 from vector-im/feature/non_unicode_reaction
Accept non unicode reactions
2019-08-27 08:10:51 -04:00
Valere
7e142d201d Use EmojiCompat to build EmojiSpans from text 2019-08-27 11:06:52 +02:00
Valere
2be6058971 accept non unicode reactions 2019-08-27 10:58:21 +02:00
Valere
49d73f360e
Merge pull request #494 from vector-im/feature/fix_441
Fix text diff removed linebreak
2019-08-27 04:36:03 -04:00
Valere
bd88d85a21
Merge branch 'develop' into feature/fix_441 2019-08-27 04:35:17 -04:00
Valere
be4fc5cce6
Merge pull request #493 from vector-im/feature/fix_358
Date change message repeats for each redaction until a normal message
2019-08-27 04:34:35 -04:00
Valere
704da1be55
Merge branch 'develop' into feature/fix_358 2019-08-27 04:34:24 -04:00
Valere
5d002532d3
Merge pull request #495 from vector-im/feature/fix_423
Slide-in reply icon is distorted
2019-08-27 04:22:02 -04:00
Valere
d4161e9a1a Fix text diff removed linebreak 2019-08-27 10:17:42 +02:00
Valere
7966ebef03 Date change message repeats for each redaction until a normal message 2019-08-27 10:16:11 +02:00
Valere
ed5faca5d2 Slide-in reply icon is distorted 2019-08-27 10:06:20 +02:00
Benoit Marty
8ca829d538 An error was displayed by mistake 2019-08-19 17:22:04 +02:00
ganfra
e7819ce678
Merge pull request #496 from vector-im/feature/di_clean
Dagger clean
2019-08-19 16:41:50 +02:00
ganfra
5402902bc2 Merge branch 'develop' into feature/di_clean 2019-08-19 15:04:26 +02:00
ganfra
bc1350aaf5
Merge pull request #484 from vector-im/feature/timeline_read_receipts
Feature/timeline read receipts
2019-08-19 14:29:59 +02:00
ganfra
fd74e3dfb1 Read receipts: clean code after review 2019-08-19 14:08:15 +02:00
ganfra
e0628da1cb Dagger: use AssistedInjectModule for viewModel + use AssistedFactory for room dependencies 2019-08-14 19:09:56 +02:00
Benoit Marty
aa4e74e986
Merge pull request #487 from vector-im/feature/fix_ui_issues
Feature/fix ui issues
2019-08-14 18:20:08 +02:00
Benoit Marty
6cc0c0672e
Merge pull request #474 from vector-im/feature/dev_suffix
Automatic "-dev" version suffix on non master branch
2019-08-14 18:15:44 +02:00
ganfra
501474b720 Fix code quality issues 2019-08-14 14:53:40 +02:00
ganfra
e11c66035c Theme: the action menu text items should use colorAccent 2019-08-14 14:19:21 +02:00
ganfra
3d2d219d79 Room list: let the fab animation be quicker 2019-08-14 14:18:56 +02:00
ganfra
63af03bedd List: add overScroll 2019-08-14 14:18:42 +02:00
ganfra
d3827b8673 Read receipts: branch settings to show/hide them 2019-08-14 10:51:09 +02:00
Benoit Marty
4ca2531e47 develop branch will have version code from timestamp, to ensure each build from CI has a incremented versionCode
Other branches (master, features, etc.) will have version code based on application version.
2019-08-14 10:45:17 +02:00
ganfra
4e8dc72439 Update CHANGES 2019-08-13 15:17:04 +02:00
ganfra
25a4240a5a Merge branch 'develop' into feature/timeline_read_receipts 2019-08-13 15:16:10 +02:00
ganfra
b9cfda23b6 Read receipts: just juste invisible on hidden avatars, to have a bigger touch zone 2019-08-13 15:06:00 +02:00
ganfra
06dcf75a32 Read receipts: fix not appearing RR 2019-08-13 12:06:49 +02:00
ganfra
21deb2551d Read receipts: handle read receipts set on filtered events + let BottomSheet takes a snapshot instead of being live. 2019-08-12 17:59:07 +02:00
ganfra
70639f180c Read receipts: add read receipts bottom sheet 2019-08-08 19:59:20 +02:00
ganfra
1dbb02a80d Read receipts: create custom view to use it wherever we want easily 2019-08-08 17:51:06 +02:00
ganfra
825463d9cd Change package for NotificationAreaView 2019-08-08 17:50:33 +02:00
ganfra
c313ce78cb Read receipts: sort descending by timestamp 2019-08-08 17:49:50 +02:00
ganfra
39f58d048b Read receipts: fix dummy being overrided 2019-08-08 17:49:31 +02:00
Benoit Marty
3f792c7a84 Automatic "-dev" version suffix on non master branch 2019-08-08 16:57:03 +02:00
Benoit Marty
347dcb469a Version++ 2019-08-08 16:47:13 +02:00
Benoit Marty
79fb1985aa Merge branch 'release/0.3.0' into develop 2019-08-08 16:45:02 +02:00
Benoit Marty
e216cd15a8 Prepare release 0.3.0 2019-08-08 16:44:53 +02:00
Benoit Marty
37fde374b3
Merge pull request #469 from vector-im/feature/versionCode_auto
Ensure versionCode is the wanted one for GPlay and F-Droid build
2019-08-08 16:32:10 +02:00
Benoit Marty
f7b471f141 Stop using BuildConfig.VERSION_CODE, it is not the correct value 2019-08-08 16:31:45 +02:00
Benoit Marty
93fd56a7ca Ensure versionCode is the wanted one for GPlay and F-Droid build 2019-08-08 16:30:44 +02:00
Benoit Marty
5a9d88e791
Merge pull request #473 from vector-im/feature/sync_room
Feature/sync room
2019-08-08 16:15:26 +02:00
Benoit Marty
eaf6a9923a Cancel sync request on pause and timeout to 0 after pause (#404) 2019-08-08 16:04:53 +02:00
ganfra
d98567045c Read receipts: use a simpler strategy when it's initialSync 2019-08-08 15:03:36 +02:00
ganfra
b4ce8748cb First step in handling read receipts 2019-08-08 14:32:11 +02:00
Benoit Marty
9d5433a857 Show sync progress also in room detail screen (#403) 2019-08-08 14:14:10 +02:00
Benoit Marty
6d4ee83e65
Merge pull request #472 from vector-im/feature/vectorPref
Dagger for VectorPreferences and /markdown command as a bonus
2019-08-08 12:43:22 +02:00
Benoit Marty
6e44cca17d Handle /markdown command 2019-08-08 12:09:05 +02:00
Benoit Marty
0a73887c70 Daggerization of VectorPreferences 2019-08-08 11:52:50 +02:00
ganfra
7fef063e15
Merge pull request #468 from vector-im/feature/fix_realm_issues
Feature/fix realm issues
2019-08-07 18:05:06 +02:00
Benoit Marty
24f391dac0
Merge pull request #467 from vector-im/feature/playstore_crash
Feature/playstore crash
2019-08-07 17:10:49 +02:00
Benoit Marty
81c7f694d6 Import Strings form Riot 2019-08-07 16:10:50 +02:00
Benoit Marty
80e2fc0ca3
Merge pull request #466 from vector-im/feature/edit_history_item
Add "View Edit History" item in the message bottom sheet (#401)
2019-08-07 15:08:26 +02:00
Benoit Marty
9f53406e99 Fix crash (KotlinNullPointerException) observed on PlayStore 2019-08-07 13:35:44 +02:00
Benoit Marty
3584658c36 Fix crash (IllegalStateException) observed on PlayStore 2019-08-07 13:24:43 +02:00
Benoit Marty
12a0cbb400 Fix crash observed on PlayStore 2019-08-07 13:16:04 +02:00
Benoit Marty
20437446b4 Add "View Edit History" item in the message bottom sheet (#401) 2019-08-07 13:05:22 +02:00
Benoit Marty
35229882e3 Fix (edited) link can be copied to clipboard (#402) 2019-08-07 12:28:21 +02:00
Benoit Marty
a04f4421f6
Merge pull request #464 from vector-im/feature/splitApk
Split apk
2019-08-07 12:11:13 +02:00
Benoit Marty
af1e81f65e Remove unused react native lib, and ensure dependencies lib are explicitly declared 2019-08-07 11:53:59 +02:00
Benoit Marty
63f6081fa5 Split APK: generate one APK per arch, to reduce APK size of about 30% 2019-08-07 11:46:38 +02:00
Benoit Marty
ee2e575211 Display VersionCode of the app in the settings, because Android system does not display it anymore 2019-08-07 11:44:51 +02:00
ganfra
0949d29f9c Let TimelineEvent be queried by SendState 2019-08-07 10:54:54 +02:00
Benoit Marty
23466fb5a4
Merge pull request #463 from vector-im/feature/fix_theme
Fix theme not well defined at runtime after configurationChange
2019-08-07 10:40:33 +02:00
ganfra
7f09e64d63 Fix timeline forward loader showing when sending events 2019-08-07 09:59:37 +02:00
ganfra
585f0ba4b7 Add an identifier method on ChunkEntity 2019-08-06 21:32:45 +02:00
ganfra
245fbe86d9 Get enum safe with realm entities 2019-08-06 21:32:40 +02:00
Dominic Fischer
456908c851
Merge branch 'develop' into kt-remove_java_util 2019-08-06 18:27:39 +01:00
ganfra
b79fdf6a85 Fix theme not well defined at runtime after configurationChange 2019-08-06 18:55:38 +02:00
Benoit Marty
d9f448c9aa
Merge pull request #459 from vector-im/feature/clenup_after_hol
Review of merged PRs
2019-08-06 18:39:37 +02:00
Benoit Marty
7a6fc4936b Start chain: create extension 2019-08-06 18:15:15 +02:00
Benoit Marty
d82fd10f3b Start chain: add missing cases 2019-08-06 18:15:15 +02:00
Benoit Marty
4009f2c176 Add comment to explain why we use a AlwaysSuccessfulWorker 2019-08-06 18:15:15 +02:00
Benoit Marty
15c4b03340 Event: do not display sendState in View Source and cleanup the class 2019-08-06 18:14:24 +02:00
Benoit Marty
7b5dff3dcf Mutualize :? part 2019-08-06 18:14:24 +02:00
Benoit Marty
357123743f Search firstIndexOf, because server url can contains port (This is what JS does, but Riot Android is also bugged) 2019-08-06 18:14:24 +02:00
Benoit Marty
bb04af1e2c Remove useless code 2019-08-06 18:14:24 +02:00
Benoit Marty
2f94fbd7eb Use existing method 2019-08-06 18:14:24 +02:00
Benoit Marty
f2a3bdb68e Kotlin style 2019-08-06 18:14:24 +02:00
Benoit Marty
097e9714ff Cleaner code 2019-08-06 18:14:24 +02:00
Benoit Marty
acae0fad3e Better private method name 2019-08-06 18:14:24 +02:00
Benoit Marty
4deb7eb865 Javadoc for NoMerger 2019-08-06 18:14:24 +02:00
Benoit Marty
f910cd6f97 More robust SDK: retry only when on failure 2019-08-06 18:14:24 +02:00
Benoit Marty
652ac81fa1 simple code 2019-08-06 18:14:24 +02:00
Benoit Marty
99f4196388 More code cleanup/review 2019-08-06 18:14:24 +02:00
Benoit Marty
c0b94f4111 Typo 2019-08-06 18:14:24 +02:00
Benoit Marty
1462fa0484 Simple code 2019-08-06 18:14:24 +02:00
Benoit Marty
dafdc1d3ad Cleaner API 2019-08-06 18:07:35 +02:00
Benoit Marty
394b89e76b Avoid duplicated code 2019-08-06 18:07:35 +02:00
Benoit Marty
0db8e7da43 Format 2019-08-06 18:07:35 +02:00
ganfra
dae8b5c196
Merge pull request #460 from vector-im/feature/fix_cancellations
Feature/fix cancellations
2019-08-06 18:06:05 +02:00
Dominic Fischer
215324a03e Some kotlinification
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2019-08-06 11:36:39 +01:00
ganfra
d3ce4c491c Clean code after review 2019-08-06 11:45:06 +02:00
Benoit Marty
ed6d28bd3b
Merge pull request #417 from Dominaezzz/kt-opt
Some optimisations
2019-08-06 11:42:07 +02:00
Benoit Marty
c2e053b62b
Merge pull request #414 from Dominaezzz/kt-leak
Fix potential resource leak
2019-08-06 11:39:51 +02:00
Benoit Marty
c450849cc3
Merge pull request #425 from Cadair/patch-1
Fix reply fallback prefix
2019-08-06 11:23:37 +02:00
ganfra
fe884dba2d Update CHANGES.md and fix code quality 2019-08-05 20:28:50 +02:00
ganfra
3fa4dbaa25 Make async transaction working with suspend method 2019-08-05 20:17:59 +02:00
ganfra
4a74f58516 Task: use a builder with DSL and introduce Constraints (only boolean connectedToNetwork at the moment) 2019-08-05 20:17:36 +02:00
ganfra
c413321a22 Remove unnecessary code and fix signout 2019-08-02 13:15:56 +02:00
ganfra
d696bd2830 Send worker: let LIMIT_EXCEEDED error to be retry 2019-08-02 11:36:32 +02:00
ganfra
a2b6bd0f62 Fix network reconnection with sync 2019-08-02 11:35:58 +02:00
ganfra
9cc922a8a2 Optimize imports 2019-08-02 11:35:27 +02:00
Valere
c36d1bcd06
Merge pull request #456 from vector-im/feature/fix_image_transition_overlap
Fix / Shared element transition overlap
2019-08-02 10:18:14 +02:00
Valere
85499c6b33 fix for background overlaps 2019-08-02 10:00:33 +02:00
Valere
8076eab4b5 Fix / Shared element transition overlap
Shared element was overlapping top system bars
2019-08-02 10:00:33 +02:00
Valere
d47c0f5ebc Fix / layout res in debug instead of main 2019-08-02 09:59:59 +02:00
ganfra
fd09a1224e Remove Try from suspending functions 2019-08-01 17:15:17 +02:00
ganfra
c300c50093
Merge pull request #449 from vector-im/feature/room_update
Feature/room upgrade
2019-07-31 15:34:38 +02:00
ganfra
77c4355aed Merge branch 'develop' into feature/room_update 2019-07-31 14:27:12 +02:00
ganfra
1a92562182 Clean code after review 2019-07-31 14:06:10 +02:00
ganfra
9c390dcc0c
Merge pull request #453 from vector-im/feature/fix_code_quality
Fix code quality issues
2019-07-30 21:54:38 +02:00
ganfra
95089b91b8 UserAccountData: optimize helper and clean code. 2019-07-30 21:41:29 +02:00
ganfra
eb446d7b49 Fix code quality issues 2019-07-30 21:20:30 +02:00
ganfra
dc4786ecf0 Room upgrade: add rx flux and handle failures more precisely 2019-07-30 19:13:09 +02:00
Valere
e245023add
Merge pull request #444 from vector-im/feature/fail_to_send_msg
Basic Message Failure support + Resend (text only)
2019-07-30 18:31:53 +02:00
Stuart Mumford
90fad23493
Fix reply fallback prefix
Plain text reply fallback should be prefixed with "> " not ">" (as per spec).

Signed-off-by: Stuart Mumford <stuart@cadair.com>
2019-07-30 12:09:29 -04:00
Valere
000db4b192 Basic Message Failure support + Resend (text only)
+ clean worker inputs when starting new independent task in unique queue
2019-07-30 17:53:43 +02:00
ganfra
2a16c36a59
Merge pull request #451 from vector-im/feature/fix_user_account_data_direct
User Account Data: fix sync issues with direct invites
2019-07-30 17:39:12 +02:00
ganfra
ef6c1cfc63 RoomSummaryUpdater: remove unused params 2019-07-30 17:37:16 +02:00
ganfra
4b4156996d User Account Data: fix sync issues with direct invites 2019-07-30 17:32:31 +02:00
Valere
087cc0e6e3
Merge pull request #448 from danteissaias/develop
Fix #447
2019-07-30 17:07:22 +02:00
ganfra
f4df27c2dc Merge branch 'develop' into feature/room_update 2019-07-30 15:51:56 +02:00
ganfra
ab25980c4e
Merge pull request #437 from vector-im/feature/create_direct_room
Feature/create direct room
2019-07-30 15:13:30 +02:00
Dante Issaias
77b402ce70
updates CHANGES.md
Signed-off-by: Dante Issaias <dante.issaias@gmail.com>
2019-07-30 14:01:41 +01:00
Dante Issaias
2763fbb496
fix #447
Signed-off-by: Dante Issaias <dante.issaias@gmail.com>
2019-07-30 13:57:04 +01:00
ganfra
6deba31111 Direct room: finally use PagedList as we can get a lot of users in DB. 2019-07-30 14:51:14 +02:00
ganfra
ff6ce8a4b7 Create direct : remove letter headers when filtering 2019-07-29 19:13:06 +02:00
ganfra
d0cff219aa
Merge pull request #446 from vector-im/feature/remove_identity_default
Remove default identity server as we don't use it.
2019-07-29 18:32:07 +02:00
ganfra
65f0af918f Remove default identity server as we don't use it. 2019-07-29 18:26:26 +02:00
ganfra
ac38a6461c Tombstone : handle joining viaserver params 2019-07-26 19:17:12 +02:00
ganfra
9a1e16a170 Tombstone : add notification area and handle links 2019-07-26 14:51:14 +02:00
ganfra
9e5c70dda3 Room update: start handling tombstone and room create events [WIP] 2019-07-25 19:34:39 +02:00
ganfra
0255696c88 Update CHANGES 2019-07-25 16:49:15 +02:00
ganfra
76a9625f25 Direct chat : finalize flow 2019-07-25 16:34:27 +02:00
ganfra
5af6bf3762 Direct room: finally handle selection with chips (not as Nad design) 2019-07-25 16:34:27 +02:00
ganfra
507bc2f622 UserEntity: fix not inserted at all 2019-07-23 21:31:58 +02:00
ganfra
125eacb20b Direct messages: try to handle selecting/deselecting users (WIP) 2019-07-23 19:53:47 +02:00
Valere
6176520805
Merge pull request #407 from vector-im/feature/pending_edits_ux
Feature/pending edits ux
2019-07-22 23:53:26 +02:00
Valere
3aea0a50ca
Merge branch 'develop' into feature/pending_edits_ux 2019-07-22 23:53:16 +02:00
Valere
ab87a3caea
Merge pull request #397 from vector-im/feature/animation_image_preview
Better image fullscreen preview animation
2019-07-22 23:37:15 +02:00
Valere
c58328f94e cleaning / review 2019-07-22 23:36:19 +02:00
ganfra
03974c8bdf Create Direct Room : fix loading/error state (WIP) 2019-07-22 19:01:17 +02:00
ganfra
151ae7f4dd Direct chat: handle user account data 2019-07-22 18:58:55 +02:00
Dominic Fischer
a34b053efe Some optimisations
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2019-07-21 23:35:38 +01:00
Dominic Fischer
02e342849f Remove most usages of the java.util package
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2019-07-21 23:23:56 +01:00
Dominic Fischer
b59017938b Fix potential leak
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2019-07-21 19:11:53 +01:00
ganfra
2c81e41288 Merge branch 'develop' into feature/create_direct_room 2019-07-19 18:18:22 +02:00
ganfra
cb44ab547c Create direct room: almost finished, still need to handle showing selected users in search field 2019-07-19 18:12:42 +02:00
Benoit Marty
6d01a570fd Clear notification for a room left on another client 2019-07-19 16:44:30 +02:00
Valere
4a2bf0d6c6 Cleaning Lint 2019-07-19 16:18:47 +02:00
Valere
36af8a6a9f Lab / show replace in timeline when show hidden event selected 2019-07-19 16:13:55 +02:00
Valere
40a68c3e9f Show pending edits by fading the event body #193
+ Fix issues with edits local echo management in aggregation
2019-07-19 16:13:35 +02:00
Benoit Marty
1a4ec34bb2 Code cleanup 2019-07-19 16:03:37 +02:00
Benoit Marty
10490e3aa6 Close detail room screen when the room is left with another client (#256) 2019-07-19 16:00:06 +02:00
Benoit Marty
cd6624a8a6 Fix issue on setting screen: bad alignment of title 2019-07-19 15:15:29 +02:00
Valere
3965218bf9 Cleaning / Review 2019-07-19 12:12:17 +02:00
Valere
d78ff7ab08 Fix / can't zoom after rotation 2019-07-19 11:58:24 +02:00
ganfra
cb274d6a33 Add some cancelable on service methods and start branching Rx 2019-07-19 11:21:16 +02:00
Valere
c00dbce536 Fix #390
(edited) string in edited message body
2019-07-19 09:58:53 +02:00
Valere
db88caf7fa Better image fullscreen preview animation 2019-07-18 18:53:46 +02:00
Benoit Marty
c3d945d6bb Version++ 2019-07-18 17:48:56 +02:00
Benoit Marty
4c128602b2 Merge branch 'release/0.2.0' into develop 2019-07-18 17:47:39 +02:00
Benoit Marty
d609c49b31 Prepare release 0.2.0 2019-07-18 17:47:24 +02:00
ganfra
001603cf9a Create direct room: add filtering and enhance design a bit 2019-07-18 17:42:22 +02:00
Valere
d87ee32422
Merge pull request #384 from vector-im/feature/edit_e2e
Feature/edit e2e
2019-07-18 16:44:44 +02:00
Benoit Marty
f0671b9e73 "Riot X" -> "RiotX" 2019-07-18 14:28:46 +02:00
Benoit Marty
e218691bf2 Import strings and translation from Riot 2019-07-18 14:25:34 +02:00
Valere
9c67036c08 Fix / keyboard won't show when using reply from long tap menu 2019-07-18 12:13:17 +02:00
ganfra
62657538af
Merge pull request #389 from vector-im/feature/cleanup
Do not show invitation in the filtered room list
2019-07-18 12:10:47 +02:00
Valere
5438207fba faster animation for quick reply 2019-07-18 12:01:23 +02:00
Benoit Marty
fe88aaffbd Inject RoomListNameFilter 2019-07-18 11:39:13 +02:00
Benoit Marty
21ba72e5e7 Do not show invitation in the filtered room list 2019-07-18 11:34:49 +02:00
Benoit Marty
d48ae967bd Remove dead code 2019-07-18 11:11:42 +02:00
Benoit Marty
0afde3b021 Rename class member for code clarity 2019-07-18 11:07:09 +02:00
Benoit Marty
49ae954183 Merge remote-tracking branch 'origin/develop' into develop 2019-07-18 10:58:40 +02:00
Benoit Marty
64bee91f7a
Merge pull request #387 from vector-im/feature/fix_sync_state
Fix sync state progress bar
2019-07-18 10:57:46 +02:00
ganfra
4341b0d0f5 Merge branch 'develop' into feature/create_direct_room 2019-07-18 09:47:25 +02:00
Valere
51fdccb393 cleaning 2019-07-18 09:29:27 +02:00
ganfra
7e3b300130 Fix sync state progress bar 2019-07-17 19:45:35 +02:00
Benoit Marty
a98b324c89
Merge pull request #385 from vector-im/feature/invit_notif
Cancel invitation notification when handling the invitation in the application
2019-07-17 18:39:40 +02:00
Benoit Marty
977721881f Cancel invitation notification when handling the invitation in the application 2019-07-17 18:35:41 +02:00
ganfra
838003b68a Create direct room: start creating all the required stuff 2019-07-17 18:30:14 +02:00
Valere
7d41352918 Fix / edit reply was quoting wrong text
+ e2e reply of edit
2019-07-17 16:46:56 +02:00
Valere
077396a832 E2E replies
+ Edit History / support e2e and use original event
2019-07-17 16:20:12 +02:00
Benoit Marty
32b79bd50e Remove extra space around userId 2019-07-17 15:13:12 +02:00
Benoit Marty
844f6d16a4 Code quality 2019-07-17 15:05:29 +02:00
Benoit Marty
fc9ef579ca
Merge pull request #381 from vector-im/feature/room_members_perf
Feature/room members perf
2019-07-17 15:01:06 +02:00
Benoit Marty
77fa5af1b8 Fix compilation issue after merge 2019-07-17 14:58:23 +02:00
ganfra
2948018453 Clean code after review 2019-07-17 14:56:00 +02:00
Benoit Marty
90d25ff45e Code cleanup 2019-07-17 14:41:01 +02:00
Benoit Marty
173452d38c
Merge pull request #367 from Dominaezzz/kotlinify-3
Some more kotlinification.
2019-07-17 14:38:16 +02:00
Benoit Marty
a9f9083745
Merge pull request #374 from vector-im/feature/quick_fix_long_click_link
WIP /  Fix Copying link from a message shouldn't open context menu
2019-07-17 14:37:11 +02:00
Valere
22dc2a6790 Fix Copying link from a message shouldn't open context menu 2019-07-17 14:36:47 +02:00
Benoit Marty
927cd7285d
Merge pull request #378 from vector-im/feature/fix_sync_thread_wrong_autostart
Fix / SyncThread was started in background
2019-07-17 14:32:19 +02:00
Benoit Marty
4d5bdecec6
Merge pull request #382 from vector-im/feature/better_long_tap_menu
Feature/better long tap menu
2019-07-17 14:28:51 +02:00
Benoit Marty
0be987ac0d
Merge branch 'develop' into feature/better_long_tap_menu 2019-07-17 14:28:36 +02:00
Valere
4bfaa00be4 Fix / clean bad method name 2019-07-17 14:27:02 +02:00
Benoit Marty
8e78d8a58d
Merge pull request #380 from vector-im/feature/rs_crash_steve
Fix a crash in notificationwhen display name is empty
2019-07-17 14:22:45 +02:00
Benoit Marty
e3e86c0a41
Merge pull request #383 from vector-im/feature/filter_params
Pass filter to room directory screen or create room screen
2019-07-17 14:20:29 +02:00
Benoit Marty
8a5fddd952
Merge pull request #379 from vector-im/feature/small_fixes
Fix bad View used for searching in room directory.
2019-07-17 14:19:37 +02:00
ganfra
208460850e Dagger: activate incremental build 2019-07-17 14:16:20 +02:00
Benoit Marty
0ddef67cc9 Migrate to rxbinding 3 and fix bad layout for room directory filter (Fixes #349) 2019-07-17 14:16:20 +02:00
Benoit Marty
896e582a9c Create style VectorSearchView 2019-07-17 14:16:20 +02:00
Benoit Marty
477920f411 Add some comment 2019-07-17 14:14:02 +02:00
Benoit Marty
c647648e79
Merge pull request #371 from vector-im/feature/composer_fix_edit_reply
Feature/composer fix edit reply
2019-07-17 14:03:10 +02:00
Benoit Marty
b654025a3b Fix alignment issue in toolbars 2019-07-17 12:38:35 +02:00
Benoit Marty
786a7d7560 Rename id 2019-07-17 12:20:11 +02:00
Benoit Marty
b935b9311e Scroll the list to top after each new filter 2019-07-17 12:18:45 +02:00
Benoit Marty
8e12f71535 Add top left back button 2019-07-17 12:16:10 +02:00
Benoit Marty
7eea2ccfb4 Fix infinite opening of room once the room is created 2019-07-17 12:09:09 +02:00
Benoit Marty
c32ef02a12 Pre fill the room directory filter and and the room name with the already entered string from the user 2019-07-17 12:04:19 +02:00
Benoit Marty
3651ec4870 Add some doc 2019-07-17 11:58:18 +02:00
Valere
87de7bd3e6 fix lint code quality 2019-07-17 11:41:14 +02:00
Valere
9494174c33 Swipe to reply in timeline (lab) 2019-07-17 10:54:15 +02:00
ganfra
b7e0b400fb Timeline : set bigger initial load size 2019-07-16 17:48:32 +02:00
ganfra
a8f06f609b Use latest retrofit version to properly cancel requests
Fix cancelation requests
2019-07-16 17:46:52 +02:00
ganfra
d469299f42 RoomMembers: should fix state events issues 2019-07-16 17:46:52 +02:00
Valere
9bdea5b325 Change order of actions (and reply on top) 2019-07-16 16:35:57 +02:00
Valere
2f01ad99b3 Compact long tap menu 2019-07-16 16:35:36 +02:00
Benoit Marty
bb3b5788ba Update hint from design 2019-07-16 16:35:10 +02:00
Benoit Marty
45f7d3e9c4 Kotlin style 2019-07-16 15:59:08 +02:00
Benoit Marty
0f7a56d005 Use Session.myUserId whereas it's possible 2019-07-16 15:54:00 +02:00
Valere
63d2861bc8 Fix / SyncThread was started in background
Upon reception of a push, is the session is instantiated the sync thread was starting to loop
2019-07-16 15:44:08 +02:00
Benoit Marty
6bbc784c29 Fix crash (from Steve's rageshake) 2019-07-16 15:42:02 +02:00
Valere
c6fd625761 code review 2019-07-16 14:56:16 +02:00
Valere
d8092abc4e fix / strip reply prefix on history 2019-07-16 14:39:46 +02:00
Valere
6effb90361 Fix / edit of reply and edit of edit of reply 2019-07-16 14:39:05 +02:00
Benoit Marty
42584fc55a
Merge pull request #372 from vector-im/feature/room_filtering
Room filtering
2019-07-16 11:41:08 +02:00
Benoit Marty
30d9ddb3e8
Merge pull request #373 from vector-im/feature/fix_composer_separator_dark
Fix / composer separator color was using a clear theme color
2019-07-15 18:16:06 +02:00
Valere
020c32bb1a Fix / composer separator color was using a clear theme color 2019-07-15 17:46:24 +02:00
Benoit Marty
efd973208f Green close icon 2019-07-15 17:35:51 +02:00
Benoit Marty
30a6c98c08 Room name in bold 2019-07-15 17:29:37 +02:00
Benoit Marty
1440080d04 Changes 2019-07-15 17:27:49 +02:00
Benoit Marty
61bb4c0427 Introduce CreateRoomActivity, a simple container for [CreateRoomFragment] 2019-07-15 17:26:48 +02:00
Benoit Marty
3c25088243 Filter rooms 2019-07-15 17:26:48 +02:00
Benoit Marty
fc1c0caea3 Avoid displaying two loaders if there is no elements between them 2019-07-15 17:25:59 +02:00
Valere
8901a5e09a
Merge pull request #342 from vector-im/feature/edit_history
Feature/edit history
2019-07-15 15:15:45 +02:00
Valere
25f1d21bc7 Edit history
Get history from API


cleaning


Updated change log


Missing copyrights


Code review


cleaning
2019-07-15 14:57:12 +02:00
Benoit Marty
4d2ab9fa31
Merge pull request #344 from vector-im/feature/play_store_crash
Feature/play store crash
2019-07-15 10:49:20 +02:00
Benoit Marty
0289d2ee87 Simpler code 2019-07-15 10:48:44 +02:00
Benoit Marty
222201cc64 Fix crash observe on the PlayStore (#341) 2019-07-15 10:48:44 +02:00
Benoit Marty
b15dea6de3
Merge pull request #338 from vector-im/feature/green_encrypt
Text in green when encrypting
2019-07-15 10:46:44 +02:00
Benoit Marty
2ba83e456d
Merge pull request #343 from vector-im/feature/click_on_redacted_event
Handle click on redacted event
2019-07-15 10:46:06 +02:00
Dominic Fischer
1822fc4fbb Some more kotlinification
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2019-07-13 15:35:10 +01:00
Dominic Fischer
e6dd1fbfec Use GlobalScope instead of temp scope
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2019-07-13 15:18:16 +01:00
Benoit Marty
e2ea76f871 Fix crash reported by PlayStore 2019-07-12 16:48:35 +02:00
ganfra
9182f2ce4e RoomMembers/User : get a better and faster handling (still need to fix one small issue) 2019-07-12 13:59:37 +02:00
Benoit Marty
34d14eb304 Fix regression on permalink click 2019-07-12 13:51:37 +02:00
Benoit Marty
3625c462f0 Click on redacted event 2019-07-12 13:51:37 +02:00
Benoit Marty
fe69206340 Prepare next release 2019-07-12 11:39:26 +02:00
Benoit Marty
f9885fd04c Update CHANGES.md 2019-07-12 11:38:55 +02:00
Benoit Marty
316c8ec27e
Merge pull request #265 from vector-im/readme_update_for_beta
README: Update it for the beta launch
2019-07-12 11:36:49 +02:00
Benoit Marty
41465450d8 Code cleanup 2019-07-12 10:45:08 +02:00
Benoit Marty
bd009caaf1 Code cleanup 2019-07-12 10:22:58 +02:00
Benoit Marty
33252c3b65 Green text color during encrypting 2019-07-12 10:16:43 +02:00
ganfra
10e4d0190f Try to insert users directly to see if perfs are better [WIP] 2019-07-11 18:55:13 +02:00
Benoit Marty
b77310fe92
Merge pull request #337 from vector-im/feature/debug_suffix
Add ".debug" to the applicationId to be able to install the app along with the prod version
2019-07-11 18:33:43 +02:00
Benoit Marty
919dec4a56 Add ".debug" to the applicationId to be able to install the app along with the prod version 2019-07-11 17:59:07 +02:00
Benoit Marty
43b3680774 Prepare next release 2019-07-11 17:44:58 +02:00
Benoit Marty
bfb5fce809 Update CHANGES.md 2019-07-11 17:43:56 +02:00
Benoit Marty
1f3731aae7 Merge branch 'master' into develop 2019-07-11 17:42:11 +02:00
Benoit Marty
52dced43ff Fix version code issue 2019-07-11 16:49:06 +02:00
Benoit Marty
ff80c3c8d5 Add script to sign the APK. 2019-07-11 16:41:45 +02:00
Benoit Marty
34e4d27573 Add missing space in pipeline 2019-07-11 16:00:45 +02:00
Benoit Marty
6522148e63 Merge branch 'release/0.1.0' 2019-07-11 15:54:48 +02:00
ganfra
252b2ea30a
Merge pull request #334 from vector-im/feature/general_perf
Feature/general perf
2019-07-11 15:52:00 +02:00
ganfra
f493ce44f2 RealmLiveEntity: passes the results and changeSet instead of filtering as it's more efficient 2019-07-11 15:30:01 +02:00
Benoit Marty
c4c5069ee5
Merge pull request #332 from vector-im/feature/login_warning
Improve login screen
2019-07-11 15:25:11 +02:00
Benoit Marty
423125b5d9
Merge pull request #333 from vector-im/feature/timeout
Create a TimeOutInterceptor to set specific timeout on some request
2019-07-11 15:24:54 +02:00
Benoit Marty
9e3d29b7d7 Create a TimeOutInterceptor to set specific timeout on some request: login and sync (Fixes #170) 2019-07-11 15:16:25 +02:00
Benoit Marty
f65becf7c0 Rework login screen before release 2019-07-11 14:38:30 +02:00
Benoit Marty
80a61cf6b5 Improve dependency download safe path 2019-07-11 14:03:20 +02:00
Benoit Marty
77056aff94
Merge pull request #330 from vector-im/feature/edit_emote
Edit emote
2019-07-11 13:34:46 +02:00
Benoit Marty
65e123d87f Split long lines 2019-07-11 13:32:28 +02:00
Valere
d0b145d031 Edit emote 2019-07-11 12:29:02 +02:00
Valere
98306e223b
Merge pull request #322 from vector-im/feature/clean
Improve reply feature
2019-07-11 11:46:00 +02:00
Benoit Marty
c9fe1adb77 Add a debug button to test crash of the app 2019-07-11 10:36:59 +02:00
ganfra
1b95336ad3 EventEntity|TimelineEventEntity : remove UUID as primary key and use auto-incremented Long 2019-07-11 10:25:30 +02:00
ganfra
f007fb04b8 Timeline: clean listeners 2019-07-11 10:25:30 +02:00
ganfra
141434e8f8 Try getting things off the main thread 2019-07-11 10:25:30 +02:00
ganfra
b8669d5ed2 Sync: use a single threaded executor to ensure we have only one sync at a time 2019-07-11 10:23:24 +02:00
Benoit Marty
7a08a11b19 Fix compilation of test 2019-07-10 18:17:03 +02:00
Valere
54b1d18812 Merge remote-tracking branch 'origin/feature/clean' into feature/clean 2019-07-10 18:07:03 +02:00
Valere
3aa30e5f15 Fix reply of reply 2019-07-10 18:06:44 +02:00
Benoit Marty
ddf4a81905 Do not display the banner when keys backup is sending keys 2019-07-10 18:04:27 +02:00
Benoit Marty
794fd650a4 Mutualize code, and also, when replying to an edited event, use the last text in the reply prefix content 2019-07-10 17:37:22 +02:00
Benoit Marty
9a57a02996 Cleaner code: add TimelineEvent to special modes 2019-07-10 17:05:32 +02:00
Benoit Marty
7e8cd07e1e Do not send edition if text is identical 2019-07-10 16:32:44 +02:00
Benoit Marty
d613abf4b4 i18n edited_suffix 2019-07-10 15:29:52 +02:00
Benoit Marty
06699eaefc Cleaner code 2019-07-10 14:40:08 +02:00
Benoit Marty
e5082f662c Fix actually done TODO 2019-07-10 14:19:59 +02:00
Benoit Marty
c8ab53e39c Video visibility fix 2019-07-10 14:11:49 +02:00
Valere
d424a135a9
Merge pull request #324 from vector-im/feature/quick_react_e2e
Quick react on e2e was not displayed
2019-07-10 14:08:46 +02:00
Benoit Marty
e6409d4c60 Create a common canReact() method 2019-07-10 12:10:55 +02:00
Benoit Marty
19c7de687e We can react on e2e room text event 2019-07-10 11:51:09 +02:00
Benoit Marty
1918302297 Reply with formatted content 2019-07-10 11:29:47 +02:00
Benoit Marty
92e3a02389 Create data class instead of Pair 2019-07-10 10:34:32 +02:00
Benoit Marty
0a54801fcc Code clarity 2019-07-10 10:16:21 +02:00
Benoit Marty
228ee52563 Remove extra space in <mx-reply> 2019-07-10 10:07:45 +02:00
Benoit Marty
e6c74dc1fe Convert a Task to a ConfigurableTask without parameter 2019-07-09 18:41:08 +02:00
Benoit Marty
fe82ad2002 Format 2019-07-09 18:31:04 +02:00
Benoit Marty
f66739491a
Merge pull request #321 from vector-im/feature/workManager_clean
Fix bug on WorkManager: clean by tag
2019-07-09 18:30:07 +02:00
Benoit Marty
c5dc9d4a9a Fix test 2019-07-09 18:29:32 +02:00
Valere
8f858f8119 Fix / line too long 2019-07-09 18:20:00 +02:00
Benoit Marty
6e036c24b8 Make the test be runnable 2019-07-09 18:14:58 +02:00
Benoit Marty
5e832e07cd Code cleanup 2019-07-09 18:04:19 +02:00
Benoit Marty
e9700e04d8 Move method to JsonCanonicalizer and fix test compilation 2019-07-09 18:04:19 +02:00
Benoit Marty
c19b1f917f Javadoc 2019-07-09 18:04:19 +02:00
Benoit Marty
4281b5967a Create object for work constraint 2019-07-09 18:04:19 +02:00
Benoit Marty
aa743d8469 Ensure we do not cancel Work from other lib or SDK client 2019-07-09 18:04:19 +02:00
Valere
a09850b16c
Merge pull request #316 from vector-im/feature/initial_sync_progress
Feature/initial sync progress
2019-07-09 17:58:24 +02:00
Valere
6cb94dd4d6 Fine tune task weights + more measure 2019-07-09 17:42:53 +02:00
Valere
c9931e3ba3 Block interaction on initial sync 2019-07-09 17:36:08 +02:00
Valere
fc302c1b5a FIx / crash notification drawer empty nam 2019-07-09 17:35:50 +02:00
Benoit Marty
34ac987494 Cleanup 2019-07-09 16:36:46 +02:00
Benoit Marty
24b2387703
Merge pull request #319 from vector-im/feature/code_quality
Feature/code quality
2019-07-09 16:29:44 +02:00
Benoit Marty
8a0c9ae9b0 Rename PreferencesManager to VectorPreferences for code clarity 2019-07-09 16:29:24 +02:00
Benoit Marty
a79227424f Convert PreferencesManager file to Kotlin 2019-07-09 16:07:16 +02:00
Benoit Marty
ffe0b9712c Convert file to Kotlin 2019-07-09 15:50:15 +02:00
Benoit Marty
d92c090c30 Code quality: HashMap / HashSet 2019-07-09 15:40:49 +02:00
Valere
1a4157a663 review 2019-07-09 15:38:44 +02:00
Valere
fa81d1a9c7 Fix / revert bad refactor rename 2019-07-09 15:38:44 +02:00
Valere
dba4df6836 clean 2019-07-09 15:38:44 +02:00
Valere
4aae1f78d8 moved new strings + @StringRes annotation 2019-07-09 15:38:44 +02:00
Valere
8159a52bd7 cleaning 2019-07-09 15:38:44 +02:00
Valere
95d83db90c WIP 2019-07-09 15:38:44 +02:00
Benoit Marty
ac5b0af63e Code quality: remove rule for map() 2019-07-09 15:37:20 +02:00
Benoit Marty
e80473903e Code quality: import static 2019-07-09 15:35:27 +02:00
Benoit Marty
d08778c674 Code quality: equalTo 2019-07-09 15:33:31 +02:00
Benoit Marty
0919b9460d Code quality: split long lines 2019-07-09 15:26:32 +02:00
Benoit Marty
66a018c79e Code quality: trim() 2019-07-09 15:11:20 +02:00
Benoit Marty
dcd64de4b8 Check sdk modules 2019-07-09 15:07:11 +02:00
Benoit Marty
a0bd206308
Merge pull request #318 from vector-im/feature/send_state
Fix some bugs on e2e rooms
2019-07-09 15:03:39 +02:00
Benoit Marty
ba589e7961 Add missing permission request 2019-07-09 15:03:21 +02:00
Benoit Marty
5dc83d64c1 Fix compilation issue 2019-07-09 15:03:21 +02:00
Benoit Marty
9a4eb8e9a4 add getFileUrl extension 2019-07-09 15:03:21 +02:00
Benoit Marty
058e7153a1 Fix bug 2019-07-09 15:03:21 +02:00
Benoit Marty
d7b2371854 Add long click listener to file items 2019-07-09 15:03:21 +02:00
Benoit Marty
b0c939866f Download file - typo 2019-07-09 15:03:21 +02:00
Benoit Marty
a07f8b615e Download file - WIP 2019-07-09 15:03:21 +02:00
Benoit Marty
12bd85e0a9 Decrypt video file 2019-07-09 15:02:31 +02:00
Benoit Marty
1b82ed5abb Fix regression 2019-07-09 15:02:31 +02:00
Benoit Marty
c13ab62187 Fix issue when sending video in encrypted room 2019-07-09 15:02:31 +02:00
Benoit Marty
ea77686746 Send file: cleanup 2019-07-09 15:02:31 +02:00
Benoit Marty
8a5612be3d Send file: improve UI feedback 2019-07-09 15:02:31 +02:00
Benoit Marty
d24ce27903 Add missing call to contentUploadStateTracker.setFailure 2019-07-09 15:02:31 +02:00
Benoit Marty
2099965508 Avoid returning Result.failure() from appendable worker. 2019-07-09 15:02:31 +02:00
Benoit Marty
829e8da8dc lastFailureMessage is val, not var 2019-07-09 15:02:31 +02:00
Benoit Marty
e149ee53de Fix bad mime type for encrypted thumbnail 2019-07-09 15:02:31 +02:00
Valere
b73d3b15f8
Merge pull request #317 from vector-im/feature/realm_entity_rework
Feature/realm entity rework
2019-07-09 15:01:05 +02:00
Valere
61d7f23870 remove dead code 2019-07-09 15:00:37 +02:00
ganfra
b5650b2b8f Pagination : avoid breaking timeline when paginating twice from same token (race condition) 2019-07-09 14:44:59 +02:00
Valere
8777d13d8b Fix / view source, decrypted source was not correct 2019-07-09 14:22:40 +02:00
Valere
d52613d723 Trick / Remove home progress blank paddings 2019-07-09 11:17:36 +02:00
Benoit Marty
7ce476f858
Merge pull request #313 from vector-im/feature/notif_optim
Improve notification drawer manager: Dagger, throttle, and icon for API 9
2019-07-08 17:44:10 +02:00
ganfra
dd07f5c2a6 TimelineEvent : update sender data when loading room members and prune event (+ remove RoomSummaryMapper param) 2019-07-08 15:32:24 +02:00
Valere
7e6e09bc19 fix / compilation 2019-07-08 15:30:11 +02:00
Valere
1d11a163af Notification resolver try to decrypt 2019-07-08 15:08:49 +02:00
Valere
57bd103de8 Fix / decrypt room summary latest event 2019-07-08 14:58:49 +02:00
Valere
25bc5001f9 RoomSummary / Use encrypted message screen 2019-07-08 14:57:37 +02:00
Valere
e4c52484b1 Fix / ensure equals check for encryption result 2019-07-08 14:57:02 +02:00
Valere
a30da07fd1 Fix / timeline auto refresh on new session 2019-07-08 14:12:46 +02:00
Valere
ee27d3e047 Fix / clear unknown session map before re-request decrypt 2019-07-08 12:49:22 +02:00
Valere
7096094224 wip crypto 2019-07-08 12:05:41 +02:00
Benoit Marty
443fb41d18 Cleanup 2019-07-08 11:21:26 +02:00
Valere
94b4351e19 wip async crypto + persist 2019-07-08 11:18:27 +02:00
Benoit Marty
e90aeff417 ThrottleLast the notification drawer manager 2019-07-08 11:08:23 +02:00
Valere
e50dd265d4 merge develop 2019-07-08 10:58:41 +02:00
Valere
4521ea14ee Merge branch 'develop' into feature/realm_entity_rework 2019-07-08 10:55:20 +02:00
Benoit Marty
535b41d818 Rename Debouncer to FirstThrottler 2019-07-08 10:49:32 +02:00
Benoit Marty
21357a1ec7 private fun 2019-07-08 10:32:38 +02:00
Benoit Marty
8c872caf78 Inject IconLoader and BitmapLoader 2019-07-08 10:30:45 +02:00
Benoit Marty
62a81a556e Refresh notification drawer in a background thread. It also fixes the person and room avatar display 2019-07-08 10:26:22 +02:00
Benoit Marty
568e8c8bc0 Do not load user icon before Android Pie 2019-07-08 10:10:39 +02:00
Valere
98a7652403 Put back local echo 2019-07-05 19:13:34 +02:00
ganfra
78951b9155 Timeline event: handle displayName/avatar [WIP] 2019-07-05 19:07:33 +02:00
Benoit Marty
8c86a653b2
Merge pull request #309 from vector-im/feature/crypto_cleanup
Rework Crypto using Try
2019-07-05 19:03:59 +02:00
Benoit Marty
ea0526821e Top left Back does not go to previous Activity anymore (Fixes #275) 2019-07-05 18:44:09 +02:00
Valere
c503445092 Branch back relation summaries 2019-07-05 18:38:20 +02:00
Benoit Marty
205af8b122
Merge pull request #280 from Dominaezzz/kotlinify-1
Enhance CancelableBag
2019-07-05 18:34:28 +02:00
Benoit Marty
3abb7c8de6
Merge pull request #308 from Dominaezzz/kotlinify-2
Some "Kotlinification"
2019-07-05 18:11:18 +02:00
Benoit Marty
a40510da3b
Merge pull request #310 from vector-im/feature/buildkite_pr
Build every branch which is not master, to be able to build PR from external repository
2019-07-05 18:06:14 +02:00
Benoit Marty
a6ab4a349d Build every branch which is not master, to be able to build PR from external repository 2019-07-05 18:02:13 +02:00
ganfra
79a704d240 Timeline : Uncomment liveChunk to make pagination working 2019-07-05 17:27:24 +02:00
Benoit Marty
e5adf174a8 Fix crash when invalid urls for image 2019-07-05 17:00:57 +02:00
Valere
f01e796271 Timeline is back 2019-07-05 17:00:13 +02:00
Benoit Marty
302d23ba96 Create a realm locker to fast up next Realm.getInstance calls 2019-07-05 16:28:15 +02:00
Benoit Marty
03050c3f25 Cleanup 2019-07-05 16:11:54 +02:00
ganfra
cbfd2af74b Start branching TimelineEventEntity 2019-07-05 16:07:12 +02:00
Benoit Marty
f3fab0dc08 Rename ErrorTypes 2019-07-05 15:52:37 +02:00
Benoit Marty
4a512d2425 Create enum for errorType and fix a few issues 2019-07-05 15:43:28 +02:00
Benoit Marty
07f80f43bd Display clear type 2019-07-05 15:15:55 +02:00
Benoit Marty
87dec337d8 Rework Crypto using Try 2019-07-05 14:41:32 +02:00
ganfra
b37877746a Introduce TimelineEventEntity to begin with the rework 2019-07-05 14:39:15 +02:00
Dominic Fischer
b0e5612bdc Convert java-esque code to Kotlin
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2019-07-05 12:32:21 +01:00
ganfra
25b0cd0e4b Remove some work from UI thread 2019-07-04 19:02:37 +02:00
Benoit Marty
2800d86a57
Merge pull request #302 from vector-im/feature/invitation
Quick action in invitation and composer input type
2019-07-04 18:47:44 +02:00
Benoit Marty
01bc0de2c2 Set again input type for composer, lost after merge 2019-07-04 18:43:36 +02:00
Benoit Marty
857a4c5a26 Quick implementation of accept/reject invitation from notification 2019-07-04 18:14:39 +02:00
Benoit Marty
063c35380a Fix regression on invitation full screen display 2019-07-04 16:44:37 +02:00
Benoit Marty
5322251bc0 Fix wording for direct message tab 2019-07-04 15:37:19 +02:00
Benoit Marty
c21b9df9a5 Fix issue with notification from previous account displayed after logout 2019-07-04 15:23:59 +02:00
Benoit Marty
f2a52f0253
Merge pull request #297 from vector-im/feature/crypto_stabilization
Safely remove all usage of `!![`
2019-07-04 15:17:26 +02:00
Benoit Marty
baaf493cb4
Merge pull request #299 from vector-im/feature/dix_concurrent_sync
Fix / Push worker could launch concurrent syncs
2019-07-04 15:10:18 +02:00
Benoit Marty
6cbd6d3a33 Valere's review 2019-07-04 14:59:29 +02:00
Benoit Marty
72e5aa981a
Merge pull request #298 from vector-im/feature/quote
Fix issue when quoting event in e2e rooms (Fixes #295)
2019-07-04 14:49:53 +02:00
Benoit Marty
c0f085cdf8 SyncTask now handles by itself the sync token 2019-07-04 14:46:59 +02:00
Valere
10bc2297d4 Fix / Push worker could launch concurrent syncs 2019-07-04 14:04:36 +02:00
Benoit Marty
8fa5e63b07 Fix issue: reply to e2e event does not contain the base message 2019-07-04 12:52:43 +02:00
Benoit Marty
9d0c50907c Fix issue when quoting event in e2e rooms (Fixes #295) 2019-07-04 12:39:59 +02:00
Benoit Marty
e5958983d8 Safely remove all usage of !![ 2019-07-04 11:44:09 +02:00
ganfra
ab23ec3f35 Fix https://github.com/matrix-org/riot-android-rageshakes/issues/5851 (DI) 2019-07-04 10:20:50 +02:00
ganfra
a79a6443e7 Realm: update realm dependencie 2019-07-03 20:08:27 +02:00
ganfra
9ff24cbf2a Merge branch 'feature/fix_issues' into develop 2019-07-03 19:46:34 +02:00
Valere
2eee25bbc1 Fix / crash not called on UI Thread 2019-07-03 19:36:25 +02:00
Valere
2a2431e490
Merge pull request #290 from vector-im/feature/fix_crash_npe_cryptomanager
Fix / Rageshake crashes + cleaning
2019-07-03 18:47:45 +02:00
Valere
4041e2e8ca code review 2019-07-03 18:40:42 +02:00
Valere
031c4e5746 Crash on loggout
https://github.com/matrix-org/riot-android-rageshakes/issues/5881
2019-07-03 18:40:04 +02:00
Valere
b4ea85fc76 Fix / Rageshake crashes + cleaning !!
https://github.com/matrix-org/riot-android-rageshakes/issues/5880
https://github.com/matrix-org/riot-android-rageshakes/issues/5877
https://github.com/matrix-org/riot-android-rageshakes/issues/5873
https://github.com/matrix-org/riot-android-rageshakes/issues/5871
2019-07-03 18:40:04 +02:00
ganfra
480f14902d Rx: observe on computation by default 2019-07-03 18:28:56 +02:00
Benoit Marty
20c8e8d922 Change the test to apply Google Service plugin to be able to run sonar 2019-07-03 18:18:07 +02:00
Benoit Marty
9cdecced57
Merge pull request #291 from vector-im/feature/start_crypto_earlier
Start crypto manager before handling first sync events
2019-07-03 18:05:44 +02:00
Benoit Marty
60d46538de
Merge pull request #292 from vector-im/feature/sonar_fix
Feature sonar fix and convert remaining Java files to Kotlin
2019-07-03 18:03:23 +02:00
Benoit Marty
223295c2f1 Convert MXUsersDevicesMap to kotlin - Fix issue 2019-07-03 18:01:28 +02:00
Benoit Marty
f789fb275d Convert MXUsersDevicesMap to kotlin 2019-07-03 17:34:22 +02:00
Valere
a7c12aeb93 Start crypto manager before handling first sync events 2019-07-03 17:17:58 +02:00
Benoit Marty
0ca9a5f68b Convert MXKey to kotlin 2019-07-03 16:45:08 +02:00
Valere
842345df9b
Merge pull request #284 from vector-im/feature/better_incoming_key_verif_mgmt
Moved incoming key/verif to active session holder
2019-07-03 15:54:15 +02:00
Benoit Marty
7d5c31c510 Fix Javadoc issues 2019-07-03 15:52:53 +02:00
Benoit Marty
1ee1c31b9c Fix bugs detected by Sonar 2019-07-03 15:42:35 +02:00
Benoit Marty
e9eada77f9 Add comment to run sonar analysis and fix compilation issue 2019-07-03 15:42:35 +02:00
ganfra
93ce0cc5e9 Realm: avoid using monarchy thread for custom work 2019-07-03 14:48:45 +02:00
ganfra
eefd09d022 Dagger: don't create MatrixCoroutineDispatchers multiple time!! 2019-07-03 14:48:03 +02:00
ganfra
ef597cc67a RoomSummary: set unreadNotification to 0 by default 2019-07-03 14:47:33 +02:00
Valere
5d171e0240 Moved incoming key/verif to active session holder 2019-07-03 12:56:08 +02:00
Valere
39070820be
Merge pull request #283 from vector-im/feature/check_pushrule_on_sync_only
Check Push rule on sync only + fix bad room name in notif
2019-07-03 12:37:49 +02:00
Valere
1fdad38b9d Check Push rule on sync only + fix bad room name in notif 2019-07-03 11:59:45 +02:00
Benoit Marty
f41c0311fa Fix done TODO 2019-07-03 11:58:50 +02:00
Benoit Marty
a476ac71da Import translations from Riot 2019-07-03 10:20:07 +02:00
manuroe
4b971a9e67 README: Fix develop build links 2019-07-03 10:04:35 +02:00
ganfra
bc2d321a84 Merge branch 'feature/Perf' into develop 2019-07-02 23:07:16 +02:00
ganfra
9adeab6bae Perf: revert constraintLayout version as it breaks at the moment 2019-07-02 23:06:40 +02:00
Dominic Fischer
0f3a63e366 Enhance CancelableBag
Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
2019-07-02 21:46:44 +01:00
Benoit Marty
d90698fe92
Merge pull request #279 from vector-im/feature/clear_glide_cache
Clear media cache from the settings and clear cache when signing out
2019-07-02 21:56:31 +02:00
Benoit Marty
af0af6e260 Fix bad background color in dark theme 2019-07-02 21:49:52 +02:00
Benoit Marty
6e71fb565a Fix bad layout for button when keyboard is opened (Fixes #268) 2019-07-02 21:23:57 +02:00
Benoit Marty
6c66ab1568 Fix code quality 2019-07-02 21:17:41 +02:00
Benoit Marty
77fd7cd33c Update wording 2019-07-02 20:48:20 +02:00
Benoit Marty
0d329f0338 Clear media cache from the settings and clear cache when signing out 2019-07-02 20:21:40 +02:00
ganfra
2f66321c2a RoomSummary: don't fetch last event by default as it takes some time 2019-07-02 19:59:01 +02:00
ganfra
5b102485bc Perf: timeline should reuse one background looper thread 2019-07-02 19:12:20 +02:00
Benoit Marty
313055b96d Fix bad alignment of button 2019-07-02 18:54:06 +02:00
Valere
cbe8236036
Merge pull request #264 from vector-im/feature/fix_double_reaction
Fix / sometime sent reaction is count twice
2019-07-02 18:52:42 +02:00
manuroe
698fc35704 README: Put back link to #riotx:matrix.org 2019-07-02 18:41:28 +02:00
ganfra
37199da52f Merge branch 'develop' into feature/Perf 2019-07-02 18:29:59 +02:00
manuroe
1c69d8e425 README: Update it for the beta launch 2019-07-02 18:06:43 +02:00
Valere
ec5ec3375a Fix / sometime sent reaction is count twice
Now use eventId format to check if local echo instead of state
2019-07-02 18:05:14 +02:00
Benoit Marty
156d88e7e2
Merge pull request #263 from vector-im/feature/appId
Rename im.vector.riotredesign to im.vector.riotx
2019-07-02 17:54:22 +02:00
Benoit Marty
504009499f Rename im.vector.riotredesign to im.vector.riotx 2019-07-02 17:27:08 +02:00
ganfra
11bf00030d Merge branch 'develop' into feature/Perf 2019-07-02 17:00:09 +02:00
Benoit Marty
73277c5b08
Merge pull request #259 from vector-im/feature/fix_read_receipts_not_updated
Fix / send read marker for collapsed items
2019-07-02 16:51:53 +02:00
Benoit Marty
f21f4dbe91
Merge pull request #262 from vector-im/feature/update_timeline_when_new_key
Update timeline on new session
2019-07-02 16:51:07 +02:00
Benoit Marty
504d7e95fd
Merge pull request #227 from vector-im/feature/encrypt_local_data
Encrypt Realm databases
2019-07-02 16:49:36 +02:00
Benoit Marty
62d2443b85 Remove duplicated method 2019-07-02 16:48:58 +02:00
Benoit Marty
bc1edcf33d Code review 2019-07-02 16:48:58 +02:00
Valere
363f52b10c Encrypt Realm databases 2019-07-02 16:48:58 +02:00
Benoit Marty
498b1f2b06
Merge pull request #261 from vector-im/feature/e2e_file
Encrypt attachment in e2e rooms
2019-07-02 16:44:17 +02:00
Valere
92222c269e Update timeline on new session 2019-07-02 16:18:16 +02:00
Valere
ee9440c1cb Fix / crash signout bottom sheet 2019-07-02 16:05:01 +02:00
Benoit Marty
fe81145680
Merge pull request #260 from vector-im/feature/misc_quick_fixes
Feature/misc quick fixes
2019-07-02 15:56:17 +02:00
Benoit Marty
0980a41752 use file name with extension 2019-07-02 14:59:44 +02:00
Benoit Marty
18a821f3f6 add message 2019-07-02 14:43:07 +02:00
Benoit Marty
14a2570ea4 Preview of encrypted images (first and fast implementation) 2019-07-02 14:35:22 +02:00
Benoit Marty
994ee1d23f Encrypt file + propagate error between chained workers 2019-07-02 14:07:48 +02:00
Benoit Marty
f0e43d31f5 Encrypt file WIP 2019-07-02 12:34:56 +02:00
Valere
85e850bcde Fix / unwanted auto-mardown when trailing space 2019-07-02 12:29:36 +02:00
Valere
6cf24cc43b Fix / some state events are missing context action (view source) 2019-07-02 12:21:27 +02:00
Valere
c7df433a44 Fix / send read marker for collapsed items
Also remove unnecessary check on matrix id format
2019-07-02 12:08:44 +02:00
ganfra
9378d30601 Merge branch 'develop' into feature/Perf 2019-07-02 11:25:39 +02:00
Valere
58a80ec543 Fix / crash user autocomplete after invite command 2019-07-02 10:43:55 +02:00
Benoit Marty
95ea6db946 Change name from "Riot X" to "RiotX" 2019-07-02 10:42:45 +02:00
Benoit Marty
a47af4d915 Split buildkite build into two build to reduce build time and resource consumption. 2019-07-02 10:41:18 +02:00
Benoit Marty
0c2d3f36c3 Encrypt file WIP 2019-07-02 09:56:20 +02:00
Benoit Marty
014d03893a Fix issue after rebase and use classic request for clear image 2019-07-02 09:56:20 +02:00
ganfra
164c8dab09 Glide: try to handle encrypted image. [WIP] 2019-07-02 09:56:20 +02:00
Benoit Marty
b54ca5a8a0 Decrypt Attachment - WIP 2019-07-02 09:56:20 +02:00
Benoit Marty
707a4712fc Add some javadoc from Matrix spec and add EncryptedFileInfo where necessary 2019-07-02 09:56:20 +02:00
Benoit Marty
8e76700c8d Handle redacted e2e event 2019-07-02 09:56:20 +02:00
Benoit Marty
3f74c4e933 Report change from https://github.com/matrix-org/matrix-android-sdk/pull/471 2019-07-02 09:56:20 +02:00
ganfra
41ed4b23d8 Update dependencies (tested ok) 2019-07-02 09:39:45 +02:00
Valere
ce9fa15bcb Missing ? 2019-07-01 20:54:42 +02:00
Valere
f9880283e9 Fix / crash when reporting bug with no active session 2019-07-01 20:47:21 +02:00
Valere
f4b124d29f
Merge pull request #257 from vector-im/feature/room_list_improvements
Room list: last event preview - invitations list
2019-07-01 20:38:32 +02:00
Valere
fb1f107911
Merge pull request #254 from vector-im/feature/enhance_notif_pre_n
Better summary for pre N devices
2019-07-01 20:38:02 +02:00
Valere
8e653979fd
Merge pull request #258 from vector-im/feature/fix_signout
Fix / signout sign-in not working
2019-07-01 20:37:32 +02:00
Valere
a5584d27af QuickFIx / regression cannot decrypt message (no sender_key) 2019-07-01 20:34:42 +02:00
ganfra
de9a5a3d12 Perf: eventHtmlRenderer is slow to build, get only one instance 2019-07-01 20:19:50 +02:00
Valere
95d64008aa Move to sdk 2019-07-01 20:12:05 +02:00
ganfra
19202cfca6 Perf: try to get better 2019-07-01 20:05:48 +02:00
Valere
ca2223f201 Force passing realm to TimelineEvent factory 2019-07-01 19:46:18 +02:00
Valere
a1ddd73d7d Fix / signout sign-in not working 2019-07-01 18:55:40 +02:00
Benoit Marty
01e3e71f98 Handle room invitation actions 2019-07-01 18:50:33 +02:00
Valere
8fefdc1019 Fix crash on logout 2019-07-01 16:56:24 +02:00
Benoit Marty
07309c90e1 Room list: rework invitations 2019-07-01 16:29:04 +02:00
Valere
0bdde4d994 Better summary for pre N devices 2019-07-01 16:19:46 +02:00
Benoit Marty
b25098c52d Fix issue on invitation: restore background and composer could be opened 2019-07-01 15:24:28 +02:00
Benoit Marty
5e9ecfbcc0 Room summary; handle encrypted events 2019-07-01 15:12:35 +02:00
Benoit Marty
e1b6f4bd74 Fix issue after rebase 2019-07-01 15:12:35 +02:00
Benoit Marty
4d79485fee Last event on room list 2019-07-01 15:12:35 +02:00
Valere
9224fcabfa Fix #253 / Image with no mimetype in info 2019-07-01 15:10:12 +02:00
Valere
0d433b2620 fix / missing reaction event in filter 2019-07-01 13:53:10 +02:00
Valere
6a829caf0f Perf / filter events for aggregation updater 2019-07-01 13:33:43 +02:00
ganfra
d643abbb22 Sender name: fix for not synced events. 2019-07-01 13:20:03 +02:00
Valere
e838794587 Do not check push rule on initial sync 2019-07-01 13:08:16 +02:00
Valere
b0ad568df0 Fix / fdroid notif was broken due to merge 2019-07-01 13:07:52 +02:00
ganfra
4739aea793 Dagger: inject dependencies earlier into activity/fragment 2019-07-01 11:41:27 +02:00
Valere
3960742f38
Merge pull request #250 from vector-im/feature/fix_impure_reducers
Fix impure reducer and use live event
2019-07-01 11:33:34 +02:00
Benoit Marty
2eef0a6162 Fix ban and kick bad message error (Fixes #184 Fixes #248) 2019-07-01 11:27:57 +02:00
Benoit Marty
466a39d239 Robustness 2019-07-01 11:08:05 +02:00
Valere
e78b703387 Fix / show source was showing content 2019-07-01 10:47:10 +02:00
Benoit Marty
9df928e709 Fix bad background color in dark themes 2019-07-01 10:04:02 +02:00
Valere
a734c699ad Fix impure reducer and use live event 2019-07-01 09:56:00 +02:00
Valere
b402bf829b Fix copy and inconsistency
thx kr0mbel
2019-06-28 18:45:49 +02:00
Benoit Marty
4d7f1b4fee Report Bug by default 2019-06-28 16:57:01 +02:00
Benoit Marty
38ceb6f52a Fix bad FCM token stored 2019-06-28 16:54:53 +02:00
Valere
419ef7b46f
Merge pull request #243 from vector-im/feature/reply_e2e
Reply in e2e room
2019-06-28 16:07:08 +02:00
Benoit Marty
4ad23f0f37 Fix bad copyright block 2019-06-28 16:05:36 +02:00
Benoit Marty
0f039fce32 Add 30 missing copyright block 2019-06-28 15:59:20 +02:00
Benoit Marty
fef1c7cc45 Set default theme in pref screen 2019-06-28 15:36:57 +02:00
Benoit Marty
7ff2477a4f
Merge pull request #241 from vector-im/feature/api16
min API 19 - tested
2019-06-28 15:06:40 +02:00
Benoit Marty
7af55a48f6 Fix lint warning 2019-06-28 15:05:57 +02:00
Benoit Marty
ee402fd328 Now with min API set to 19, we do not need Left and Right attribute, Start and End is enougth. For the moment, just reduce the severity 2019-06-28 14:57:41 +02:00
Valere
75c1718252 code review 2019-06-28 14:57:22 +02:00
Valere
f83491fdfc Fix / impure reducer in action view model 2019-06-28 14:57:22 +02:00
Valere
a9dd06562a Reply in e2e room
+ Add reply option in e2e room
+ Fix bug 242
+ Show preview of messages in menu and in text composer preview
2019-06-28 14:57:22 +02:00
Benoit Marty
cea8abb9b1 Fix issue in test and add a test for Json canonicalization (will pass when reply_e2e branch will be merged) 2019-06-28 14:27:08 +02:00
Benoit Marty
13a0b809e1 Fix compilation issue in release 2019-06-28 14:08:38 +02:00
Benoit Marty
d28e9862a2
Merge pull request #236 from vector-im/feature/lab_show_hidden_events
Feature/lab show hidden events
2019-06-28 12:51:31 +02:00
Benoit Marty
bf68a6bafc Comment used labs settings 2019-06-28 12:50:56 +02:00
Valere
b14a6224ba Add lab option to show hidden events in timeline
+ cleaning labs settings
2019-06-28 12:45:08 +02:00
Valere
b92cc524b6 Fix / Day separator flickering in timeline
Sending events were not filtered, so sending events like reactions would make the day separator appear
2019-06-28 11:33:33 +02:00
Benoit Marty
17a4a86ad1
Merge pull request #220 from vector-im/feature/restrict_reaction_emoji
Only show reactions with an emoji key
2019-06-28 11:29:32 +02:00
Benoit Marty
0a908136b6 Only show reactions with an emoji key 2019-06-28 11:28:51 +02:00
Benoit Marty
83ceb36a12
Merge pull request #233 from vector-im/feature/suggestion
Feature suggestion
2019-06-28 10:47:14 +02:00
Benoit Marty
2ef53e2066 Fix compilation issue after rebase 2019-06-28 10:44:02 +02:00
Benoit Marty
519f49b50d Add report bug in the menu 2019-06-28 10:40:00 +02:00
Benoit Marty
a550743f2f Report suggestion feature 2019-06-28 10:40:00 +02:00
Benoit Marty
40bf3a15cd Move signout action to the settings General 2019-06-28 10:37:25 +02:00
Benoit Marty
4422ebb77b Remove old menu 2019-06-28 10:28:41 +02:00
Benoit Marty
99271ce5d6
Merge pull request #234 from vector-im/feature/alpha_disclaimer
Show disclaimer at first launch (Fixes #215)
2019-06-28 10:25:55 +02:00
Benoit Marty
2c9280dca6
Merge pull request #235 from vector-im/feature/debounce
Debounce click on room
2019-06-28 10:24:45 +02:00
Benoit Marty
7187cc23a1 code quality 2019-06-28 10:23:27 +02:00
Benoit Marty
10353c9871 add dagger2 licence 2019-06-28 10:12:04 +02:00
Benoit Marty
f410538e2f minSdkVersion 19 (mainly for security reason and also because of MotionLayout only supported on API 18) 2019-06-28 10:06:36 +02:00
Benoit Marty
76fc455d93 Stop using textColorTertiary (fix crash on API 19) 2019-06-28 10:04:43 +02:00
Benoit Marty
22c005d05a
Merge pull request #239 from vector-im/feature/dagger
Feature/dagger
2019-06-28 10:02:20 +02:00
ganfra
604de7eebc Dagger: fix some merging issues 2019-06-28 09:35:34 +02:00
ganfra
f18bc9bd00 Dagger: fix no session 2019-06-27 19:12:46 +02:00
ganfra
f91959ea96 Merge branch 'develop' into feature/dagger 2019-06-27 18:57:49 +02:00
ganfra
2063a3e535 Merge branch 'develop' into feature/dagger 2019-06-27 18:56:23 +02:00
Benoit Marty
a1c22c9aa6 Remove useless property for a SDK 2019-06-27 18:25:50 +02:00
Valere
d5625b95fe Fix / use senderId when display name cannot be resolved 2019-06-27 17:58:11 +02:00
Benoit Marty
d205f63928 Debounce click on room 2019-06-27 17:32:49 +02:00
Benoit Marty
bd8d6f92da Update wording 2019-06-27 16:04:02 +02:00
Benoit Marty
f9c8e4f85a Show disclaimer at first launch (Fixes #215) 2019-06-27 16:01:11 +02:00
ganfra
1fa7b7367a Dagger: merge develop compiling now. 2019-06-27 15:25:01 +02:00
Valere
0765d6d1da Fix / Action bottom sheet show preview for encrypted messages 2019-06-27 15:21:10 +02:00
Benoit Marty
f98f0e1a87
Merge pull request #232 from vector-im/feature/settings_v2_clean_notif
Cleans notification pref screen
2019-06-27 14:12:12 +02:00
Valere
fb7ada72dd Fix / register/unregister pusher 2019-06-27 14:08:54 +02:00
Valere
338de3ebf5 Cleans notification pref screen
+ fix troubleshoots
2019-06-27 12:21:38 +02:00
Benoit Marty
fb43c87107
Merge pull request #231 from vector-im/feature/fcm_privacy
Upgrade firebase messaging version and disable Firebase Analytics
2019-06-27 11:55:19 +02:00
Benoit Marty
f092c40999
Merge pull request #228 from vector-im/feature/settings_v2
Split settings into sub sections
2019-06-27 11:54:03 +02:00
Benoit Marty
f414f46cba General setting: avatar and display name 2019-06-27 11:53:28 +02:00
Benoit Marty
9ec364b60e
Merge pull request #226 from vector-im/feature/notification_beta
Notification beta
2019-06-27 10:46:27 +02:00
Benoit Marty
ae7e617fdd Rename and format and remove duplicate EventType.REDACTION 2019-06-27 10:46:04 +02:00
Benoit Marty
d1642c928a Move specific classes for FDroid into FDroid variant source code 2019-06-27 10:46:04 +02:00
Benoit Marty
5e619f2593 Upgrade firebase messaging version and disable Firebase Analytics 2019-06-27 10:42:36 +02:00
Benoit Marty
679a4c7f31 Add ignored users icon in the root settings 2019-06-27 10:17:57 +02:00
Benoit Marty
76b890fe06
Merge pull request #230 from vector-im/feature/e2e_hint
Change hint for encrypted room (fix #210)
2019-06-26 21:05:19 +02:00
ganfra
b2d2582e0f Merge branch 'develop' into feature/dagger [WIP] 2019-06-26 20:58:46 +02:00
Valere
715b44ec79
Merge pull request #229 from vector-im/feature/update_icons
Feature/update icons
2019-06-26 19:30:55 +02:00
Benoit Marty
25b7bf76bf Change hint for encrypted room (fix #210) 2019-06-26 18:49:55 +02:00
Benoit Marty
b69940a5da Hide some settings for notifications 2019-06-26 18:28:45 +02:00
Benoit Marty
28f2bb3ebd Use im.vector.riotredesign.core.preference.VectorPreferenceCategory 2019-06-26 18:15:50 +02:00
Valere
6bf940bedf Updated login logo 2019-06-26 18:09:42 +02:00
Benoit Marty
56fc223930 Add missing point in the interrogation point 2019-06-26 18:00:51 +02:00
Valere
3e00576230 New status bar notification icons 2019-06-26 17:55:07 +02:00
ganfra
6e7adaec59 Dagger: prepare for multi session [WIP] 2019-06-26 17:51:24 +02:00
Benoit Marty
9fd9124643 Disable some unimplemented pref 2019-06-26 17:43:36 +02:00
Benoit Marty
ad3d303405 Fix issue in notification preference 2019-06-26 17:37:03 +02:00
Benoit Marty
7c47c6a033 split preference (Kotlin) 2019-06-26 17:20:26 +02:00
Valere
33f17e4c5c Quick Fix / DI crash when not logged in 2019-06-26 17:15:10 +02:00
Valere
289b2a4eb1 Launch icons update 2019-06-26 17:14:28 +02:00
Benoit Marty
e63f51821f split preference (XML) 2019-06-26 15:26:08 +02:00
Benoit Marty
8370f4fc76 rename file 2019-06-26 15:05:07 +02:00
Benoit Marty
5feebeba01 Integrate new icons for preference root screen 2019-06-26 15:01:46 +02:00
Benoit Marty
0c0ef38b4f Fix notification on FDroid 2019-06-26 13:32:55 +02:00
Benoit Marty
bec5ca1420
Merge pull request #213 from vector-im/feature/notification_alpha
Riot X alpha - Notification phase 1
2019-06-26 13:30:22 +02:00
Benoit Marty
895f0f0079 Fix compilation issue on FDroid 2019-06-26 12:21:30 +02:00
Benoit Marty
134c2fcd42 Notification: Fix TestAccountSettings test 2019-06-26 12:19:54 +02:00
Benoit Marty
2625e11508 rename method 2019-06-26 12:19:54 +02:00
Benoit Marty
9fa3a75fb6 Notification: display room avatar 2019-06-26 12:19:54 +02:00
Benoit Marty
b388be93c8 Notification: better code 2019-06-26 12:19:54 +02:00
Benoit Marty
5a1242109d Notification: display rooms and users' avatars 2019-06-26 12:19:54 +02:00
Benoit Marty
4f0ed402bf Notification: cleanup 2019-06-26 12:19:54 +02:00
Benoit Marty
f6c500d120 Notification: dismiss all on sign out 2019-06-26 12:19:54 +02:00
Benoit Marty
785f33177d Notification: open room and clear drawer - Smart reply - Mark as read - dismiss all 2019-06-26 12:19:54 +02:00
Benoit Marty
328f090723 Code quality: i18n 2019-06-26 12:19:54 +02:00
Benoit Marty
ce3242c748 Code quality: preference 2019-06-26 12:19:54 +02:00
Benoit Marty
71ae99012b Code review and cleanup 2019-06-26 12:19:54 +02:00
Benoit Marty
ab0141a5c6 Fix issue after rebase 2019-06-26 12:19:54 +02:00
Valere
abb1c3f3c4 Fix / try to get edited message content first 2019-06-26 12:19:54 +02:00
Valere
1feb1f9c3f Fix test 2019-06-26 12:19:54 +02:00
Valere
090ee1d4e9 Fix / ignore message sent by me in push rules 2019-06-26 12:19:54 +02:00
Valere
7821ca12fd Fix / fetch from realm without copy (proxy error) 2019-06-26 12:19:54 +02:00
Valere
c01af6ac78 Stop notification using preference when disabled 2019-06-26 12:19:54 +02:00
Valere
74099be316 Remove / Add pusher from enable notif preference
+Added Retrofit/Moshi null serializer for pusher kind
2019-06-26 12:19:54 +02:00
Valere
4e6b34b9d1 Fix issues on Notification Event resolver 2019-06-26 12:19:54 +02:00
Valere
6743dc6273 Set sync timeout to 30s when in foreground 2019-06-26 12:19:54 +02:00
Valere
288ebe48fd Doc / quick fixes 2019-06-26 12:19:54 +02:00
Valere
9ae9830de4 Fix / compilation in gplay flavor 2019-06-26 12:19:54 +02:00
Valere
0584fc3666 Get real push rules from server and evaluate them 2019-06-26 12:19:54 +02:00
Valere
2e417a9143 Basic FCM vs fdroid mode 2019-06-26 12:19:54 +02:00
Valere
0e46fc4c0a WIP 2019-06-26 12:19:54 +02:00
Benoit Marty
79735c6338 Introduce activity-alias for Launcher Activity 2019-06-26 12:16:05 +02:00
Valere
4505d13385 Fix / SAS verification infinite waiting on last step
Missing state update to verified after mac verification
2019-06-26 10:46:58 +02:00
Valere
8fe0bd5abe
Merge pull request #214 from vector-im/feature/update_quick_reactions
Feature/ Update quick reactions
2019-06-25 15:47:17 +02:00
Valere
98176b9760 Cleaning (code review) 2019-06-25 15:45:44 +02:00
Benoit Marty
104ffc930d
Merge pull request #200 from vector-im/feature/permalinks
Handle permalink with the new navigation UX - WIP
2019-06-25 09:34:58 +02:00
Benoit Marty
2741780553 Change scope of PermalinkHandler 2019-06-25 09:34:12 +02:00
Benoit Marty
625242a3d9 handle all themes 2019-06-25 09:34:12 +02:00
Benoit Marty
401f878a9c Fix ConcurrentModificationException 2019-06-25 09:34:12 +02:00
Benoit Marty
3e97503220 Avoid erasing all cache 2019-06-25 09:34:12 +02:00
Benoit Marty
76ade2957e Handle permalink click 2019-06-25 09:34:12 +02:00
Benoit Marty
b1e009f8b4 Handle eventId v4 (https://matrix.org/docs/spec/rooms/v4#event-ids) 2019-06-25 09:33:52 +02:00
Benoit Marty
90f420b287 Cleanup PermalinkHandler and Navigation 2019-06-25 09:33:52 +02:00
Benoit Marty
73b55fd975 Group navigation cleanup 2019-06-25 09:33:52 +02:00
Benoit Marty
ad601c7d5a
Merge pull request #189 from vector-im/feature/third_party_notice
Feature/third party notice
2019-06-25 09:32:08 +02:00
Benoit Marty
046aac74c2 Add link for reference 2019-06-25 09:31:45 +02:00
Benoit Marty
0998ffb5f2 Update open source license file 2019-06-25 09:31:45 +02:00
Benoit Marty
8ff6fbb153 Handle redirection 2019-06-25 09:31:45 +02:00
Benoit Marty
9d3a8e7c40 Add usage of com.google.android.gms:oss-licenses-plugin to list open source licenses 2019-06-25 09:31:45 +02:00
Valere
56aaa9dce3 Fix / updated unicode for smiling 2019-06-24 16:15:26 +02:00
Valere
43ead66991 Update quick reactions to new design 2019-06-24 16:13:58 +02:00
Benoit Marty
92eb7d55dc
Merge pull request #207 from vector-im/feature/version
Display some version of Riot and SDK (Fix #185)
2019-06-21 17:07:55 +02:00
Benoit Marty
1cfc85a772 Display some version of Riot and SDK (Fix #185) 2019-06-21 11:13:16 +02:00
ganfra
47968c9447 Dagger: everything should be injected ok now 2019-06-21 10:36:02 +02:00
ganfra
07fee8ed3d Dagger: continue reworking on app and sdk [WIP] 2019-06-20 19:26:59 +02:00
Benoit Marty
1eb374fa49
Merge pull request #188 from vector-im/feature/disambiguation
Disambiguation of display names
2019-06-20 17:29:01 +02:00
Benoit Marty
285da114e7 better code (ganfra's review) 2019-06-20 17:27:15 +02:00
Benoit Marty
34870591b4 Update wording 2019-06-20 17:22:38 +02:00
ganfra
ee87c253fe Dagger: continue working on app side. Now compile but some DI are not branched yet. 2019-06-19 19:40:59 +02:00
ganfra
9c1f870694 Dagger: start handling app dependencies [WIP] 2019-06-18 20:00:20 +02:00
Benoit Marty
56e0680398 Remove unused class 2019-06-18 16:11:24 +02:00
Benoit Marty
8c0a1ed37d Rename "sender" to "senderId" for code clarity 2019-06-18 16:11:24 +02:00
Benoit Marty
625500212d Manage display name disambiguation (Fixes #172) 2019-06-18 16:09:48 +02:00
Benoit Marty
b1f5b3ad96
Merge pull request #187 from vector-im/feature/issues_fix
Add a few feature
2019-06-18 16:03:36 +02:00
Benoit Marty
02f84a3b53 View source of encrypted event 2019-06-18 13:14:39 +02:00
Benoit Marty
7fe662598b Handle click on encryption message 2019-06-18 12:56:08 +02:00
Benoit Marty
5bfa67b442 Handle click on encrypted message 2019-06-18 12:45:24 +02:00
Benoit Marty
a53e40e1ee Create MessageInformationDataFactory for reusability 2019-06-18 12:33:07 +02:00
Benoit Marty
273c8a19b8 Fix UI issue notification troubleshot screen 2019-06-18 10:30:56 +02:00
Benoit Marty
53bdd58c1b Fix UI issue on BugReportActivity (send button not visible) 2019-06-18 10:25:13 +02:00
Benoit Marty
51879845f2
Merge pull request #186 from vector-im/feature/crypto_up
Crypto work
2019-06-17 19:07:24 +02:00
Benoit Marty
f2372841f6 KeysBackup: import change from https://github.com/vector-im/riot-android/pull/3127 2019-06-17 19:07:04 +02:00
Benoit Marty
0497d14a08 SAS: import change from https://github.com/matrix-org/matrix-android-sdk/pull/467 2019-06-17 19:06:32 +02:00
Benoit Marty
0b6b95110f
Merge pull request #182 from vector-im/feature/cryptoKeys
Crypto: Import/export room keys (the old way)
2019-06-17 19:05:43 +02:00
Benoit Marty
191d80e5f5 Fix issue with key importation 2019-06-17 19:05:26 +02:00
Benoit Marty
659ba34fb3 Remove CryptoAsyncHelper and use only coroutine 2019-06-17 19:05:26 +02:00
Benoit Marty
907a1d1a4b Import keys: WIP 2019-06-17 19:05:26 +02:00
Benoit Marty
99d2e8388a Fix crash 2019-06-17 19:04:48 +02:00
Benoit Marty
38b1d24953 Use foldToCallback() whenever it's possible 2019-06-17 19:04:48 +02:00
Benoit Marty
b682f3e982 Cleaner code 2019-06-17 19:04:48 +02:00
Benoit Marty
5f0d1d9536 Crypto: export room keys 2019-06-17 19:04:48 +02:00
ganfra
c2c2d0b21e Dagger: make SDK DI working 2019-06-17 18:17:37 +02:00
Benoit Marty
8c8a4dcbd1 Fix margin issue when second text is not displayed 2019-06-17 18:13:34 +02:00
Benoit Marty
7e9275831b
Merge pull request #180 from vector-im/feature/fix_timeline
Request can now be canceled properly
2019-06-17 18:01:46 +02:00
Benoit Marty
6266f9e6a1 Handle device deletion the proper way 2019-06-17 17:32:35 +02:00
Benoit Marty
9649e190ef Fix compilation issue after rebase 2019-06-17 16:28:27 +02:00
ganfra
1547045165 Request can now be canceled properly: it should fix the issue with live chunk being deleted. 2019-06-17 15:08:16 +02:00
Benoit Marty
5b0cab3e8a Merge branch 'feature/i18n_sync' into develop 2019-06-17 14:55:54 +02:00
Benoit Marty
97b066b8fa Import strings from Riot 2019-06-17 14:55:17 +02:00
ganfra
4be0ab87fc Dagger: continue adding it to SDK [WIP] 2019-06-16 17:00:47 +02:00
ganfra
3d465f6fdf Start to introduce Dagger into SDK [WIP] 2019-06-14 16:32:23 +02:00
Benoit Marty
e3bc88e36c
Merge pull request #183 from vector-im/feature/motionLayout
Better anim of ome button
2019-06-14 16:17:27 +02:00
Benoit Marty
eaf1e080ba format file 2019-06-14 16:14:39 +02:00
Benoit Marty
02ef1172ce
Merge pull request #179 from vector-im/feature/cryptoFinalization
Crypto: Delete device
2019-06-14 16:06:23 +02:00
Benoit Marty
8f6f72ca48 Review: Added optional to stage and renamed to "InteractiveAuthenticationFlow" 2019-06-14 16:06:07 +02:00
ganfra
df4f0eac20 Merge branch 'feature/sync_ui' into develop 2019-06-13 18:16:45 +02:00
Benoit Marty
d353e9314b Crypto: Delete device 2019-06-13 16:48:42 +02:00
Benoit Marty
567c1fd7a5
Merge pull request #175 from vector-im/feature/crypto
Feature/crypto
2019-06-13 15:28:09 +02:00
Benoit Marty
ab95cbee92 Improve keys backup banner rendering 2019-06-13 14:20:43 +02:00
ganfra
9dc1684179 Crypto: check for encryption state event to know if room isEncrypted 2019-06-13 11:49:11 +02:00
Benoit Marty
c20b256b24 Move KeysBackupStateListener to a dedicated file 2019-06-13 11:13:05 +02:00
Benoit Marty
02d3fea4a9 Move javadoc to interface 2019-06-13 11:10:26 +02:00
Benoit Marty
ca98ff5864 Clear crypto database when signing out 2019-06-13 10:58:45 +02:00
Benoit Marty
6cd3b4dd95 Import https://github.com/vector-im/riot-android/pull/3111/files in RiotX 2019-06-13 10:33:04 +02:00
Benoit Marty
480d197ffa Keys share request handling 2019-06-12 18:32:24 +02:00
Benoit Marty
a7c0e87f40 Alerter: upgrade lib and change status icon color when alert is displayed 2019-06-12 16:30:30 +02:00
Benoit Marty
af1a48d918 SAS: fix issue on emoji rendering 2019-06-12 15:44:25 +02:00
Benoit Marty
e17ffc85e7 KeysBackup: save recovery key to file 2019-06-12 14:59:54 +02:00
Benoit Marty
9c654ba72c Use observeEvent when appropriate 2019-06-12 13:19:52 +02:00
Benoit Marty
b47ef9220e Keys backup: migrate settings to Epoxy and MvRx 2019-06-12 13:09:43 +02:00
ganfra
0204bade8b Content: hide some internal methods 2019-06-12 10:54:26 +02:00
ganfra
481a25d4df Settings: add some webview content 2019-06-12 10:53:48 +02:00
ganfra
3dd161d65a Sync: add progress indicator for sync, need UI inputs. 2019-06-11 16:54:44 +02:00
Benoit Marty
53dd9c3427 Keys backup fix some issue on layout 2019-06-11 16:48:48 +02:00
Benoit Marty
4827b76b80 Integrate keysbackup banner 2019-06-11 15:45:40 +02:00
Valere
1206107a73 Fix / visibility bug after scroll
+ refine animation
2019-06-11 15:43:40 +02:00
Benoit Marty
5621f0661e Merge branch 'develop' into feature/crypto 2019-06-11 14:56:27 +02:00
Benoit Marty
875947dd61 Give the opportunity to override log configuration in local gradle properties file 2019-06-11 14:52:39 +02:00
Benoit Marty
61b1d83bbd Clean 2019-06-11 14:37:02 +02:00
Benoit Marty
64e5fed7ac Fix issue: lastSeenTs can be null 2019-06-11 13:57:35 +02:00
Benoit Marty
f6c36670c3 Rename class members and class name for code clarity 2019-06-11 13:32:09 +02:00
Benoit Marty
2e39a678db Code quality 2019-06-11 10:15:50 +02:00
Benoit Marty
6dacb9894e Merge branch 'develop' into feature/crypto 2019-06-11 10:11:53 +02:00
ganfra
612b13808f Crypto: clean some code + add failure send state (but not handled yet). 2019-06-10 19:22:48 +02:00
Benoit Marty
90a011c4e4 Fix issue on animation 2019-06-10 18:16:06 +02:00
Benoit Marty
56f1c726b2 FAB Motion WIP
FAB Motion WIP

FAB Motion WIP

FAB Motion WIP
2019-06-10 17:22:00 +02:00
Benoit Marty
6323183119 Ganfra's review: use sumBy() instead of reduce() 2019-06-10 17:06:58 +02:00
Benoit Marty
3439a9ca27
Merge pull request #173 from vector-im/feature/create_room
Create Room screen
2019-06-10 17:01:44 +02:00
Benoit Marty
9772bbe157 Ganfra's review: revert change 2019-06-10 16:58:48 +02:00
Benoit Marty
fa297a7b6a Ganfra's review: use NavigationViewModel to open the drawer 2019-06-10 16:53:21 +02:00
Benoit Marty
b48c920292 Ganfra's review: use simple ViewModel 2019-06-10 16:45:42 +02:00
Benoit Marty
c0be04f46c Ganfra's review: use observeEvent 2019-06-10 16:39:46 +02:00
Benoit Marty
b437837809 Ganfra's review: use RealmQueryLatch 2019-06-10 16:35:51 +02:00
Benoit Marty
33f8059846 Increase connect timeout from 30 seconds to 1 minute, for slow Homeserver (should fix #170) 2019-06-10 15:57:42 +02:00
Benoit Marty
4eab0a3704 Add foreground attribute 2019-06-10 15:35:05 +02:00
Benoit Marty
933e06a7ef Auto collapse toolbar 2019-06-10 15:24:25 +02:00
Benoit Marty
ad8baf8091 Fix screen rotation issue 2019-06-10 14:13:14 +02:00
Benoit Marty
598245531a Fix compilation issue after rebase 2019-06-10 13:45:34 +02:00
Benoit Marty
4f044c0cd6 Create room screen - Navigate to change protocol 2019-06-10 13:39:51 +02:00
Benoit Marty
77fc793e89 Create room screen - Navigate to freshly created room 2019-06-10 13:39:51 +02:00
Benoit Marty
aa95ce3d02 Create room screen - Better navigation pattern 2019-06-10 13:39:51 +02:00
Benoit Marty
4c5bffe0f5 Create room screen - WIP TODO: screen rotation - navigate to created room 2019-06-10 13:39:51 +02:00
Benoit Marty
ed18a504e4 Open drawer when clicking on group avatar 2019-06-10 13:39:11 +02:00
Benoit Marty
aec7e72dcf Add missing files for Status theme 2019-06-10 13:39:11 +02:00
ganfra
f2722f4766 Crypto: fix a small issue 2019-06-07 20:38:39 +02:00
ganfra
07c516ccdd Merge branch 'develop' into feature/crypto 2019-06-07 19:25:55 +02:00
ganfra
81330d30cf Merge branch 'develop' into feature/crypto 2019-06-07 18:53:24 +02:00
Valere
8f2c005d82
Merge pull request #168 from vector-im/feature/aggregation_p1_wrapup
Feature/aggregation p1 wrapup
2019-06-07 16:40:22 +02:00
Valere
a4a813708c Fix / send state always returning Unknown 2019-06-07 16:39:45 +02:00
ganfra
664e5354d3 Crypto: continue cleaning + fix some issues. 2019-06-07 16:01:24 +02:00
Valere
10251b906a clean / format 2019-06-07 15:57:55 +02:00
Valere
c9240c2dce Fix / disable context menu on not sent messages 2019-06-07 15:49:41 +02:00
Valere
220e6224e7 Merge develop 2019-06-07 15:42:04 +02:00
Valere
d3518c4944
Merge pull request #161 from vector-im/feature/fix_timeline_clicks
Fix / click|longclick link interference
2019-06-07 14:43:04 +02:00
Valere
5f34e58bd3 Fix / style on emoji picker appbar layout 2019-06-07 14:29:42 +02:00
Valere
438404b5ba code review cleaning 2019-06-07 14:14:51 +02:00
Valere
651d0472cd Show preview for notice events in context menu + fix merge issues 2019-06-07 14:14:51 +02:00
Valere
5cf9deb329 Menu action for non room messages 2019-06-07 14:14:51 +02:00
Valere
7409003949 Fix / Bug aggregation on initial sync
fix / All messages were not processed due to a test exiting the for loop
+ started adding context menu for non room messages
2019-06-07 14:14:51 +02:00
Valere
3f1bf00fdd Fix / use emoji Compat font for view reaction screen 2019-06-07 14:14:51 +02:00
Valere
04576ba7fd Permalink message action + Fix crash on injection of navigator 2019-06-07 14:14:51 +02:00
Valere
053dc1d8dd Show 'view reaction' option in context menu 2019-06-07 14:14:51 +02:00
Valere
834a865dfa Show text with only few emojis in bigger 2019-06-07 14:14:51 +02:00
Valere
e22b555b58 Refactoring (duplication in Message Item Factory) + cleaning 2019-06-07 14:14:51 +02:00
Valere
297f202005 Fix / Local echo taking too much time 2019-06-07 14:14:51 +02:00
Valere
440442bb99 New View Reactions bottom sheet
+ visible on reaction long click
+ Reaction pills size adapt to count, and number format
2019-06-07 14:14:51 +02:00
Valere
d2f648edec Use Font emoji compat for quickReactions and pills 2019-06-07 14:14:51 +02:00
Valere
53c91dc0c2 Ignore server aggregation until API ready 2019-06-07 14:14:51 +02:00
Valere
adbfde94d6 Fix / move read receipt on m.replace events 2019-06-07 14:14:51 +02:00
Valere
1b3ec2d0fb fix / review 2019-06-07 13:38:58 +02:00
Valere
ecccb80e04 Fix / No elevation on toolbars
In order to work se need to set a background on toolbar
2019-06-07 13:26:03 +02:00
Benoit Marty
11914ca188
Merge pull request #166 from vector-im/feature/debug_signature
Share the debug signature to all machines which build the debug APK
2019-06-07 10:38:40 +02:00
Benoit Marty
fb9627b7c4 Share the debug signature to all machines which build the debug APK 2019-06-07 10:17:14 +02:00
Benoit Marty
b782e5e8af
Merge pull request #164 from vector-im/feature/cleanup
Theme integration
2019-06-06 19:27:39 +02:00
Benoit Marty
b67c686d67 Fix lint warning 2019-06-06 19:23:14 +02:00
ganfra
c4d7711d2f Crypto: finally get a working encrypt/decrypt + SAS 2019-06-06 19:10:04 +02:00
Benoit Marty
f2da46b5f9 Dark dialog 2019-06-06 19:09:59 +02:00
Benoit Marty
a0b2d4c8f2 L'oeil à l'interieur 2019-06-06 18:56:54 +02:00
Benoit Marty
1f85f4a007 Remove unused themes 2019-06-06 18:47:27 +02:00
Benoit Marty
2c2f517e52 Hot change of theme - WIP 2019-06-06 18:34:14 +02:00
Benoit Marty
bfbb29b2cf Theme FAB menu 2019-06-06 16:45:45 +02:00
Benoit Marty
dd563ec9ae Fix issue in theme 2019-06-06 15:56:05 +02:00
Benoit Marty
e2d36aa213 Fix issue in theme 2019-06-06 15:24:04 +02:00
Benoit Marty
2cc2844abf Fix issue in theme 2019-06-06 15:16:56 +02:00
Benoit Marty
75b8932395 Fix issue in theme 2019-06-06 14:37:30 +02:00
Benoit Marty
311d8484a2 Add test Theme Activity 2019-06-06 13:39:08 +02:00
Benoit Marty
917282303d Import test Activities from Riot 2019-06-06 10:28:11 +02:00
Benoit Marty
8afe31192b Fix issue in themes 2019-06-06 09:50:26 +02:00
Benoit Marty
bbbf64f543 Fix issue in themes 2019-06-06 09:39:08 +02:00
ganfra
6b0ab10231 Crypto: continue threading rework. WIP to shash 2019-06-05 22:18:16 +02:00
Benoit Marty
acedff4e89 FAB Menu
FAB Menu WIP

FAB Menu WIP

FAB Menu WIP
2019-06-05 18:59:50 +02:00
Benoit Marty
f9bfda059f Theme rework WIP 2019-06-05 16:16:37 +02:00
Benoit Marty
94c91e0dae Theme rework WIP 2019-06-05 15:58:00 +02:00
Benoit Marty
48fadd1a11 Theme rework WIP 2019-06-05 15:27:35 +02:00
Benoit Marty
51f5594ea0 Theme rework WIP 2019-06-05 14:57:30 +02:00
Benoit Marty
91114e2afe Quick and dirty implementation of password reveal on HomeScreen 2019-06-05 10:17:59 +02:00
Benoit Marty
e058fa9069 Add elevation on Toolbar 2019-06-04 18:10:38 +02:00
Benoit Marty
2ba7ec48f6 Code cleanup, remove duplicate code, and add some comments 2019-06-04 17:36:49 +02:00
ganfra
e125862794 Crypto: start reworking threading - WIP (to squash) 2019-06-04 16:26:37 +02:00
Benoit Marty
ab6220a4cb Fix crash when reducing empty collection 2019-06-04 15:12:09 +02:00
Benoit Marty
647a066c90
Merge pull request #159 from vector-im/feature/home_rework
Feature/home rework
2019-06-04 12:54:38 +02:00
Benoit Marty
2b6eee4237 Merge branch 'develop' into feature/home_rework 2019-06-04 12:54:16 +02:00
Benoit Marty
7eb1be4633 Valere's review 2019-06-04 12:35:50 +02:00
Valere
0ecc53f59c Added simple (limited) message preview 2019-06-04 12:02:34 +02:00
Benoit Marty
e3983deacc dispose uiDisposable in onDestroy() 2019-06-04 11:02:40 +02:00
Valere
9357059cbc
Merge pull request #155 from vector-im/feature/aggregation_local_echo
Local echo for reactions/edits/redacts
2019-06-04 10:43:22 +02:00
Benoit Marty
9061d5c972 better code 2019-06-04 10:37:49 +02:00
Valere
471170a3e0 Fix / click|longclick link interference
+ some missing long click (image content wrapper)
+ update markwon version
2019-06-04 10:29:56 +02:00
Benoit Marty
43521c6e09 Cleanup 2019-06-04 10:25:29 +02:00
Benoit Marty
fc5edcdf0f Expanding Fab menu 2019-06-04 10:14:48 +02:00
ganfra
3d50393b33 Crypto: continue cleaning. Need threading refactoring 2019-06-03 18:39:37 +02:00
Valere
424fd1347d Code review 2019-06-03 18:23:40 +02:00
Benoit Marty
3475b169ea icon change 2019-06-03 16:46:27 +02:00
Benoit Marty
c1fa728c24 Public rooms little rework 2019-06-03 16:44:31 +02:00
Benoit Marty
3b12f5eec7 Room preview toolbar + link on topic 2019-06-03 14:37:22 +02:00
Benoit Marty
12b03a844d Room preview world readable room 2019-06-03 14:29:29 +02:00
Benoit Marty
4716ceb950 Correct initial state 2019-06-03 14:13:56 +02:00
Benoit Marty
c91a409258 Do not use execute{ } 2019-06-03 14:06:01 +02:00
ganfra
784d55c16c Crypto: WIP cleaning 2019-06-02 20:34:19 +02:00
Valere
99925d7cf9 Local echo for reactions/edits/redacts 2019-05-29 18:43:33 +02:00
Benoit Marty
ae38917a33 Home badge 2019-05-29 18:04:41 +02:00
Benoit Marty
9da727b623 All caught up screen 2019-05-29 16:20:25 +02:00
Benoit Marty
241ee1cb9d Fix issue with Avatar renderer in invitation screen 2019-05-29 15:07:08 +02:00
Benoit Marty
e959fe2e9d Hide FAB when list is scrolling 2019-05-29 14:52:08 +02:00
Benoit Marty
6978ec4246 cleanup 2019-05-29 14:19:40 +02:00
Benoit Marty
2b8bbc550c Room list 2019-05-29 13:36:24 +02:00
Benoit Marty
25f6528049 Drawer layout 2019-05-29 10:52:26 +02:00
Benoit Marty
3289cbd6e7 Cleanup 2019-05-29 09:58:29 +02:00
Benoit Marty
b91e7e9fb8 Cleanup 2019-05-29 09:39:55 +02:00
Benoit Marty
e70a483d6b Introduce Navigator 2019-05-28 21:24:29 +02:00
Benoit Marty
6244913ab9 Join room from room preview 2019-05-28 17:21:54 +02:00
Benoit Marty
33fbcc8ba3 RoomPreview when the room is not world readable 2019-05-28 15:58:30 +02:00
ganfra
3f7d20ec5b Crypto: make encryption working. 2019-05-28 15:54:16 +02:00
Valere
466be1dca5 Fix / issue with avatar url 2019-05-28 15:17:06 +02:00
Valere
bdbd521257
Merge pull request #148 from vector-im/feature/edit_message
Edit message in timeline (+ quote / reply)
2019-05-28 14:57:00 +02:00
Valere
deba756598 Added doc 2019-05-28 10:51:02 +02:00
Valere
3cb99ff64f Renamed package .internal.session.room.annotation to xx.relation 2019-05-28 10:45:58 +02:00
Valere
20e903914c Cleaning / code review 2019-05-28 10:43:36 +02:00
Valere
71ea1c5f9b Fix / avoid newlines and ws in reply event representations 2019-05-27 18:21:59 +02:00
Valere
4a4c0a3da1 Added auto markdown (as per preference)
Fix / show formatted message preview upon composer in edit/quote/reply
Fix / use aggregated content to decide for actions on long click
2019-05-27 18:08:29 +02:00
Benoit Marty
8f2754493c Fix issue with Avatar URL 2019-05-27 17:42:29 +02:00
Benoit Marty
dde94c0d0f Plug screens together 2019-05-27 17:28:18 +02:00
Valere
00d66ffd48
Merge branch 'develop' into feature/edit_message 2019-05-27 17:08:39 +02:00
Valere
c7c7211978 Fix layout preview 2019-05-27 17:02:12 +02:00
Benoit Marty
02a81dd9e1 Fix issue 2019-05-27 16:07:26 +02:00
Benoit Marty
02555fcbac Fix compilation issues after rebase 2019-05-27 15:43:26 +02:00
ganfra
b9d76f5047 Room list & event : decouple notice events formatting to be used within room controller 2019-05-27 15:37:18 +02:00
ganfra
9f9f4c0755 Home: change some UI in room list 2019-05-27 15:34:11 +02:00
ganfra
1691537a1e Room list : add chronological and alphabetical comparators 2019-05-27 15:32:20 +02:00
ganfra
eb2344a43f Home: continue room list rework. 2019-05-27 15:32:20 +02:00
ganfra
c0fd06fd2d Home: start reworking room list. 2019-05-27 15:31:26 +02:00
ganfra
275521db70 Home: continue architecture rework. WIP 2019-05-27 15:30:47 +02:00
ganfra
268730e71b Home: start reworking UX [WIP] 2019-05-27 15:28:27 +02:00
Benoit Marty
0feb10315b
Merge pull request #150 from vector-im/feature/rooms_directory
Feature/rooms directory
2019-05-27 14:28:21 +02:00
Benoit Marty
39f69a6c3b Code quality 2019-05-27 14:00:13 +02:00
Valere
d9fecabc1f Fix / Edits could break cells merging
Edits are not displayable
2019-05-27 12:30:05 +02:00
Benoit Marty
14611d1f7b Disable log 2019-05-27 12:28:06 +02:00
Benoit Marty
fe6e27fd6a Create ButtonStateView with some custom attributes 2019-05-27 12:08:18 +02:00
Valere
0e06908a48 Design update
+ Reply 
+ Better preview in action menu
2019-05-27 11:55:52 +02:00
Benoit Marty
390c6a1977 layout 2019-05-27 10:04:54 +02:00
ganfra
af338b0607 Crypto: decryption is working (but still a lot to do) 2019-05-26 19:21:45 +02:00
Valere
b45cc0e63f Refactoring/ create custom view for composerLayout in timeline
+ simplify quote/edit composer preview animation
2019-05-25 14:49:35 +02:00
Benoit Marty
128dea2677 Scope and error manager 2019-05-24 22:27:26 +02:00
Benoit Marty
cd5e808bb6 Retry join room 2019-05-24 17:38:46 +02:00
Benoit Marty
bbf2f96288 Add marging around item 2019-05-24 15:57:28 +02:00
Benoit Marty
2404eeadf0 RoomDirectoryPicker WIP 2019-05-24 15:43:12 +02:00
Benoit Marty
877de1f597 Get Public rooms and join public room 2019-05-24 11:36:04 +02:00
ganfra
3519ad7c8d Crypto : WIP 2019-05-23 19:12:06 +02:00
Valere
3c16701766 Fix / line too long 2019-05-23 17:56:05 +02:00
Valere
1da0b5be76 Fix / Block command completion in Quote and Edit mode 2019-05-23 17:53:11 +02:00
Valere
c6e428c047 Fix / remove DebugActivity + clean 2019-05-23 17:27:32 +02:00
Valere
45ea5c356e WIP / edit message 2019-05-23 16:44:51 +02:00
Benoit Marty
5da29e8063 Update MxRx library from 0.7.0 to 1.0.1 2019-05-22 16:36:31 +02:00
Benoit Marty
99087019d2 Input type on message text field (Fixes #129) 2019-05-22 15:33:22 +02:00
Benoit Marty
71f8ce001d Fix Crash when connecting to a homeserver URL with a subpath (Fixes #133) 2019-05-22 15:23:36 +02:00
Benoit Marty
bb39db3f42 WIP 2019-05-21 16:33:43 +02:00
Valere
b0e80e49b3 QuickFix / Allow to scroll under login button 2019-05-21 16:28:47 +02:00
Valere
ec53ce9d00
Merge pull request #141 from vector-im/feature/edit_aggregation
Support incoming message edition
2019-05-21 16:21:46 +02:00
Benoit Marty
52d9adad70 WIP 2019-05-21 15:42:09 +02:00
Valere
118a4392a2 Fix / Support redaction of a m.replace event
+ refactoring
2019-05-21 15:33:16 +02:00
Valere
b8c3bdbbf6 Cleaning 2019-05-21 14:27:57 +02:00
Valere
d49007538b Fix / Annotate emote also 2019-05-21 14:26:46 +02:00
Valere
6f103101b6 Show edited annotation in timeline + simple edit history 2019-05-21 14:12:18 +02:00
Valere
a5a9fa3750 Color provider need to be aware of theme 2019-05-21 14:10:19 +02:00
Valere
efcac6b3e4 Fix / Missing schema for realm 2019-05-21 09:50:10 +02:00
Valere
8cb884f10e Support message edition 2019-05-20 18:52:48 +02:00
Benoit Marty
6d8000b957 Log 2019-05-20 17:13:08 +02:00
Benoit Marty
f5bd215f36 rework 2019-05-20 16:55:45 +02:00
Benoit Marty
532a028e41 Split again 2019-05-20 16:13:50 +02:00
Benoit Marty
e0e41d9e5c Create common action 2019-05-17 15:33:38 +02:00
Benoit Marty
340830d45f Test passed 2019-05-17 15:21:44 +02:00
Benoit Marty
de4662b9d5 Remove all async thread 2019-05-17 15:05:07 +02:00
Benoit Marty
c66e82c4ae Create OneTimeKeysManager 2019-05-17 12:39:18 +02:00
Benoit Marty
a2210a6b0d WIP 2019-05-17 11:20:22 +02:00
Benoit Marty
102bc9c01b SAS Tested 2019-05-16 17:28:51 +02:00
Benoit Marty
e70fd8e351 canonicalize 2019-05-16 15:36:51 +02:00
Benoit Marty
1436667e7d Crypto 2019-05-16 10:34:17 +02:00
1420 changed files with 79043 additions and 18601 deletions

View File

@ -5,18 +5,30 @@
# Build debug version of the RiotX application, from the develop branch and the features branches # Build debug version of the RiotX application, from the develop branch and the features branches


steps: steps:
- label: "Assemble Debug version" - label: "Assemble GPlay Debug version"
agents: agents:
# We use a medium sized instance instead of the normal small ones because # We use a medium sized instance instead of the normal small ones because
# gradle build is long # gradle build is long
queue: "medium" queue: "medium"
commands: commands:
- "./gradlew clean lintGplayRelease assembleGplayDebug --stacktrace" - "./gradlew clean lintGplayRelease assembleGplayDebug --stacktrace"
- "./gradlew lintFdroidRelease assembleFdroidDebug --stacktrace"
artifact_paths: artifact_paths:
- "vector/build/outputs/apk/gplay/debug/*.apk" - "vector/build/outputs/apk/gplay/debug/*.apk"
branches: "!master"
plugins:
- docker#v3.1.0:
image: "runmymind/docker-android-sdk"

- label: "Assemble FDroid Debug version"
agents:
# We use a medium sized instance instead of the normal small ones because
# gradle build is long
queue: "medium"
commands:
- "./gradlew clean lintFdroidRelease assembleFdroidDebug --stacktrace"
artifact_paths:
- "vector/build/outputs/apk/fdroid/debug/*.apk" - "vector/build/outputs/apk/fdroid/debug/*.apk"
branches: "develop feature/*" branches: "!master"
plugins: plugins:
- docker#v3.1.0: - docker#v3.1.0:
image: "runmymind/docker-android-sdk" image: "runmymind/docker-android-sdk"
@ -33,7 +45,7 @@ steps:
branches: "master" branches: "master"
plugins: plugins:
- docker#v3.1.0: - docker#v3.1.0:
image: "runmymind/docker-android-sdk" image: "runmymind/docker-android-sdk"


# Code quality # Code quality



View File

@ -1,24 +1,106 @@
Changes in RiotX 0.XX (2019-XX-XX) Changes in RiotX 0.5.0 (2019-XX-XX)
=================================================== ===================================================


Features: Features:
- Contextual action menu for messages in room -


Improvements: Improvements:
- - Reduce default release build log level, and lab option to enable more logs.


Other changes: Other changes:
- -


Bugfix: Bugfix:
- - Fix crash due to missing informationData (#535)
- Progress in initial sync dialog is decreasing for a step and should not (#532)


Translations: Translations:
- -


Build: Build:
- - Fix issue with version name (#533)
- Fix rendering issue of accepted third party invitation event


Changes in RiotX 0.4.0 (2019-XX-XX)
===================================================

Features:
- Display read receipts in timeline (#81)

Improvements:
- Reactions: Reinstate the ability to react with non-unicode keys (#307)

Bugfix:
- Fix text diff linebreak display (#441)
- Date change message repeats for each redaction until a normal message (#358)
- Slide-in reply icon is distorted (#423)
- Regression / e2e replies not encrypted
- Some video won't play
- Privacy: remove log of notifiable event (#519)
- Fix crash with EmojiCompat (#530)

Changes in RiotX 0.3.0 (2019-08-08)
===================================================

Features:
- Create Direct Room flow
- Handle `/markdown` command

Improvements:
- UI for pending edits (#193)
- UX image preview screen transition (#393)
- Basic support for resending failed messages (retry/remove)
- Enable proper cancellation of suspending functions (including db transaction)
- Enhances network connectivity checks in SDK
- Add "View Edit History" item in the message bottom sheet (#401)
- Cancel sync request on pause and timeout to 0 after pause (#404)

Other changes:
- Show sync progress also in room detail screen (#403)

Bugfix:
- Edited message: link confusion when (edited) appears in body (#398)
- Close detail room screen when the room is left with another client (#256)
- Clear notification for a room left on another client
- Fix messages with empty `in_reply_to` not rendering (#447)
- Fix clear cache (#408) and Logout (#205)
- Fix `(edited)` link can be copied to clipboard (#402)

Build:
- Split APK: generate one APK per arch, to reduce APK size of about 30%


Changes in RiotX 0.2.0 (2019-07-18)
===================================================

Features:
- Message Editing: View edit history (#121)
- Rooms filtering (#304)
- Edit in encrypted room

Improvements:
- Handle click on redacted events: view source and create permalink
- Improve long tap menu: reply on top, more compact (#368)
- Quick reply in timeline with swipe gesture (#167)
- Improve edit of replies
- Improve performance on Room Members and Users management (#381)

Other changes:
- migrate from rxbinding 2 to rxbinding 3

Bugfix:
- Fix regression on permalink click
- Fix crash reported by the PlayStore (#341)
- Fix Chat composer separator color in dark/black theme
- Fix bad layout for room directory filter (#349)
- Fix Copying link from a message shouldn't open context menu (#364)

Changes in RiotX 0.1.0 (2019-07-11)
===================================================

First release!

Mode details here: https://medium.com/@RiotChat/introducing-the-riotx-beta-for-android-b17952e8f771




======================================================= =======================================================
@ -26,7 +108,7 @@ Build:
======================================================= =======================================================




Changes in RiotX 0.XX (2019-XX-XX) Changes in RiotX 0.0.0 (2019-XX-XX)
=================================================== ===================================================


Features: Features:

View File

@ -1,4 +1,4 @@
[![Buildkite](https://badge.buildkite.com/657d3db27364448d69d54f66c690f7788bc6aa80a7628e37f3.svg?branch=develop)](https://buildkite.com/matrix-dot-org/riotx-android) [![Buildkite](https://badge.buildkite.com/657d3db27364448d69d54f66c690f7788bc6aa80a7628e37f3.svg?branch=develop)](https://buildkite.com/matrix-dot-org/riotx-android/builds?branch=develop)
[![Weblate](https://translate.riot.im/widgets/riot-android/-/svg-badge.svg)](https://translate.riot.im/engage/riot-android/?utm_source=widget) [![Weblate](https://translate.riot.im/widgets/riot-android/-/svg-badge.svg)](https://translate.riot.im/engage/riot-android/?utm_source=widget)
[![RiotX Android Matrix room #riot-android:matrix.org](https://img.shields.io/matrix/riotx:matrix.org.svg?label=%23RiotX:matrix.org&logo=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#riotx:matrix.org) [![RiotX Android Matrix room #riot-android:matrix.org](https://img.shields.io/matrix/riotx:matrix.org.svg?label=%23RiotX:matrix.org&logo=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#riotx:matrix.org)
[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=vector.android.riotx&metric=alert_status)](https://sonarcloud.io/dashboard?id=vector.android.riotx) [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=vector.android.riotx&metric=alert_status)](https://sonarcloud.io/dashboard?id=vector.android.riotx)
@ -7,14 +7,31 @@


# RiotX Android # RiotX Android


RiotX is an Android Matrix Client currently in development. The application is not yet available on the PlayStore. RiotX is an Android Matrix Client currently in beta but in active development.


It's based on a new Matrix SDK, written in Kotlin. It is a total rewrite of [Riot-Android](https://github.com/vector-im/riot-android) with a new user experience. RiotX will become the official replacement as soon as all features are implemented.


Download nightly build here: [![Buildkite](https://badge.buildkite.com/657d3db27364448d69d54f66c690f7788bc6aa80a7628e37f3.svg?branch=develop)](https://buildkite.com/matrix-dot-org/riotx-android/builds?branch=develop) [<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" alt="Get it on Google Play" height="60">](https://play.google.com/store/apps/details?id=im.vector.riotx)

Nightly build: [![Buildkite](https://badge.buildkite.com/657d3db27364448d69d54f66c690f7788bc6aa80a7628e37f3.svg?branch=develop)](https://buildkite.com/matrix-dot-org/riotx-android/builds?branch=develop)

# New Android SDK

RiotX is based on a new Android SDK fully written in Kotlin (like RiotX). In order to make the early development as fast as possible, RiotX and the new SDK currently share the same git repository. We will make separate repos once the API is stable enough.


# Roadmap

The current target is to release an application out of beta with the same level of features (and even more) as Riot.
The roadmap has 3 phases:

- [phase 0](https://github.com/vector-im/riotX-android/labels/phase0): Prototyping / Project setup
- [phase 1](https://github.com/vector-im/riotX-android/labels/phase1): Beta release to the Play Store
- [phase 2](https://github.com/vector-im/riotX-android/labels/phase2): Out of beta


Matrix Room: [![RiotX Android Matrix room #riot-android:matrix.org](https://img.shields.io/matrix/riotx:matrix.org.svg?label=%23RiotX:matrix.org&logo=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#riotx:matrix.org)


## Contributing ## Contributing


Please refer to [CONTRIBUTING.md](https://github.com/vector-im/riotX-android/blob/develop/CONTRIBUTING.md) if you want to contribute the Matrix on Android projects! Please refer to [CONTRIBUTING.md](https://github.com/vector-im/riotX-android/blob/develop/CONTRIBUTING.md) if you want to contribute on Matrix Android projects!

Come chat with the community in the dedicated Matrix [room](https://matrix.to/#/#riotx:matrix.org).

View File

@ -1,8 +1,9 @@
import javax.tools.JavaCompiler

// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.


buildscript { buildscript {
ext.kotlin_version = '1.3.21' ext.kotlin_version = '1.3.21'
ext.koin_version = '1.0.2'
repositories { repositories {
google() google()
jcenter() jcenter()
@ -11,11 +12,12 @@ buildscript {
} }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.3.2' classpath 'com.android.tools.build:gradle:3.4.1'
classpath 'com.google.gms:google-services:4.2.0' classpath 'com.google.gms:google-services:4.2.0'
classpath "com.airbnb.okreplay:gradle-plugin:1.4.0" classpath "com.airbnb.okreplay:gradle-plugin:1.4.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2' classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2'
classpath 'com.google.android.gms:oss-licenses-plugin:0.9.5'


// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
@ -24,12 +26,47 @@ buildscript {


allprojects { allprojects {
repositories { repositories {
maven { url "http://dl.bintray.com/piasy/maven" } // For olm library. This has to be declared first, to ensure that Olm library is not downloaded from another repo
maven { url 'https://jitpack.io' } maven {
url 'https://jitpack.io'
content {
// Use this repo only for olm library
includeGroupByRegex "org\\.matrix\\.gitlab\\.matrix-org"
// And also for FilePicker
includeGroupByRegex "com\\.github\\.jaiselrahman"
// And monarchy
includeGroupByRegex "com\\.github\\.Zhuinden"
}
}
maven {
url "http://dl.bintray.com/piasy/maven"
content {
includeGroupByRegex "com\\.github\\.piasy"
}
}
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
google() google()
jcenter() jcenter()
maven {
url 'https://repo.adobe.com/nexus/content/repositories/public/'
content {
includeGroupByRegex "diff_match_patch"
}
}
} }

tasks.withType(JavaCompile).all {
options.compilerArgs += [
'-Adagger.gradle.incremental=enabled'
]
}

afterEvaluate {
extensions.findByName("kapt")?.arguments {
arg("dagger.gradle.incremental", "enabled")
}
}

} }


task clean(type: Delete) { task clean(type: Delete) {
@ -38,6 +75,10 @@ task clean(type: Delete) {


apply plugin: 'org.sonarqube' apply plugin: 'org.sonarqube'


// To run a sonar analysis:
// Run './gradlew sonarqube -Dsonar.login=<REPLACE_WITH_SONAR_KEY>'
// The SONAR_KEY is stored in passbolt

sonarqube { sonarqube {
properties { properties {
property "sonar.projectName", "RiotX-Android" property "sonar.projectName", "RiotX-Android"
@ -63,3 +104,23 @@ project(":vector") {
} }
} }
} }

//project(":matrix-sdk-android") {
// sonarqube {
// properties {
// property "sonar.sources", project(":matrix-sdk-android").android.sourceSets.main.java.srcDirs
// // exclude source code from analyses separated by a colon (:)
// // property "sonar.exclusions", "**/*.*"
// }
// }
//}
//
//project(":matrix-sdk-android-rx") {
// sonarqube {
// properties {
// property "sonar.sources", project(":matrix-sdk-android-rx").android.sourceSets.main.java.srcDirs
// // exclude source code from analyses separated by a colon (:)
// // property "sonar.exclusions", "**/*.*"
// }
// }
//}

281
docs/notifications.md Normal file
View File

@ -0,0 +1,281 @@
This document aims to describe how RiotX android displays notifications to the end user. It also clarifies notifications and background settings in the app.

# Table of Contents
1. [Prerequisites Knowledge](#prerequisites-knowledge)
* [How does a matrix client gets a message from a Home Server?](#how-does-a-matrix-client-gets-a-message-from-a-home-server)
* [How does a mobile app receives push notification?](#how-does-a-mobile-app-receives-push-notification)
* [Push VS Notification](#push-vs-notification)
* [Push in the matrix federated world](#push-in-the-matrix-federated-world)
* [How does the Home Server knows when to notify a client?](#how-does-the-home-server-knows-when-to-notify-a-client)
* [Push vs privacy, and mitigation](#push-vs-privacy-and-mitigation)
* [Background processing limitations](#background-processing-limitations)
2. [RiotX Notification implementations](#riotx-notification-implementations)
* [Requirements](#requirements)
* [Foreground sync mode (Gplay & F-Droid)](#foreground-sync-mode-gplay-f-droid)
* [Push (FCM) received in background](#push-fcm-received-in-background)
* [FCM Fallback mode](#fcm-fallback-mode)
* [F-Droid background Mode](#f-droid-background-mode)
3. [Application Settings](#application-settings)


First let's start with some prerequisite knowledge

# Prerequisites Knowledge

## How does a matrix client gets a message from a Home Server?

In order to get messages from a home server, a matrix client need to perform a ``sync`` operation.

`To read events, the intended flow of operation is for clients to first call the /sync API without a since parameter. This returns the most recent message events for each room, as well as the state of the room at the start of the returned timeline. `

The client need to call the `sync`API periodically in order to get incremental updates of the server state (new messages).
This mechanism is known as **HTTP long Polling**.

Using the **HTTP Long Polling** mechanism a client polls a server requesting new information.
The server *holds the request open until new data is available*.
Once available, the server responds and sends the new information.
When the client receives the new information, it immediately sends another request, and the operation is repeated.
This effectively emulates a server push feature.

The HTTP long Polling can be fine tuned in the **SDK** using two parameters:
* timout (Sync request timeout)
* delay (Delay between each sync)

**timeout** is a server paramter, defined by:
```
The maximum time to wait, in milliseconds, before returning this request.`
If no events (or other data) become available before this time elapses, the server will return a response with empty fields.
By default, this is 0, so the server will return immediately even if the response is empty.
```

**delay** is a client preference. When the server responds to a sync request, the client waits for `delay`before calling a new sync.

When the RiotX Android app is open (i.e in foreground state), the default timeout is 30 seconds, and delay is 0.

## How does a mobile app receives push notification

Push notification is used as a way to wake up a mobile application when some important information is available and should be processed.

Typically in order to get push notification, an application relies on a **Push Notification Service** or **Push Provider**.

For example iOS uses APNS (Apple Push Notification Service).
Most of android devices relies on Google's Firebase Cloud Messaging (FCM).
> FCM has replaced Google Cloud Messaging (GCM - deprecated April 10 2018)

FCM will only work on android devices that have Google plays services installed
(In simple terms, Google Play Services is a background service that runs on Android, which in turn helps in integrating Googles advanced functionalities to other applications)

De-Googlified devices need to rely on something else in order to stay up to date with a server.
There some cases when devices with google services cannot use FCM (network infrastructure limitations -firewalls- ,
privacy and or independency requirement, source code licence)

## Push VS Notification

This need some disambiguation, because it is the source of common confusion:


*The fact that you see a notification on your screen does not mean that you have successfully configured your PUSH plateform.*

Technically there is a difference between a push and a notification. A notification is what you see on screen and/or in the notification Menu/Drawer (in the top bar of the phone).

Notifications are not always triggered by a push (One can display a notification locally triggered by an alarm)


## Push in the matrix federated world

In order to send a push to a mobile, App developers need to have a server that will use the FCM APIs, and these APIs requires authentication!
This server is called a **Push Gateway** in the matrix world

That means that RiotX Android, a matrix client created by New Vector, is using a **Push Gateway** with the needed credentials (FCM API secret Key) in order to send push to the New Vector client.

If you create your own matrix client, you will also need to deploy an instance of a **Push Gateway** with the credentials needed to use FCM for your app.

On registration, a matrix client must tell to it's Home Server what Push Gateway to use.

See [Sygnal](https://github.com/matrix-org/sygnal/) for a reference implementation.
```

+--------------------+ +-------------------+
Matrix HTTP | | | |
Notification Protocol | App Developer | | Device Vendor |
| | | |
+-------------------+ | +----------------+ | | +---------------+ |
| | | | | | | | | |
| Matrix homeserver +-----> Push Gateway +------> Push Provider | |
| | | | | | | | | |
+-^-----------------+ | +----------------+ | | +----+----------+ |
| | | | | |
Matrix | | | | | |
Client/Server API + | | | | |
| | +--------------------+ +-------------------+
| +--+-+ |
| | <-------------------------------------------+
+---+ |
| | Provider Push Protocol
+----+

Mobile Device or Client
```

Recommended reading:
* https://thomask.sdf.org/blog/2016/12/11/riots-magical-push-notifications-in-ios.html
* https://matrix.org/docs/spec/client_server/r0.4.0.html#id128


## How does the Home Server knows when to notify a client?

This is defined by [**push rules**](https://matrix.org/docs/spec/client_server/r0.4.0.html#push-rules-).

`A push rule is a single rule that states under what conditions an event should be passed onto a push gateway and how the notification should be presented (sound / importance).`

A Home Server can be configured with default rules (for Direct messages, group messages, mentions, etc.. ).

There are different kind of push rules, it can be per room (each new message on this room should be notified), it can also define a pattern that a message should match (when you are mentioned, or key word based).

Notifications have 2 'levels' (`highlighted = true/false sound = default/custom`). In RiotX these notifications level are reflected as Noisy/Silent.

**What about encrypted messages?**

Of course, content patterns matching cannot be used for encrypted messages server side (as the content is encrypted).

That is why clients are able to **process the push rules client side** to decide what kind of notification should be presented for a given event.

## Push vs privacy, and mitigation

As seen previously, App developers don't directly send a push to the end user's device, they use a Push Provider as intermediary. So technically this intermediary is able to read the content of what is sent.

App developers usually mitigate this by sending a `silent notification`, that is a notification with no identifiable data, or with an encrypted payload. When the push is received the app can then synchronise to it's server in order to generate a local notification.


## Background processing limitations

A mobile applications process live in a managed word, meaning that its process can be limited (e.g no network access), stopped or killed at almost anytime by the Operating System.

In order to improve the battery life of their devices some constructors started to implement mechanism to drastically limit background execution of applications (e.g MIUI/Xiaomi restrictions, Sony stamina mode).
Then starting android M, android has also put more focus on improving device performances, introducing several IDLE modes, App-Standby, Light Doze, Doze.

In a nutshell, apps can't do much in background now.

If the devices is not plugged and stays IDLE for a certain amount of time, radio (mobile connectivity) and CPU can/will be turned off.

For an application like RiotX, where users can receive important information at anytime, the best option is to rely on a push system (Google's Firebase Message a.k.a FCM). FCM high priority push can wake up the device and whitelist an application to perform background task (for a limited but unspecified amount of time).

Notice that this is still evolving, and in future versions application that has been 'background restricted' by users won't be able to wake up even when a high priority push is received. Also high priority notifications could be rate limited (not defined anywhere)

It's getting a lot more complicated when you cannot rely on FCM (because: closed sources, network/firewall restrictions, privacy concerns).
The documentation on this subject is vague, and as per our experiments not always exact, also device's behaviour is fragmented.

It is getting more and more complex to have reliable notifications when FCM is not used.

# RiotX Notification implementations

## Requirements

RiotX Android must work with and without FCM.
* The RiotX android app published on F-Droid do not rely on FCM (all related dependencies are not present)
* The RiotX android app published on google play rely on FCM, with a fallback mode when FCM registration has failed (e.g outdated or missing Google Play Services)

## Foreground sync mode (Gplay & F-Droid)

When in foreground, RiotX performs sync continuously with a timeout value set to 10 seconds (see HttpPooling).

As this mode does not need to live beyond the scope of the application, and as per Google recommendation, RiotX uses the internal app resources (Thread and Timers) to perform the syncs.

This mode is turned on when the app enters foreground, and off when enters background.

In background, and depending on wether push is available or not, RiotX will use different methods to perform the syncs (Workers / Alarms / Service)

## Push (FCM) received in background

In order to enable Push, RiotX must first get a push token from the firebase SDK, then register a pusher with this token on the HomeServer.

When a message should be notified to a user, the user's homeserver notifies the registered `push gateway` for RiotX, that is [sygnal](https://github.com/matrix-org/sygnal) _- The reference implementation for push gateways -_ hosted by matrix.org.

This sygnal instance is configured with the required FCM API authentication token, and will then use the FCM API in order to notify the user's device running riotX.

```
Homeserver ----> Sygnal (configured for RiotX) ----> FCM ----> RiotX
```

The push gateway is configured to only send `(eventId,roomId)` in the push payload (for better [privacy](#push-vs-privacy-and-mitigation)).

RiotX needs then to synchronise with the user's HomeServer, in order to resolve the event and create a notification.

As per [Google recommendation](https://android-developers.googleblog.com/2018/09/notifying-your-users-with-fcm.html), RiotX will then use the WorkManager API in order to trigger a background sync.

**Google recommendations:**
> We recommend using FCM messages in combination with the WorkManager 1 or JobScheduler API

> Avoid background services. One common pitfall is using a background service to fetch data in the FCM message handler, since background service will be stopped by the system per recent changes to Google Play Policy

```
Homeserver ----> Sygnal ----> FCM ----> RiotX
(Sync) ----> Homeserver
<----
Display notification
```

**Possible outcomes**

Upon reception of the FCM push, RiotX will perform a sync call to the Home Server, during this process it is possible that:
* Happy path, the sync is performed, the message resolved and displayed in the notification drawer
* The notified message is not in the sync. Can happen if a lot of things did happen since the push (`gappy sync`)
* The sync generates additional notifications (e.g an encrypted message where the user is mentioned detected locally)
* The sync takes too long and the process is killed before completion, or network is not reliable and the sync fails.

RiotX implements several strategies in these cases (TODO document)

## FCM Fallback mode

It is possible that RiotX is not able to get a FCM push token.
Common errors (amoung several others) that can cause that:
* Google Play Services is outdated
* Google Play Service fails in someways with FCM servers (infamous `SERVICE_NOT_AVAILABLE`)

If RiotX is able to detect one of this cases, it will notifies it to the users and when possible help him fix it via a dedicated troubleshoot screen.

Meanwhile, in order to offer a minimal service, and as per Google's recommendation for background activities, RiotX will launch periodic background sync in order to stays in sync with servers.

The fallback mode is impacted by all the battery life saving mechanism implemented by android. Meaning that if the app is not used for a certain amount of time (`App-Standby`), or the device stays still and unplugged (`Light Doze`) , the sync will become less frequent.

And if the device stays unplugged and still for too long (`Doze Mode`), no background sync will be perform at all (the system's `Ignore Battery Optimization option` has no effect on that).

Also the time interval between sync is elastic, controlled by the system to group other apps background sync request and start radio/cpu only once for all.

Usually in this mode, what happen is when you take back your phone in your hand, you suddenly receive notifications.

The fallback mode is supposed to be a temporary state waiting for the user to fix issues for FCM, or for App Developers that has done a fork to correctly configure their FCM settings.

## F-Droid background Mode

The F-Droid RiotX flavor has no dependencies to FCM, therefore cannot relies on Push.

Also Google's recommended background processing method cannot be applied. This is because all of these methods are affected by IDLE modes, and will result on the user not being notified at all when the app is in a Doze mode (only in maintenance windows that could happens only after hours).

Only solution left is to use `AlarmManager`, that offers new API to allow launching some process even if the App is in IDLE modes.

Notice that these alarms, due to their potential impact on battery life, can still be restricted by the system. Documentation says that they will not be triggered more than every minutes under normal system operation, and when in low power mode about every 15 mn.

These restrictions can be relaxed by requirering the app to be white listed from battery optimization.

F-Droid version will schedule alarms that will then trigger a Broadcast Receiver, that in turn will launch a Service (in the classic android way), and the reschedule an alarm for next time.

Depending on the system status (or device make), it is still possible that the app is not given enough time to launch the service, or that the radio is still turned off thus preventing the sync to success (that's why Alarms are not recommended for network related tasks).

That is why on RiotX F-Droid, the broadcast receiver will acquire a temporary WAKE_LOCK for several seconds (thus securing cpu/network), and launch the service in foreground. The service performs the sync.

Note that foreground services require to put a notification informing the user that the app is doing something even if not launched).



# Application Settings

**Notifications > Enable notifications for this account**

Configure Sygnal to send or not notifications to all user devices.

**Notifications > Enable notifications for this device**

Disable notifications locally. The push server will continue to send notifications to the device but this one will ignore them.


View File

@ -13,3 +13,11 @@ org.gradle.jvmargs=-Xmx1536m
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true


vector.debugPrivateData=false
vector.httpLogLevel=NONE

# Note: to debug, you can put and uncomment the following lines in the file ~/.gradle/gradle.properties to override the value above
#vector.debugPrivateData=true
#vector.httpLogLevel=BODY

View File

@ -33,16 +33,14 @@ android {
} }


dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(":matrix-sdk-android") implementation project(":matrix-sdk-android")
implementation 'androidx.appcompat:appcompat:1.1.0-alpha01' implementation 'androidx.appcompat:appcompat:1.1.0-beta01'
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'

// Paging // Paging
implementation 'androidx.paging:paging-runtime:2.0.0' implementation "androidx.paging:paging-runtime-ktx:2.1.0"


testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
} }

View File

@ -20,6 +20,8 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.android.MainThreadDisposable import io.reactivex.android.MainThreadDisposable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers


private class LiveDataObservable<T>( private class LiveDataObservable<T>(
private val liveData: LiveData<T>, private val liveData: LiveData<T>,
@ -57,5 +59,5 @@ private class LiveDataObservable<T>(
} }


fun <T> LiveData<T>.asObservable(): Observable<T> { fun <T> LiveData<T>.asObservable(): Observable<T> {
return LiveDataObservable(this) return LiveDataObservable(this).observeOn(Schedulers.computation())
} }

View File

@ -0,0 +1,39 @@
/*
* Copyright 2019 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.matrix.rx

import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.util.Cancelable
import io.reactivex.CompletableEmitter
import io.reactivex.SingleEmitter

internal class MatrixCallbackCompletable<T>(private val completableEmitter: CompletableEmitter) : MatrixCallback<T> {

override fun onSuccess(data: T) {
completableEmitter.onComplete()
}

override fun onFailure(failure: Throwable) {
completableEmitter.tryOnError(failure)
}
}

fun Cancelable.toCompletable(completableEmitter: CompletableEmitter) {
completableEmitter.setCancellable {
this.cancel()
}
}

View File

@ -14,23 +14,25 @@
* limitations under the License. * limitations under the License.
*/ */


package im.vector.riotredesign.features.home.room.list package im.vector.matrix.rx


import android.content.SharedPreferences import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.util.Cancelable
import io.reactivex.SingleEmitter


private const val SHARED_PREFS_SELECTED_ROOM_KEY = "SHARED_PREFS_SELECTED_ROOM_KEY" internal class MatrixCallbackSingle<T>(private val singleEmitter: SingleEmitter<T>) : MatrixCallback<T> {


class RoomSelectionRepository(private val sharedPreferences: SharedPreferences) { override fun onSuccess(data: T) {

singleEmitter.onSuccess(data)
fun lastSelectedRoom(): String? {
return sharedPreferences.getString(SHARED_PREFS_SELECTED_ROOM_KEY, null)
} }


fun saveLastSelectedRoom(roomId: String) { override fun onFailure(failure: Throwable) {
sharedPreferences.edit() singleEmitter.tryOnError(failure)
.putString(SHARED_PREFS_SELECTED_ROOM_KEY, roomId)
.apply()
} }

} }


fun <T> Cancelable.toSingle(singleEmitter: SingleEmitter<T>) {
singleEmitter.setCancellable {
this.cancel()
}
}

View File

@ -17,19 +17,43 @@
package im.vector.matrix.rx package im.vector.matrix.rx


import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
import im.vector.matrix.android.api.session.room.model.ReadReceipt
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.Single


class RxRoom(private val room: Room) { class RxRoom(private val room: Room) {


fun liveRoomSummary(): Observable<RoomSummary> { fun liveRoomSummary(): Observable<RoomSummary> {
return room.roomSummary.asObservable() return room.liveRoomSummary().asObservable()
} }


fun liveRoomMemberIds(): Observable<List<String>> { fun liveRoomMemberIds(): Observable<List<String>> {
return room.getRoomMemberIdsLive().asObservable() return room.getRoomMemberIdsLive().asObservable()
} }


fun liveAnnotationSummary(eventId: String): Observable<EventAnnotationsSummary> {
return room.getEventSummaryLive(eventId).asObservable()
}

fun liveTimelineEvent(eventId: String): Observable<TimelineEvent> {
return room.liveTimeLineEvent(eventId).asObservable()
}

fun loadRoomMembersIfNeeded(): Single<Unit> = Single.create {
room.loadRoomMembersIfNeeded(MatrixCallbackSingle(it)).toSingle(it)
}

fun joinRoom(viaServers: List<String> = emptyList()): Single<Unit> = Single.create {
room.join(viaServers, MatrixCallbackSingle(it)).toSingle(it)
}

fun liveEventReadReceipts(eventId: String): Observable<List<ReadReceipt>> {
return room.getEventReadReceiptsLive(eventId).asObservable()
}

} }


fun Room.rx(): RxRoom { fun Room.rx(): RxRoom {

View File

@ -16,10 +16,16 @@


package im.vector.matrix.rx package im.vector.matrix.rx


import androidx.paging.PagedList
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.matrix.android.api.session.group.model.GroupSummary
import im.vector.matrix.android.api.session.pushers.Pusher
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
import im.vector.matrix.android.api.session.sync.SyncState
import im.vector.matrix.android.api.session.user.model.User
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.Single


class RxSession(private val session: Session) { class RxSession(private val session: Session) {


@ -31,6 +37,36 @@ class RxSession(private val session: Session) {
return session.liveGroupSummaries().asObservable() return session.liveGroupSummaries().asObservable()
} }


fun liveSyncState(): Observable<SyncState> {
return session.syncState().asObservable()
}

fun livePushers(): Observable<List<Pusher>> {
return session.livePushers().asObservable()
}

fun liveUsers(): Observable<List<User>> {
return session.liveUsers().asObservable()
}

fun livePagedUsers(filter: String? = null): Observable<PagedList<User>> {
return session.livePagedUsers(filter).asObservable()
}

fun createRoom(roomParams: CreateRoomParams): Single<String> = Single.create {
session.createRoom(roomParams, MatrixCallbackSingle(it)).toSingle(it)
}

fun searchUsersDirectory(search: String,
limit: Int,
excludedUserIds: Set<String>): Single<List<User>> = Single.create {
session.searchUsersDirectory(search, limit, excludedUserIds, MatrixCallbackSingle(it)).toSingle(it)
}

fun joinRoom(roomId: String, viaServers: List<String> = emptyList()): Single<Unit> = Single.create {
session.joinRoom(roomId, viaServers, MatrixCallbackSingle(it)).toSingle(it)
}

} }


fun Session.rx(): RxSession { fun Session.rx(): RxSession {

View File

@ -6,20 +6,14 @@ apply plugin: 'realm-android'
apply plugin: 'okreplay' apply plugin: 'okreplay'


buildscript { buildscript {

repositories { repositories {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath "io.realm:realm-gradle-plugin:5.9.0" classpath "io.realm:realm-gradle-plugin:5.12.0"
} }
} }


repositories {
google()
jcenter()
}

androidExtensions { androidExtensions {
experimental = true experimental = true
} }
@ -32,10 +26,12 @@ android {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 28 targetSdkVersion 28
versionCode 1 versionCode 1
versionName "1.0" versionName "0.0.1"
// Multidex is useful for tests
multiDexEnabled true multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"


buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
resValue "string", "git_sdk_revision", "\"${gitRevision()}\"" resValue "string", "git_sdk_revision", "\"${gitRevision()}\""
resValue "string", "git_sdk_revision_unix_date", "\"${gitRevisionUnixDate()}\"" resValue "string", "git_sdk_revision_unix_date", "\"${gitRevisionUnixDate()}\""
resValue "string", "git_sdk_revision_date", "\"${gitRevisionDate()}\"" resValue "string", "git_sdk_revision_date", "\"${gitRevisionDate()}\""
@ -45,10 +41,9 @@ android {


debug { debug {
// Set to true to log privacy or sensible data, such as token // Set to true to log privacy or sensible data, such as token
buildConfigField "boolean", "LOG_PRIVATE_DATA", "false" buildConfigField "boolean", "LOG_PRIVATE_DATA", project.property("vector.debugPrivateData")

// Set to BODY instead of NONE to enable logging // Set to BODY instead of NONE to enable logging
buildConfigField "okhttp3.logging.HttpLoggingInterceptor.Level", "OKHTTP_LOGGING_LEVEL", "okhttp3.logging.HttpLoggingInterceptor.Level.NONE" buildConfigField "okhttp3.logging.HttpLoggingInterceptor.Level", "OKHTTP_LOGGING_LEVEL", "okhttp3.logging.HttpLoggingInterceptor.Level." + project.property("vector.httpLogLevel")
} }


release { release {
@ -67,6 +62,11 @@ android {
lintOptions { lintOptions {
lintConfig file("lint.xml") lintConfig file("lint.xml")
} }

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
} }


static def gitRevision() { static def gitRevision() {
@ -87,48 +87,53 @@ static def gitRevisionDate() {
dependencies { dependencies {


def arrow_version = "0.8.0" def arrow_version = "0.8.0"
def support_version = '1.1.0-alpha03' def support_version = '1.1.0-beta01'
def moshi_version = '1.8.0' def moshi_version = '1.8.0'
def lifecycle_version = '2.0.0' def lifecycle_version = '2.0.0'
def coroutines_version = "1.0.1" def coroutines_version = "1.0.1"
def markwon_version = '3.0.0'
def daggerVersion = '2.23.1'


implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"


implementation "androidx.appcompat:appcompat:$support_version" implementation "androidx.appcompat:appcompat:1.1.0-rc01"
implementation "androidx.recyclerview:recyclerview:$support_version" implementation "androidx.recyclerview:recyclerview:1.1.0-beta01"


implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"


// Network // Network
implementation 'com.squareup.retrofit2:retrofit:2.4.0' implementation 'com.squareup.retrofit2:retrofit:2.6.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.4.0' implementation 'com.squareup.retrofit2:converter-moshi:2.4.0'
implementation 'com.squareup.okhttp3:okhttp:3.11.0' implementation 'com.squareup.okhttp3:okhttp:3.14.1'
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
implementation 'com.novoda:merlin:1.1.6' implementation 'com.novoda:merlin:1.2.0'
implementation "com.squareup.moshi:moshi-adapters:$moshi_version" implementation "com.squareup.moshi:moshi-adapters:$moshi_version"
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"


implementation "ru.noties.markwon:core:$markwon_version"

// Database // Database
implementation 'com.github.Zhuinden:realm-monarchy:0.5.1' implementation 'com.github.Zhuinden:realm-monarchy:0.5.1'
kapt 'dk.ilios:realmfieldnameshelper:1.1.1' kapt 'dk.ilios:realmfieldnameshelper:1.1.1'


// Work // Work
implementation "android.arch.work:work-runtime-ktx:1.0.0" implementation "androidx.work:work-runtime-ktx:2.1.0-rc01"


// FP // FP
implementation "io.arrow-kt:arrow-core:$arrow_version" implementation "io.arrow-kt:arrow-core:$arrow_version"
implementation "io.arrow-kt:arrow-instances-core:$arrow_version" implementation "io.arrow-kt:arrow-instances-core:$arrow_version"
implementation "io.arrow-kt:arrow-effects:$arrow_version"
implementation "io.arrow-kt:arrow-effects-instances:$arrow_version" // olm lib is now hosted by jitpack: https://jitpack.io/#org.matrix.gitlab.matrix-org/olm
implementation "io.arrow-kt:arrow-integration-retrofit-adapter:$arrow_version" implementation 'org.matrix.gitlab.matrix-org:olm:3.1.2'


// DI // DI
implementation "org.koin:koin-core:$koin_version" implementation "com.google.dagger:dagger:$daggerVersion"
implementation "org.koin:koin-core-ext:$koin_version" kapt "com.google.dagger:dagger-compiler:$daggerVersion"
compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'


// Logging // Logging
implementation 'com.jakewharton.timber:timber:4.7.1' implementation 'com.jakewharton.timber:timber:4.7.1'
@ -140,18 +145,16 @@ dependencies {


testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation 'org.robolectric:robolectric:4.0.2' testImplementation 'org.robolectric:robolectric:4.0.2'
testImplementation "org.koin:koin-test:$koin_version"
//testImplementation 'org.robolectric:shadows-support-v4:3.0' //testImplementation 'org.robolectric:shadows-support-v4:3.0'
testImplementation "io.mockk:mockk:1.8.13.kotlin13" testImplementation "io.mockk:mockk:1.8.13.kotlin13"
testImplementation 'org.amshove.kluent:kluent-android:1.44' testImplementation 'org.amshove.kluent:kluent-android:1.44'
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"


androidTestImplementation "org.koin:koin-test:$koin_version" androidTestImplementation 'androidx.test:core:1.2.0'
androidTestImplementation 'androidx.test:core:1.1.0' androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:rules:1.2.0'
androidTestImplementation 'androidx.test:rules:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
androidTestImplementation 'org.amshove.kluent:kluent-android:1.44' androidTestImplementation 'org.amshove.kluent:kluent-android:1.44'
androidTestImplementation "io.mockk:mockk-android:1.8.13.kotlin13" androidTestImplementation "io.mockk:mockk-android:1.8.13.kotlin13"
androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version" androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version"

Binary file not shown.

View File

@ -16,10 +16,10 @@


package im.vector.matrix.android; package im.vector.matrix.android;


import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.annotation.Nullable;


import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;

View File

@ -19,4 +19,4 @@ package im.vector.matrix.android
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main


internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main) internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main, Main)

View File

@ -19,36 +19,21 @@ package im.vector.matrix.android.auth
import androidx.test.annotation.UiThreadTest import androidx.test.annotation.UiThreadTest
import androidx.test.rule.GrantPermissionRule import androidx.test.rule.GrantPermissionRule
import androidx.test.runner.AndroidJUnit4 import androidx.test.runner.AndroidJUnit4
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.InstrumentedTest import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.OkReplayRuleChainNoActivity import im.vector.matrix.android.OkReplayRuleChainNoActivity
import im.vector.matrix.android.api.auth.Authenticator import im.vector.matrix.android.api.auth.Authenticator
import im.vector.matrix.android.internal.auth.AuthModule
import im.vector.matrix.android.internal.di.MatrixModule
import im.vector.matrix.android.internal.di.NetworkModule
import okreplay.* import okreplay.*
import org.junit.ClassRule import org.junit.ClassRule
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.koin.standalone.StandAloneContext.loadKoinModules
import org.koin.standalone.inject
import org.koin.test.KoinTest




@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
internal class AuthenticatorTest : InstrumentedTest, KoinTest { internal class AuthenticatorTest : InstrumentedTest {


init { lateinit var authenticator: Authenticator
Monarchy.init(context()) lateinit var okReplayInterceptor: OkReplayInterceptor
val matrixModule = MatrixModule(context()).definition
val networkModule = NetworkModule().definition
val authModule = AuthModule().definition
loadKoinModules(listOf(matrixModule, networkModule, authModule))
}

private val authenticator: Authenticator by inject()
private val okReplayInterceptor: OkReplayInterceptor by inject()


private val okReplayConfig = OkReplayConfig.Builder() private val okReplayConfig = OkReplayConfig.Builder()
.tapeRoot(AndroidTapeRoot( .tapeRoot(AndroidTapeRoot(

View File

@ -0,0 +1,44 @@
/*
* Copyright 2018 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.matrix.android.internal.crypto

import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStore
import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreModule
import io.realm.RealmConfiguration
import kotlin.random.Random

internal class CryptoStoreHelper {

fun createStore(): IMXCryptoStore {
return RealmCryptoStore(
realmConfiguration = RealmConfiguration.Builder()
.name("test.realm")
.modules(RealmCryptoStoreModule())
.build(),
credentials = createCredential())
}

fun createCredential() = Credentials(
userId = "userId_" + Random.nextInt(),
homeServer = "http://matrix.org",
accessToken = "access_token",
refreshToken = null,
deviceId = "deviceId_sample"
)
}

View File

@ -0,0 +1,117 @@
/*
* Copyright 2018 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.matrix.android.internal.crypto

import im.vector.matrix.android.internal.crypto.model.OlmSessionWrapper
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import org.junit.Assert.*
import org.junit.Test
import org.matrix.olm.OlmAccount
import org.matrix.olm.OlmManager
import org.matrix.olm.OlmSession

private const val DUMMY_DEVICE_KEY = "DeviceKey"

class CryptoStoreTest {

private val cryptoStoreHelper = CryptoStoreHelper()

@Test
fun test_metadata_realm_ok() {
val cryptoStore: IMXCryptoStore = cryptoStoreHelper.createStore()

assertFalse(cryptoStore.hasData())

cryptoStore.open()

assertEquals("deviceId_sample", cryptoStore.getDeviceId())

assertTrue(cryptoStore.hasData())

// Cleanup
cryptoStore.close()
cryptoStore.deleteStore()
}

@Test
fun test_lastSessionUsed() {
// Ensure Olm is initialized
OlmManager()

val cryptoStore: IMXCryptoStore = cryptoStoreHelper.createStore()

assertNull(cryptoStore.getLastUsedSessionId(DUMMY_DEVICE_KEY))

val olmAccount1 = OlmAccount().apply {
generateOneTimeKeys(1)
}

val olmSession1 = OlmSession().apply {
initOutboundSession(olmAccount1,
olmAccount1.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY],
olmAccount1.oneTimeKeys()[OlmAccount.JSON_KEY_ONE_TIME_KEY]?.values?.first())
}

val sessionId1 = olmSession1.sessionIdentifier()
val olmSessionWrapper1 = OlmSessionWrapper(olmSession1)

cryptoStore.storeSession(olmSessionWrapper1, DUMMY_DEVICE_KEY)

assertEquals(sessionId1, cryptoStore.getLastUsedSessionId(DUMMY_DEVICE_KEY))

val olmAccount2 = OlmAccount().apply {
generateOneTimeKeys(1)
}

val olmSession2 = OlmSession().apply {
initOutboundSession(olmAccount2,
olmAccount2.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY],
olmAccount2.oneTimeKeys()[OlmAccount.JSON_KEY_ONE_TIME_KEY]?.values?.first())
}

val sessionId2 = olmSession2.sessionIdentifier()
val olmSessionWrapper2 = OlmSessionWrapper(olmSession2)

cryptoStore.storeSession(olmSessionWrapper2, DUMMY_DEVICE_KEY)

// Ensure sessionIds are distinct
assertNotEquals(sessionId1, sessionId2)

// Note: we cannot be sure what will be the result of getLastUsedSessionId() here

olmSessionWrapper2.onMessageReceived()
cryptoStore.storeSession(olmSessionWrapper2, DUMMY_DEVICE_KEY)

// sessionId2 is returned now
assertEquals(sessionId2, cryptoStore.getLastUsedSessionId(DUMMY_DEVICE_KEY))

Thread.sleep(2)

olmSessionWrapper1.onMessageReceived()
cryptoStore.storeSession(olmSessionWrapper1, DUMMY_DEVICE_KEY)

// sessionId1 is returned now
assertEquals(sessionId1, cryptoStore.getLastUsedSessionId(DUMMY_DEVICE_KEY))

// Cleanup
olmSession1.releaseSession()
olmSession2.releaseSession()

olmAccount1.releaseAccount()
olmAccount2.releaseAccount()
}
}

View File

@ -0,0 +1,162 @@
/*
* Copyright 2019 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.matrix.android.internal.util

import androidx.test.ext.junit.runners.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
internal class JsonCanonicalizerTest : InstrumentedTest {

@Test
fun identityTest() {
listOf(
"{}",
"""{"a":true}""",
"""{"a":false}""",
"""{"a":1}""",
"""{"a":1.2}""",
"""{"a":null}""",
"""{"a":[]}""",
"""{"a":["b":"c"]}""",
"""{"a":["c":"b","d":"e"]}""",
"""{"a":["d":"b","c":"e"]}"""
).forEach {
assertEquals(it,
JsonCanonicalizer.canonicalize(it))
}
}

@Test
fun reorderTest() {
assertEquals("""{"a":true,"b":false}""",
JsonCanonicalizer.canonicalize("""{"b":false,"a":true}"""))
}

@Test
fun realSampleTest() {
assertEquals("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX\/FjTRLfySgs65ldYyomm7PIx6U"},"user_id":"@benoitx:matrix.org"}""",
JsonCanonicalizer.canonicalize("""{"algorithms":["m.megolm.v1.aes-sha2","m.olm.v1.curve25519-aes-sha2"],"device_id":"VSCUNFSOUI","user_id":"@benoitx:matrix.org","keys":{"curve25519:VSCUNFSOUI":"utyOjnhiQ73qNhi9HlN0OgWIowe5gthTS8r0r9TcJ3o","ed25519:VSCUNFSOUI":"qNhEt+Yggaajet0hX/FjTRLfySgs65ldYyomm7PIx6U"}}"""))
}

@Test
fun doubleQuoteTest() {
assertEquals("{\"a\":\"\\\"\"}",
JsonCanonicalizer.canonicalize("{\"a\":\"\\\"\"}"))
}



/* ==========================================================================================
* Test from https://matrix.org/docs/spec/appendices.html#examples
* ========================================================================================== */

@Test
fun matrixOrg001Test() {
assertEquals("""{}""",
JsonCanonicalizer.canonicalize("""{}"""))
}


@Test
fun matrixOrg002Test() {
assertEquals("""{"one":1,"two":"Two"}""",
JsonCanonicalizer.canonicalize("""{
"one": 1,
"two": "Two"
}"""))
}


@Test
fun matrixOrg003Test() {
assertEquals("""{"a":"1","b":"2"}""",
JsonCanonicalizer.canonicalize("""{
"b": "2",
"a": "1"
}"""))
}


@Test
fun matrixOrg004Test() {
assertEquals("""{"a":"1","b":"2"}""",
JsonCanonicalizer.canonicalize("""{"b":"2","a":"1"}"""))
}


@Test
fun matrixOrg005Test() {
assertEquals("""{"auth":{"mxid":"@john.doe:example.com","profile":{"display_name":"John Doe","three_pids":[{"address":"john.doe@example.org","medium":"email"},{"address":"123456789","medium":"msisdn"}]},"success":true}}""",
JsonCanonicalizer.canonicalize("""{
"auth": {
"success": true,
"mxid": "@john.doe:example.com",
"profile": {
"display_name": "John Doe",
"three_pids": [
{
"medium": "email",
"address": "john.doe@example.org"
},
{
"medium": "msisdn",
"address": "123456789"
}
]
}
}
}"""))
}


@Test
fun matrixOrg006Test() {
assertEquals("""{"a":"日本語"}""",
JsonCanonicalizer.canonicalize("""{
"a": "日本語"
}"""))
}


@Test
fun matrixOrg007Test() {
assertEquals("""{"日":1,"本":2}""",
JsonCanonicalizer.canonicalize("""{
"本": 2,
"日": 1
}"""))
}


@Test
fun matrixOrg008Test() {
assertEquals("""{"a":"日"}""",
JsonCanonicalizer.canonicalize("{\"a\": \"\u65E5\"}"))
}

@Test
fun matrixOrg009Test() {
assertEquals("""{"a":null}""",
JsonCanonicalizer.canonicalize("""{
"a": null
}"""))
}
}

View File

@ -19,11 +19,7 @@ package im.vector.matrix.android.session.room.timeline
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.InstrumentedTest import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.internal.database.helper.add import im.vector.matrix.android.internal.database.helper.*
import im.vector.matrix.android.internal.database.helper.addAll
import im.vector.matrix.android.internal.database.helper.isUnlinked
import im.vector.matrix.android.internal.database.helper.lastStateIndex
import im.vector.matrix.android.internal.database.helper.merge
import im.vector.matrix.android.internal.database.model.ChunkEntity import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeListOfEvents import im.vector.matrix.android.session.room.timeline.RoomDataHelper.createFakeListOfEvents
@ -59,7 +55,7 @@ internal class ChunkEntityTest : InstrumentedTest {
val chunk: ChunkEntity = realm.createObject() val chunk: ChunkEntity = realm.createObject()
val fakeEvent = createFakeMessageEvent() val fakeEvent = createFakeMessageEvent()
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS) chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.events.size shouldEqual 1 chunk.timelineEvents.size shouldEqual 1
} }
} }


@ -70,7 +66,7 @@ internal class ChunkEntityTest : InstrumentedTest {
val fakeEvent = createFakeMessageEvent() val fakeEvent = createFakeMessageEvent()
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS) chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS) chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.events.size shouldEqual 1 chunk.timelineEvents.size shouldEqual 1
} }
} }


@ -126,7 +122,7 @@ internal class ChunkEntityTest : InstrumentedTest {
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS) chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
chunk1.events.size shouldEqual 60 chunk1.timelineEvents.size shouldEqual 60
} }
} }


@ -142,7 +138,7 @@ internal class ChunkEntityTest : InstrumentedTest {
chunk1.addAll("roomId", eventsForChunk1, PaginationDirection.FORWARDS) chunk1.addAll("roomId", eventsForChunk1, PaginationDirection.FORWARDS)
chunk2.addAll("roomId", eventsForChunk2, PaginationDirection.BACKWARDS) chunk2.addAll("roomId", eventsForChunk2, PaginationDirection.BACKWARDS)
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS) chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
chunk1.events.size shouldEqual 40 chunk1.timelineEvents.size shouldEqual 40
chunk1.isLastForward.shouldBeTrue() chunk1.isLastForward.shouldBeTrue()
} }
} }

View File

@ -16,16 +16,14 @@


package im.vector.matrix.android.session.room.timeline package im.vector.matrix.android.session.room.timeline


import arrow.core.Try
import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEvent
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEventPersistor import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEventPersistor
import kotlin.random.Random import kotlin.random.Random


internal class FakeGetContextOfEventTask(private val tokenChunkEventPersistor: TokenChunkEventPersistor) : GetContextOfEventTask { internal class FakeGetContextOfEventTask constructor(private val tokenChunkEventPersistor: TokenChunkEventPersistor) : GetContextOfEventTask {


override fun execute(params: GetContextOfEventTask.Params): Try<TokenChunkEventPersistor.Result> { override suspend fun execute(params: GetContextOfEventTask.Params): TokenChunkEventPersistor.Result {
val fakeEvents = RoomDataHelper.createFakeListOfEvents(30) val fakeEvents = RoomDataHelper.createFakeListOfEvents(30)
val tokenChunkEvent = FakeTokenChunkEvent( val tokenChunkEvent = FakeTokenChunkEvent(
Random.nextLong(System.currentTimeMillis()).toString(), Random.nextLong(System.currentTimeMillis()).toString(),

View File

@ -16,14 +16,14 @@


package im.vector.matrix.android.session.room.timeline package im.vector.matrix.android.session.room.timeline


import arrow.core.Try
import im.vector.matrix.android.internal.session.room.timeline.PaginationTask import im.vector.matrix.android.internal.session.room.timeline.PaginationTask
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEventPersistor import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEventPersistor
import javax.inject.Inject
import kotlin.random.Random import kotlin.random.Random


internal class FakePaginationTask(private val tokenChunkEventPersistor: TokenChunkEventPersistor) : PaginationTask { internal class FakePaginationTask @Inject constructor(private val tokenChunkEventPersistor: TokenChunkEventPersistor) : PaginationTask {


override fun execute(params: PaginationTask.Params): Try<TokenChunkEventPersistor.Result> { override suspend fun execute(params: PaginationTask.Params): TokenChunkEventPersistor.Result {
val fakeEvents = RoomDataHelper.createFakeListOfEvents(30) val fakeEvents = RoomDataHelper.createFakeListOfEvents(30)
val tokenChunkEvent = FakeTokenChunkEvent(params.from, Random.nextLong(System.currentTimeMillis()).toString(), fakeEvents) val tokenChunkEvent = FakeTokenChunkEvent(params.from, Random.nextLong(System.currentTimeMillis()).toString(), fakeEvents)
return tokenChunkEventPersistor.insertInDb(tokenChunkEvent, params.roomId, params.direction) return tokenChunkEventPersistor.insertInDb(tokenChunkEvent, params.roomId, params.direction)

View File

@ -59,7 +59,7 @@ object RoomDataHelper {
eventId = Random.nextLong().toString(), eventId = Random.nextLong().toString(),
content = content, content = content,
prevContent = prevContent, prevContent = prevContent,
sender = sender, senderId = sender,
stateKey = stateKey stateKey = stateKey
) )
} }

View File

@ -18,24 +18,6 @@ package im.vector.matrix.android.session.room.timeline


import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.InstrumentedTest import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.session.room.timeline.Timeline
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.internal.session.room.EventRelationExtractor
import im.vector.matrix.android.internal.session.room.EventRelationsAggregationUpdater
import im.vector.matrix.android.internal.session.room.members.SenderRoomMemberExtractor
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimeline
import im.vector.matrix.android.internal.session.room.timeline.TimelineEventFactory
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEventPersistor
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.testCoroutineDispatchers
import io.realm.Realm
import io.realm.RealmConfiguration
import org.amshove.kluent.shouldEqual
import org.junit.Before
import org.junit.Test
import timber.log.Timber
import java.util.concurrent.CountDownLatch


internal class TimelineTest : InstrumentedTest { internal class TimelineTest : InstrumentedTest {


@ -45,59 +27,60 @@ internal class TimelineTest : InstrumentedTest {


private lateinit var monarchy: Monarchy private lateinit var monarchy: Monarchy


@Before // @Before
fun setup() { // fun setup() {
Timber.plant(Timber.DebugTree()) // Timber.plant(Timber.DebugTree())
Realm.init(context()) // Realm.init(context())
val testConfiguration = RealmConfiguration.Builder().name("test-realm").build() // val testConfiguration = RealmConfiguration.Builder().name("test-realm")
Realm.deleteRealm(testConfiguration) // .modules(SessionRealmModule()).build()
monarchy = Monarchy.Builder().setRealmConfiguration(testConfiguration).build() //
RoomDataHelper.fakeInitialSync(monarchy, ROOM_ID) // Realm.deleteRealm(testConfiguration)
} // monarchy = Monarchy.Builder().setRealmConfiguration(testConfiguration).build()

// RoomDataHelper.fakeInitialSync(monarchy, ROOM_ID)
private fun createTimeline(initialEventId: String? = null): Timeline { // }
val taskExecutor = TaskExecutor(testCoroutineDispatchers) //
val erau = EventRelationsAggregationUpdater(Credentials("", "", "", null, null)) // private fun createTimeline(initialEventId: String? = null): Timeline {
val tokenChunkEventPersistor = TokenChunkEventPersistor(monarchy, erau) // val taskExecutor = TaskExecutor(testCoroutineDispatchers)
val paginationTask = FakePaginationTask(tokenChunkEventPersistor) // val tokenChunkEventPersistor = TokenChunkEventPersistor(monarchy)
val getContextOfEventTask = FakeGetContextOfEventTask(tokenChunkEventPersistor) // val paginationTask = FakePaginationTask @Inject constructor(tokenChunkEventPersistor)
val roomMemberExtractor = SenderRoomMemberExtractor(ROOM_ID) // val getContextOfEventTask = FakeGetContextOfEventTask @Inject constructor(tokenChunkEventPersistor)
val timelineEventFactory = TimelineEventFactory(roomMemberExtractor, EventRelationExtractor()) // val roomMemberExtractor = SenderRoomMemberExtractor(ROOM_ID)
return DefaultTimeline( // val timelineEventFactory = TimelineEventFactory(roomMemberExtractor, EventRelationExtractor())
ROOM_ID, // return DefaultTimeline(
initialEventId, // ROOM_ID,
monarchy.realmConfiguration, // initialEventId,
taskExecutor, // monarchy.realmConfiguration,
getContextOfEventTask, // taskExecutor,
timelineEventFactory, // getContextOfEventTask,
paginationTask, // timelineEventFactory,
null) // paginationTask,
} // null)

// }
@Test //
fun backPaginate_shouldLoadMoreEvents_whenPaginateIsCalled() { // @Test
val timeline = createTimeline() // fun backPaginate_shouldLoadMoreEvents_whenPaginateIsCalled() {
timeline.start() // val timeline = createTimeline()
val paginationCount = 30 // timeline.start()
var initialLoad = 0 // val paginationCount = 30
val latch = CountDownLatch(2) // var initialLoad = 0
var timelineEvents: List<TimelineEvent> = emptyList() // val latch = CountDownLatch(2)
timeline.listener = object : Timeline.Listener { // var timelineEvents: List<TimelineEvent> = emptyList()
override fun onUpdated(snapshot: List<TimelineEvent>) { // timeline.listener = object : Timeline.Listener {
if (snapshot.isNotEmpty()) { // override fun onUpdated(snapshot: List<TimelineEvent>) {
if (initialLoad == 0) { // if (snapshot.isNotEmpty()) {
initialLoad = snapshot.size // if (initialLoad == 0) {
} // initialLoad = snapshot.size
timelineEvents = snapshot // }
latch.countDown() // timelineEvents = snapshot
timeline.paginate(Timeline.Direction.BACKWARDS, paginationCount) // latch.countDown()
} // timeline.paginate(Timeline.Direction.BACKWARDS, paginationCount)
} // }
} // }
latch.await() // }
timelineEvents.size shouldEqual initialLoad + paginationCount // latch.await()
timeline.dispose() // timelineEvents.size shouldEqual initialLoad + paginationCount
} // timeline.dispose()
// }




} }

View File

@ -17,12 +17,14 @@


package im.vector.matrix.android.internal.network.interceptors package im.vector.matrix.android.internal.network.interceptors


import im.vector.matrix.android.internal.di.MatrixScope
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Response import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import okio.Buffer import okio.Buffer
import java.io.IOException import java.io.IOException
import java.nio.charset.Charset import java.nio.charset.Charset
import javax.inject.Inject


/** /**
* An OkHttp interceptor that logs requests as curl shell commands. They can then * An OkHttp interceptor that logs requests as curl shell commands. They can then
@ -33,7 +35,8 @@ import java.nio.charset.Charset
* information. It should only be used in a controlled manner or in a * information. It should only be used in a controlled manner or in a
* non-production environment. * non-production environment.
*/ */
internal class CurlLoggingInterceptor(private val logger: HttpLoggingInterceptor.Logger = HttpLoggingInterceptor.Logger.DEFAULT) @MatrixScope
internal class CurlLoggingInterceptor @Inject constructor(private val logger: HttpLoggingInterceptor.Logger)
: Interceptor { : Interceptor {


/** /**

View File

@ -1,4 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="im.vector.matrix.android"> package="im.vector.matrix.android">


<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@ -7,9 +8,10 @@


<application> <application>


<provider <provider android:name="androidx.work.impl.WorkManagerInitializer"
android:name=".internal.MatrixInitProvider" android:authorities="${applicationId}.workmanager-init"
android:authorities="im.vector.matrix.android.MatrixInitProvider" /> android:exported="false"
tools:node="remove" />


</application> </application>



View File

@ -18,74 +18,85 @@ package im.vector.matrix.android.api


import android.content.Context import android.content.Context
import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner
import androidx.work.Configuration
import androidx.work.WorkManager
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.BuildConfig
import im.vector.matrix.android.api.auth.Authenticator import im.vector.matrix.android.api.auth.Authenticator
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.internal.SessionManager
import im.vector.matrix.android.api.session.sync.FilterService import im.vector.matrix.android.internal.di.DaggerMatrixComponent
import im.vector.matrix.android.internal.auth.AuthModule
import im.vector.matrix.android.internal.di.MatrixKoinComponent
import im.vector.matrix.android.internal.di.MatrixKoinHolder
import im.vector.matrix.android.internal.di.MatrixModule
import im.vector.matrix.android.internal.di.NetworkModule
import im.vector.matrix.android.internal.network.UserAgentHolder import im.vector.matrix.android.internal.network.UserAgentHolder
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
import org.koin.standalone.inject import org.matrix.olm.OlmManager
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject

data class MatrixConfiguration(
val applicationFlavor: String = "Default-application-flavor"
) {

interface Provider {
fun providesMatrixConfiguration(): MatrixConfiguration
}

}


/** /**
* This is the main entry point to the matrix sdk. * This is the main entry point to the matrix sdk.
* This class is automatically init by a provider.
* To get the singleton instance, use getInstance static method. * To get the singleton instance, use getInstance static method.
*/ */
class Matrix private constructor(context: Context) : MatrixKoinComponent { class Matrix private constructor(context: Context, matrixConfiguration: MatrixConfiguration) {


private val authenticator by inject<Authenticator>() @Inject internal lateinit var authenticator: Authenticator
private val userAgentHolder by inject<UserAgentHolder>() @Inject internal lateinit var userAgentHolder: UserAgentHolder
private val backgroundDetectionObserver by inject<BackgroundDetectionObserver>() @Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver
var currentSession: Session? = null @Inject internal lateinit var olmManager: OlmManager
@Inject internal lateinit var sessionManager: SessionManager


init { init {
Monarchy.init(context) Monarchy.init(context)
val matrixModule = MatrixModule(context).definition DaggerMatrixComponent.factory().create(context).inject(this)
val networkModule = NetworkModule().definition if (context.applicationContext !is Configuration.Provider) {
val authModule = AuthModule().definition WorkManager.initialize(context, Configuration.Builder().build())
MatrixKoinHolder.instance.loadModules(listOf(matrixModule, networkModule, authModule))
ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
authenticator.getLastActiveSession()?.also {
currentSession = it
it.open()
it.setFilter(FilterService.FilterPreset.RiotFilter)
it.startSync()
} }
ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
userAgentHolder.setApplicationFlavor(matrixConfiguration.applicationFlavor)
} }


fun getUserAgent() = userAgentHolder.userAgent

fun authenticator(): Authenticator { fun authenticator(): Authenticator {
return authenticator return authenticator
} }


/**
* Set application flavor, to alter user agent.
*/
fun setApplicationFlavor(flavor: String) {
userAgentHolder.setApplicationFlavor(flavor)
}

fun getUserAgent() = userAgentHolder.userAgent

companion object { companion object {

private lateinit var instance: Matrix private lateinit var instance: Matrix
private val isInit = AtomicBoolean(false) private val isInit = AtomicBoolean(false)


internal fun initialize(context: Context) { fun initialize(context: Context, matrixConfiguration: MatrixConfiguration) {
if (isInit.compareAndSet(false, true)) { if (isInit.compareAndSet(false, true)) {
instance = Matrix(context.applicationContext) instance = Matrix(context.applicationContext, matrixConfiguration)
} }
} }


fun getInstance(): Matrix { fun getInstance(context: Context): Matrix {
if (isInit.compareAndSet(false, true)) {
val appContext = context.applicationContext
if (appContext is MatrixConfiguration.Provider) {
val matrixConfiguration = (appContext as MatrixConfiguration.Provider).providesMatrixConfiguration()
instance = Matrix(appContext, matrixConfiguration)
} else {
throw IllegalStateException("Matrix is not initialized properly." +
" You should call Matrix.initialize or let your application implements MatrixConfiguration.Provider.")
}
}
return instance return instance
} }


fun getSdkVersion(): String {
return BuildConfig.VERSION_NAME + " (" + BuildConfig.GIT_SDK_REVISION + ")"
}
} }


} }

View File

@ -16,8 +16,6 @@


package im.vector.matrix.android.api package im.vector.matrix.android.api


import java.util.*
import java.util.regex.Pattern


/** /**
* This class contains pattern to match the different Matrix ids * This class contains pattern to match the different Matrix ids
@ -25,53 +23,57 @@ import java.util.regex.Pattern
object MatrixPatterns { object MatrixPatterns {


// Note: TLD is not mandatory (localhost, IP address...) // Note: TLD is not mandatory (localhost, IP address...)
private val DOMAIN_REGEX = ":[A-Z0-9.-]+(:[0-9]{2,5})?" private const val DOMAIN_REGEX = ":[A-Z0-9.-]+(:[0-9]{2,5})?"


// regex pattern to find matrix user ids in a string. // regex pattern to find matrix user ids in a string.
// See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids // See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids
private val MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+$DOMAIN_REGEX" private const val MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+$DOMAIN_REGEX"
val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = Pattern.compile(MATRIX_USER_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = MATRIX_USER_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)


// regex pattern to find room ids in a string. // regex pattern to find room ids in a string.
private val MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+$DOMAIN_REGEX" private const val MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+$DOMAIN_REGEX"
val PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = Pattern.compile(MATRIX_ROOM_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) private val PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = MATRIX_ROOM_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)


// regex pattern to find room aliases in a string. // regex pattern to find room aliases in a string.
private val MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+$DOMAIN_REGEX" private const val MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+$DOMAIN_REGEX"
val PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE) private val PATTERN_CONTAIN_MATRIX_ALIAS = MATRIX_ROOM_ALIAS_REGEX.toRegex(RegexOption.IGNORE_CASE)


// regex pattern to find message ids in a string. // regex pattern to find message ids in a string.
private val MATRIX_EVENT_IDENTIFIER_REGEX = "\\$[A-Z0-9]+$DOMAIN_REGEX" private const val MATRIX_EVENT_IDENTIFIER_REGEX = "\\$[A-Z0-9]+$DOMAIN_REGEX"
val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER = Pattern.compile(MATRIX_EVENT_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER = MATRIX_EVENT_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)


// regex pattern to find message ids in a string. // regex pattern to find message ids in a string.
private val MATRIX_EVENT_IDENTIFIER_V3_REGEX = "\\$[A-Z0-9/+]+" private const val MATRIX_EVENT_IDENTIFIER_V3_REGEX = "\\$[A-Z0-9/+]+"
val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 = Pattern.compile(MATRIX_EVENT_IDENTIFIER_V3_REGEX, Pattern.CASE_INSENSITIVE) private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 = MATRIX_EVENT_IDENTIFIER_V3_REGEX.toRegex(RegexOption.IGNORE_CASE)

// Ref: https://matrix.org/docs/spec/rooms/v4#event-ids
private const val MATRIX_EVENT_IDENTIFIER_V4_REGEX = "\\$[A-Z0-9\\-_]+"
private val PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4 = MATRIX_EVENT_IDENTIFIER_V4_REGEX.toRegex(RegexOption.IGNORE_CASE)


// regex pattern to find group ids in a string. // regex pattern to find group ids in a string.
private val MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+$DOMAIN_REGEX" private const val MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+$DOMAIN_REGEX"
val PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = Pattern.compile(MATRIX_GROUP_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE) private val PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = MATRIX_GROUP_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)


// regex pattern to find permalink with message id. // regex pattern to find permalink with message id.
// Android does not support in URL so extract it. // Android does not support in URL so extract it.
private val PERMALINK_BASE_REGEX = "https://matrix\\.to/#/" private const val PERMALINK_BASE_REGEX = "https://matrix\\.to/#/"
private val APP_BASE_REGEX = "https://[A-Z0-9.-]+\\.[A-Z]{2,}/[A-Z]{3,}/#/room/" private const val APP_BASE_REGEX = "https://[A-Z0-9.-]+\\.[A-Z]{2,}/[A-Z]{3,}/#/room/"
val SEP_REGEX = "/" const val SEP_REGEX = "/"


private val LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX private const val LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE) private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = LINK_TO_ROOM_ID_REGEXP.toRegex(RegexOption.IGNORE_CASE)


private val LINK_TO_ROOM_ALIAS_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX private const val LINK_TO_ROOM_ALIAS_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE) private val PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS = LINK_TO_ROOM_ALIAS_REGEXP.toRegex(RegexOption.IGNORE_CASE)


private val LINK_TO_APP_ROOM_ID_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX private const val LINK_TO_APP_ROOM_ID_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_APP_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE) private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID = LINK_TO_APP_ROOM_ID_REGEXP.toRegex(RegexOption.IGNORE_CASE)


private val LINK_TO_APP_ROOM_ALIAS_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX private const val LINK_TO_APP_ROOM_ALIAS_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX
val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_APP_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE) private val PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = LINK_TO_APP_ROOM_ALIAS_REGEXP.toRegex(RegexOption.IGNORE_CASE)


// list of patterns to find some matrix item. // list of patterns to find some matrix item.
val MATRIX_PATTERNS = Arrays.asList( val MATRIX_PATTERNS = listOf(
PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID, PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID,
PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS, PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS,
PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID, PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID,
@ -90,7 +92,7 @@ object MatrixPatterns {
* @return true if the string is a valid user id * @return true if the string is a valid user id
*/ */
fun isUserId(str: String?): Boolean { fun isUserId(str: String?): Boolean {
return str != null && PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER.matcher(str).matches() return str != null && str matches PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER
} }


/** /**
@ -100,7 +102,7 @@ object MatrixPatterns {
* @return true if the string is a valid room Id * @return true if the string is a valid room Id
*/ */
fun isRoomId(str: String?): Boolean { fun isRoomId(str: String?): Boolean {
return str != null && PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER.matcher(str).matches() return str != null && str matches PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER
} }


/** /**
@ -110,7 +112,7 @@ object MatrixPatterns {
* @return true if the string is a valid room alias. * @return true if the string is a valid room alias.
*/ */
fun isRoomAlias(str: String?): Boolean { fun isRoomAlias(str: String?): Boolean {
return str != null && PATTERN_CONTAIN_MATRIX_ALIAS.matcher(str).matches() return str != null && str matches PATTERN_CONTAIN_MATRIX_ALIAS
} }


/** /**
@ -121,7 +123,9 @@ object MatrixPatterns {
*/ */
fun isEventId(str: String?): Boolean { fun isEventId(str: String?): Boolean {
return str != null return str != null
&& (PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER.matcher(str).matches() || PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3.matcher(str).matches()) && (str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER
|| str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3
|| str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4)
} }


/** /**
@ -131,6 +135,25 @@ object MatrixPatterns {
* @return true if the string is a valid group id. * @return true if the string is a valid group id.
*/ */
fun isGroupId(str: String?): Boolean { fun isGroupId(str: String?): Boolean {
return str != null && PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER.matcher(str).matches() return str != null && str matches PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER
} }
}// Cannot be instantiated
/**
* Extract server name from a matrix id
*
* @param matrixId
* @return null if not found or if matrixId is null
*/
fun extractServerNameFromId(matrixId: String?): String? {
if (matrixId == null) {
return null
}

val index = matrixId.indexOf(":")

return if (index == -1) {
null
} else matrixId.substring(index + 1)

}
}

View File

@ -18,6 +18,7 @@ package im.vector.matrix.android.api.auth


import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.api.util.Cancelable


@ -35,19 +36,24 @@ interface Authenticator {
*/ */
fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig, login: String, password: String, callback: MatrixCallback<Session>): Cancelable fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig, login: String, password: String, callback: MatrixCallback<Session>): Cancelable


//TODO remove this method. Shouldn't be managed like that.
/** /**
* Check if there is an active [Session]. * Check if there is an authenticated [Session].
* @return true if there is at least one active session. * @return true if there is at least one active session.
*/ */
fun hasActiveSessions(): Boolean fun hasAuthenticatedSessions(): Boolean


//TODO remove this method. Shouldn't be managed like that.
/** /**
* Get the last active [Session], if there is an active session. * Get the last authenticated [Session], if there is an active session.
* @return the lastActive session if any, or null * @return the last active session if any, or null
*/ */
fun getLastActiveSession(): Session? fun getLastAuthenticatedSession(): Session?



/**
* Get an authenticated session. You should at least call authenticate one time before.
* If you logout, this session will no longer be valid.
*
* @param sessionParams the sessionParams to open with.
* @return the associated session if any, or null
*/
fun getSession(sessionParams: SessionParams): Session?
} }

View File

@ -31,7 +31,7 @@ import okhttp3.TlsVersion
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class HomeServerConnectionConfig( data class HomeServerConnectionConfig(
val homeServerUri: Uri, val homeServerUri: Uri,
val identityServerUri: Uri, val identityServerUri: Uri? = null,
val antiVirusServerUri: Uri? = null, val antiVirusServerUri: Uri? = null,
val allowedFingerprints: MutableList<Fingerprint> = ArrayList(), val allowedFingerprints: MutableList<Fingerprint> = ArrayList(),
val shouldPin: Boolean = false, val shouldPin: Boolean = false,
@ -48,7 +48,7 @@ data class HomeServerConnectionConfig(
class Builder { class Builder {


private lateinit var homeServerUri: Uri private lateinit var homeServerUri: Uri
private lateinit var identityServerUri: Uri private var identityServerUri: Uri? = null
private var antiVirusServerUri: Uri? = null private var antiVirusServerUri: Uri? = null
private val allowedFingerprints: MutableList<Fingerprint> = ArrayList() private val allowedFingerprints: MutableList<Fingerprint> = ArrayList()
private var shouldPin: Boolean = false private var shouldPin: Boolean = false
@ -70,11 +70,11 @@ data class HomeServerConnectionConfig(
if (hsUri.scheme != "http" && hsUri.scheme != "https") { if (hsUri.scheme != "http" && hsUri.scheme != "https") {
throw RuntimeException("Invalid home server URI: " + hsUri) throw RuntimeException("Invalid home server URI: " + hsUri)
} }
// remove trailing / // ensure trailing /
homeServerUri = if (hsUri.toString().endsWith("/")) { homeServerUri = if (!hsUri.toString().endsWith("/")) {
try { try {
val url = hsUri.toString() val url = hsUri.toString()
Uri.parse(url.substring(0, url.length - 1)) Uri.parse("$url/")
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException("Invalid home server URI: $hsUri") throw RuntimeException("Invalid home server URI: $hsUri")
} }
@ -96,11 +96,11 @@ data class HomeServerConnectionConfig(
if (identityServerUri.scheme != "http" && identityServerUri.scheme != "https") { if (identityServerUri.scheme != "http" && identityServerUri.scheme != "https") {
throw RuntimeException("Invalid identity server URI: $identityServerUri") throw RuntimeException("Invalid identity server URI: $identityServerUri")
} }
// remove trailing / // ensure trailing /
if (identityServerUri.toString().endsWith("/")) { if (!identityServerUri.toString().endsWith("/")) {
try { try {
val url = identityServerUri.toString() val url = identityServerUri.toString()
this.identityServerUri = Uri.parse(url.substring(0, url.length - 1)) this.identityServerUri = Uri.parse("$url/")
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException("Invalid identity server URI: $identityServerUri") throw RuntimeException("Invalid identity server URI: $identityServerUri")
} }

View File

@ -0,0 +1,40 @@
/*
* Copyright 2019 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.matrix.android.api.comparators

import im.vector.matrix.android.api.interfaces.DatedObject

object DatedObjectComparators {

/**
* Comparator to sort DatedObjects from the oldest to the latest.
*/
val ascComparator by lazy {
Comparator<DatedObject> { datedObject1, datedObject2 ->
(datedObject1.date - datedObject2.date).toInt()
}
}

/**
* Comparator to sort DatedObjects from the latest to the oldest.
*/
val descComparator by lazy {
Comparator<DatedObject> { datedObject1, datedObject2 ->
(datedObject2.date - datedObject1.date).toInt()
}
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2018 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.matrix.android.api.extensions

import im.vector.matrix.android.api.comparators.DatedObjectComparators
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
import java.util.Collections

/* ==========================================================================================
* MXDeviceInfo
* ========================================================================================== */

fun MXDeviceInfo.getFingerprintHumanReadable() = fingerprint()
?.chunked(4)
?.joinToString(separator = " ")


fun List<DeviceInfo>.sortByLastSeen() {
Collections.sort(this, DatedObjectComparators.descComparator)
}

View File

@ -16,6 +16,8 @@


package im.vector.matrix.android.api.failure package im.vector.matrix.android.api.failure


import im.vector.matrix.android.api.session.crypto.MXCryptoError
import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse
import java.io.IOException import java.io.IOException


/** /**
@ -30,7 +32,13 @@ import java.io.IOException
sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) { sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) {
data class Unknown(val throwable: Throwable? = null) : Failure(throwable) data class Unknown(val throwable: Throwable? = null) : Failure(throwable)
data class NetworkConnection(val ioException: IOException? = null) : Failure(ioException) data class NetworkConnection(val ioException: IOException? = null) : Failure(ioException)
data class ServerError(val error: MatrixError) : Failure(RuntimeException(error.toString())) data class ServerError(val error: MatrixError, val httpCode: Int) : Failure(RuntimeException(error.toString()))
// When server send an error, but it cannot be interpreted as a MatrixError
data class OtherServerError(val errorBody: String, val httpCode: Int) : Failure(RuntimeException(errorBody))

data class RegistrationFlowError(val registrationFlowResponse: RegistrationFlowResponse) : Failure(RuntimeException(registrationFlowResponse.toString()))

data class CryptoError(val error: MXCryptoError) : Failure(error)


abstract class FeatureFailure : Failure() abstract class FeatureFailure : Failure()



View File

@ -26,8 +26,13 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class MatrixError( data class MatrixError(
@Json(name = "errcode") val code: String, @Json(name = "errcode") val code: String,
@Json(name = "error") val message: String @Json(name = "error") val message: String,
) {
@Json(name = "consent_uri") val consentUri: String? = null,
// RESOURCE_LIMIT_EXCEEDED data
@Json(name = "limit_type") val limitType: String? = null,
@Json(name = "admin_contact") val adminUri: String? = null) {



companion object { companion object {
const val FORBIDDEN = "M_FORBIDDEN" const val FORBIDDEN = "M_FORBIDDEN"
@ -54,5 +59,9 @@ data class MatrixError(
const val TOO_LARGE = "M_TOO_LARGE" const val TOO_LARGE = "M_TOO_LARGE"
const val M_CONSENT_NOT_GIVEN = "M_CONSENT_NOT_GIVEN" const val M_CONSENT_NOT_GIVEN = "M_CONSENT_NOT_GIVEN"
const val RESOURCE_LIMIT_EXCEEDED = "M_RESOURCE_LIMIT_EXCEEDED" const val RESOURCE_LIMIT_EXCEEDED = "M_RESOURCE_LIMIT_EXCEEDED"
const val WRONG_ROOM_KEYS_VERSION = "M_WRONG_ROOM_KEYS_VERSION"

// Possible value for "limit_type"
const val LIMIT_TYPE_MAU = "monthly_active_user"
} }
} }

View File

@ -0,0 +1,25 @@
/*
* Copyright 2018 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.matrix.android.api.interfaces

/**
* Can be implemented by any object containing a timestamp.
* This interface can be use to sort such object
*/
interface DatedObject {
val date: Long
}

View File

@ -0,0 +1,28 @@
/*
* Copyright 2019 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.matrix.android.api.listeners

/**
* Interface to send a progress info
*/
interface ProgressListener {
/**
* @param progress from 0 to total by contract
* @param total
*/
fun onProgress(progress: Int, total: Int)
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2019 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.matrix.android.api.listeners

/**
* Interface to send a progress info
*/
interface StepProgressListener {

sealed class Step {
data class ComputingKey(val progress: Int, val total: Int) : Step()
object DownloadingKey : Step()
data class ImportingKey(val progress: Int, val total: Int) : Step()
}

/**
* @param step The current step, containing progress data if available. Else you should consider progress as indeterminate
*/
fun onStepProgress(step: Step)
}

View File

@ -17,9 +17,6 @@
package im.vector.matrix.android.api.permalinks package im.vector.matrix.android.api.permalinks


import android.text.Spannable import android.text.Spannable
import android.text.SpannableString
import android.text.method.LinkMovementMethod
import android.widget.TextView
import im.vector.matrix.android.api.MatrixPatterns import im.vector.matrix.android.api.MatrixPatterns


/** /**
@ -40,15 +37,13 @@ object MatrixLinkify {
} }
val text = spannable.toString() val text = spannable.toString()
var hasMatch = false var hasMatch = false
for (index in MatrixPatterns.MATRIX_PATTERNS.indices) { for (pattern in MatrixPatterns.MATRIX_PATTERNS) {
val pattern = MatrixPatterns.MATRIX_PATTERNS[index] for (match in pattern.findAll(spannable)) {
val matcher = pattern.matcher(spannable)
while (matcher.find()) {
hasMatch = true hasMatch = true
val startPos = matcher.start(0) val startPos = match.range.first
if (startPos == 0 || text[startPos - 1] != '/') { if (startPos == 0 || text[startPos - 1] != '/') {
val endPos = matcher.end(0) val endPos = match.range.last + 1
val url = text.substring(matcher.start(0), matcher.end(0)) val url = text.substring(match.range)
val span = MatrixPermalinkSpan(url, callback) val span = MatrixPermalinkSpan(url, callback)
spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) spannable.setSpan(span, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
} }
@ -57,36 +52,4 @@ object MatrixLinkify {
return hasMatch return hasMatch
} }


fun addLinks(textView: TextView, callback: MatrixPermalinkSpan.Callback?): Boolean {
val text = textView.text
if (text is Spannable) {
if (addLinks(text, callback)) {
addLinkMovementMethod(textView)
return true
}

return false
} else {
val spannableString = SpannableString.valueOf(text)
if (addLinks(spannableString, callback)) {
addLinkMovementMethod(textView)
textView.text = spannableString
return true
}
return false
}
}

/**
* Add linkMovementMethod on textview if not already set
* @param textView the textView on which the movementMethod is set
*/
fun addLinkMovementMethod(textView: TextView) {
val movementMethod = textView.movementMethod
if (movementMethod == null || movementMethod !is LinkMovementMethod) {
if (textView.linksClickable) {
textView.movementMethod = LinkMovementMethod.getInstance()
}
}
}
} }

View File

@ -18,6 +18,7 @@ package im.vector.matrix.android.api.permalinks


import android.text.style.ClickableSpan import android.text.style.ClickableSpan
import android.view.View import android.view.View
import im.vector.matrix.android.api.permalinks.MatrixPermalinkSpan.Callback


/** /**
* This MatrixPermalinkSpan is a clickable span which use a [Callback] to communicate back. * This MatrixPermalinkSpan is a clickable span which use a [Callback] to communicate back.

View File

@ -24,7 +24,7 @@ import im.vector.matrix.android.api.session.events.model.Event
*/ */
object PermalinkFactory { object PermalinkFactory {


private val MATRIX_TO_URL_BASE = "https://matrix.to/#/" const val MATRIX_TO_URL_BASE = "https://matrix.to/#/"


/** /**
* Creates a permalink for an event. * Creates a permalink for an event.

View File

@ -36,12 +36,20 @@ object PermalinkParser {
* Turns an uri to a [PermalinkData] * Turns an uri to a [PermalinkData]
*/ */
fun parse(uri: Uri): PermalinkData { fun parse(uri: Uri): PermalinkData {
if (!uri.toString().startsWith(PermalinkFactory.MATRIX_TO_URL_BASE)) {
return PermalinkData.FallbackLink(uri)
}

val fragment = uri.fragment val fragment = uri.fragment
if (fragment.isNullOrEmpty()) { if (fragment.isNullOrEmpty()) {
return PermalinkData.FallbackLink(uri) return PermalinkData.FallbackLink(uri)
} }

val indexOfQuery = fragment.indexOf("?")
val safeFragment = if (indexOfQuery != -1) fragment.substring(0, indexOfQuery) else fragment

// we are limiting to 2 params // we are limiting to 2 params
val params = fragment val params = safeFragment
.split(MatrixPatterns.SEP_REGEX.toRegex()) .split(MatrixPatterns.SEP_REGEX.toRegex())
.filter { it.isNotEmpty() } .filter { it.isNotEmpty() }
.take(2) .take(2)

View File

@ -0,0 +1,95 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules

import im.vector.matrix.android.api.pushrules.rest.PushRule
import timber.log.Timber


class Action(val type: Type) {

enum class Type(val value: String) {
NOTIFY("notify"),
DONT_NOTIFY("dont_notify"),
COALESCE("coalesce"),
SET_TWEAK("set_tweak");

companion object {

fun safeValueOf(value: String): Type? {
try {
return valueOf(value)
} catch (e: IllegalArgumentException) {
return null
}
}
}
}

var tweak_action: String? = null
var stringValue: String? = null
var boolValue: Boolean? = null

companion object {
fun mapFrom(pushRule: PushRule): List<Action>? {
val actions = ArrayList<Action>()
pushRule.actions.forEach { actionStrOrObj ->
if (actionStrOrObj is String) {
when (actionStrOrObj) {
Action.Type.NOTIFY.value -> Action(Action.Type.NOTIFY)
Action.Type.DONT_NOTIFY.value -> Action(Action.Type.DONT_NOTIFY)
else -> {
Timber.w("Unsupported action type ${actionStrOrObj}")
null
}
}?.let {
actions.add(it)
}
} else if (actionStrOrObj is Map<*, *>) {
val tweakAction = actionStrOrObj["set_tweak"] as? String
when (tweakAction) {
"sound" -> {
(actionStrOrObj["value"] as? String)?.let { stringValue ->
Action(Action.Type.SET_TWEAK).also {
it.tweak_action = "sound"
it.stringValue = stringValue
actions.add(it)
}
}
}
"highlight" -> {
(actionStrOrObj["value"] as? Boolean)?.let { boolValue ->
Action(Action.Type.SET_TWEAK).also {
it.tweak_action = "highlight"
it.boolValue = boolValue
actions.add(it)
}
}
}
else -> {
Timber.w("Unsupported action type ${actionStrOrObj}")
}
}
} else {
Timber.w("Unsupported action type ${actionStrOrObj}")
return null
}
}
return if (actions.isEmpty()) null else actions
}
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules

abstract class Condition(val kind: Kind) {

enum class Kind(val value: String) {
event_match("event_match"),
contains_display_name("contains_display_name"),
room_member_count("room_member_count"),
sender_notification_permission("sender_notification_permission"),
UNRECOGNIZE("");

companion object {

fun fromString(value: String): Kind {
return when (value) {
"event_match" -> event_match
"contains_display_name" -> contains_display_name
"room_member_count" -> room_member_count
"sender_notification_permission" -> sender_notification_permission
else -> UNRECOGNIZE
}
}

}

}

abstract fun isSatisfied(conditionResolver: ConditionResolver): Boolean

open fun technicalDescription(): String {
return "Kind: $kind"
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules

/**
* Acts like a visitor on Conditions.
* This class as all required context needed to evaluate rules
*/
interface ConditionResolver {

fun resolveEventMatchCondition(eventMatchCondition: EventMatchCondition): Boolean
fun resolveRoomMemberCountCondition(roomMemberCountCondition: RoomMemberCountCondition): Boolean
fun resolveSenderNotificationPermissionCondition(senderNotificationPermissionCondition: SenderNotificationPermissionCondition): Boolean
fun resolveContainsDisplayNameCondition(containsDisplayNameCondition: ContainsDisplayNameCondition) : Boolean
}

View File

@ -0,0 +1,79 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules

import android.text.TextUtils
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.message.MessageContent
import timber.log.Timber
import java.util.regex.Pattern

class ContainsDisplayNameCondition : Condition(Kind.contains_display_name) {

override fun isSatisfied(conditionResolver: ConditionResolver): Boolean {
return conditionResolver.resolveContainsDisplayNameCondition(this)
}

override fun technicalDescription(): String {
return "User is mentioned"
}

fun isSatisfied(event: Event, displayName: String): Boolean {
var message = when (event.type) {
EventType.MESSAGE -> {
event.content.toModel<MessageContent>()
}
//TODO the spec says:
// Matches any message whose content is unencrypted and contains the user's current display name
// EventType.ENCRYPTED -> {
// event.root.getClearContent()?.toModel<MessageContent>()
// }
else -> null
} ?: return false

return caseInsensitiveFind(displayName, message.body)
}


companion object {
/**
* Returns whether a string contains an occurrence of another, as a standalone word, regardless of case.
*
* @param subString the string to search for
* @param longString the string to search in
* @return whether a match was found
*/
fun caseInsensitiveFind(subString: String, longString: String): Boolean {
// add sanity checks
if (TextUtils.isEmpty(subString) || TextUtils.isEmpty(longString)) {
return false
}

var res = false

try {
val pattern = Pattern.compile("(\\W|^)" + Pattern.quote(subString) + "(\\W|$)", Pattern.CASE_INSENSITIVE)
res = pattern.matcher(longString).find()
} catch (e: Exception) {
Timber.e(e, "## caseInsensitiveFind() : failed")
}

return res
}
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules

import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.internal.di.MoshiProvider
import timber.log.Timber

class EventMatchCondition(val key: String, val pattern: String) : Condition(Kind.event_match) {

override fun isSatisfied(conditionResolver: ConditionResolver) : Boolean {
return conditionResolver.resolveEventMatchCondition(this)
}

override fun technicalDescription(): String {
return "'$key' Matches '$pattern'"
}


fun isSatisfied(event: Event): Boolean {
//TODO encrypted events?
val rawJson = MoshiProvider.providesMoshi().adapter(Event::class.java).toJsonValue(event) as? Map<*, *>
?: return false
val value = extractField(rawJson, key) ?: return false

//Patterns with no special glob characters should be treated as having asterisks prepended
// and appended when testing the condition.
try {
val modPattern = if (hasSpecialGlobChar(pattern)) simpleGlobToRegExp(pattern) else simpleGlobToRegExp("*$pattern*")
val regex = Regex(modPattern, RegexOption.DOT_MATCHES_ALL)
return regex.containsMatchIn(value)
} catch (e: Throwable) {
//e.g PatternSyntaxException
Timber.e(e, "Failed to evaluate push condition")
return false
}

}


private fun extractField(jsonObject: Map<*, *>, fieldPath: String): String? {
val fieldParts = fieldPath.split(".")
if (fieldParts.isEmpty()) return null

var jsonElement: Map<*, *> = jsonObject
fieldParts.forEachIndexed { index, pathSegment ->
if (index == fieldParts.lastIndex) {
return jsonElement[pathSegment]?.toString()
} else {
val sub = jsonElement[pathSegment] ?: return null
if (sub is Map<*, *>) {
jsonElement = sub
} else {
return null
}
}
}
return null
}

companion object {

private fun hasSpecialGlobChar(glob: String): Boolean {
return glob.contains("*") || glob.contains("?")
}

//Very simple glob to regexp converter
private fun simpleGlobToRegExp(glob: String): String {
var out = ""//"^"
for (i in 0 until glob.length) {
val c = glob[i]
when (c) {
'*' -> out += ".*"
'?' -> out += '.'.toString()
'.' -> out += "\\."
'\\' -> out += "\\\\"
else -> out += c
}
}
out += ""//'$'.toString()
return out
}
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules

import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.util.Cancelable

interface PushRuleService {

/**
* Fetch the push rules from the server
*/
fun fetchPushRules(scope: String = "global")

//TODO get push rule set
fun getPushRules(scope: String = "global"): List<PushRule>

//TODO update rule

fun updatePushRuleEnableStatus(kind: String, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>): Cancelable

fun addPushRuleListener(listener: PushRuleListener)

fun removePushRuleListener(listener: PushRuleListener)

// fun fulfilledBingRule(event: Event, rules: List<PushRule>): PushRule?

interface PushRuleListener {
fun onMatchRule(event: Event, actions: List<Action>)
fun onRoomLeft(roomId: String)
fun batchFinish()
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules

import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.room.RoomService
import timber.log.Timber

private val regex = Regex("^(==|<=|>=|<|>)?(\\d*)$")

class RoomMemberCountCondition(val iz: String) : Condition(Kind.room_member_count) {

override fun isSatisfied(conditionResolver: ConditionResolver): Boolean {
return conditionResolver.resolveRoomMemberCountCondition(this)
}

override fun technicalDescription(): String {
return "Room member count is $iz"
}

fun isSatisfied(event: Event, session: RoomService?): Boolean {
// sanity check^
val roomId = event.roomId ?: return false
val room = session?.getRoom(roomId) ?: return false

// Parse the is field into prefix and number the first time
val (prefix, count) = parseIsField() ?: return false

val numMembers = room.getNumberOfJoinedMembers()

return when (prefix) {
"<" -> numMembers < count
">" -> numMembers > count
"<=" -> numMembers <= count
">=" -> numMembers >= count
else -> numMembers == count
}
}

/**
* Parse the is field to extract meaningful information.
*/
private fun parseIsField(): Pair<String?, Int>? {
try {
val match = regex.find(iz) ?: return null
val (prefix, count) = match.destructured
return prefix to count.toInt()
} catch (t: Throwable) {
Timber.d(t)
}
return null

}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules

/**
* Known rule ids
*
* Ref: https://matrix.org/docs/spec/client_server/latest#predefined-rules
*/
object RuleIds {
// Default Override Rules
const val RULE_ID_DISABLE_ALL = ".m.rule.master"
const val RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS = ".m.rule.suppress_notices"
const val RULE_ID_INVITE_ME = ".m.rule.invite_for_me"
const val RULE_ID_PEOPLE_JOIN_LEAVE = ".m.rule.member_event"
const val RULE_ID_CONTAIN_DISPLAY_NAME = ".m.rule.contains_display_name"

const val RULE_ID_TOMBSTONE = ".m.rule.tombstone"
const val RULE_ID_ROOM_NOTIF = ".m.rule.roomnotif"

// Default Content Rules
const val RULE_ID_CONTAIN_USER_NAME = ".m.rule.contains_user_name"

// Default Underride Rules
const val RULE_ID_CALL = ".m.rule.call"
const val RULE_ID_one_to_one_encrypted_room = ".m.rule.encrypted_room_one_to_one"
const val RULE_ID_ONE_TO_ONE_ROOM = ".m.rule.room_one_to_one"
const val RULE_ID_ALL_OTHER_MESSAGES_ROOMS = ".m.rule.message"
const val RULE_ID_ENCRYPTED = ".m.rule.encrypted"

// Not documented
const val RULE_ID_FALLBACK = ".m.rule.fallback"
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules


enum class RulesetKey(val value: String) {
CONTENT("content"),
OVERRIDE("override"),
ROOM("room"),
SENDER("sender"),
UNDERRIDE("underride"),
UNKNOWN("")
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules

import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.room.model.PowerLevels


class SenderNotificationPermissionCondition(val key: String) : Condition(Kind.sender_notification_permission) {

override fun isSatisfied(conditionResolver: ConditionResolver): Boolean {
return conditionResolver.resolveSenderNotificationPermissionCondition(this)
}

override fun technicalDescription(): String {
return "User power level <$key>"
}


fun isSatisfied(event: Event, powerLevels: PowerLevels): Boolean {
return event.senderId != null && powerLevels.getUserPowerLevel(event.senderId) >= powerLevels.notificationLevel(key)
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules.rest

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

/**
* All push rulesets for a user.
*/
@JsonClass(generateAdapter = true)
data class GetPushRulesResponse(
/**
* Global rules, account level applying to all devices
*/
@Json(name = "global")
val global: Ruleset,

/**
* Device specific rules, apply only to current device
*/
@Json(name = "device")
val device: Ruleset? = null
)

View File

@ -0,0 +1,79 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules.rest

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.pushrules.*
import timber.log.Timber

@JsonClass(generateAdapter = true)
data class PushCondition(
/**
* Required. The kind of condition to apply.
*/
val kind: String,

/**
* Required for event_match conditions. The dot- separated field of the event to match.
*/

val key: String? = null,
/**
*Required for event_match conditions.
*/

val pattern: String? = null,
/**
* Required for room_member_count conditions.
* A decimal integer optionally prefixed by one of, ==, <, >, >= or <=.
* A prefix of < matches rooms where the member count is strictly less than the given number and so forth.
* If no prefix is present, this parameter defaults to ==.
*/
@Json(name = "is") val iz: String? = null
) {

fun asExecutableCondition(): Condition? {
return when (Condition.Kind.fromString(this.kind)) {
Condition.Kind.event_match -> {
if (this.key != null && this.pattern != null) {
EventMatchCondition(key, pattern)
} else {
Timber.e("Malformed Event match condition")
null
}
}
Condition.Kind.contains_display_name -> {
ContainsDisplayNameCondition()
}
Condition.Kind.room_member_count -> {
if (this.iz.isNullOrBlank()) {
Timber.e("Malformed ROOM_MEMBER_COUNT condition")
null
} else {
RoomMemberCountCondition(this.iz)
}
}
Condition.Kind.sender_notification_permission -> {
this.key?.let { SenderNotificationPermissionCondition(it) }
}
Condition.Kind.UNRECOGNIZE -> {
Timber.e("Unknwon kind $kind")
null
}
}
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules.rest

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass


@JsonClass(generateAdapter = true)
data class PushRule(
/**
* Required. The actions to perform when this rule is matched.
*/
val actions: List<Any>,
/**
* Required. Whether this is a default rule, or has been set explicitly.
*/
val default: Boolean? = false,
/**
* Required. Whether the push rule is enabled or not.
*/
val enabled: Boolean,
/**
* Required. The ID of this rule.
*/
@Json(name = "rule_id") val ruleId: String,
/**
* The conditions that must hold true for an event in order for a rule to be applied to an event
*/
val conditions: List<PushCondition>? = null,
/**
* The glob-style pattern to match against. Only applicable to content rules.
*/
val pattern: String? = null
)

View File

@ -0,0 +1,27 @@
/*
* Copyright 2019 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.matrix.android.api.pushrules.rest

import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class Ruleset(
val content: List<PushRule>? = null,
val override: List<PushRule>? = null,
val room: List<PushRule>? = null,
val sender: List<PushRule>? = null,
val underride: List<PushRule>? = null
)

View File

@ -0,0 +1,29 @@
/*
* Copyright 2019 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.matrix.android.api.session

import androidx.annotation.StringRes
import androidx.lifecycle.LiveData

interface InitialSyncProgressService {

fun getInitialSyncProgressStatus() : LiveData<Status?>

data class Status(
@StringRes val statusText: Int,
val percentProgress: Int = 0
)
}

View File

@ -17,15 +17,21 @@
package im.vector.matrix.android.api.session package im.vector.matrix.android.api.session


import androidx.annotation.MainThread import androidx.annotation.MainThread
import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.pushrules.PushRuleService
import im.vector.matrix.android.api.session.cache.CacheService import im.vector.matrix.android.api.session.cache.CacheService
import im.vector.matrix.android.api.session.content.ContentUploadStateTracker import im.vector.matrix.android.api.session.content.ContentUploadStateTracker
import im.vector.matrix.android.api.session.content.ContentUrlResolver import im.vector.matrix.android.api.session.content.ContentUrlResolver
import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.crypto.CryptoService
import im.vector.matrix.android.api.session.file.FileService
import im.vector.matrix.android.api.session.group.GroupService import im.vector.matrix.android.api.session.group.GroupService
import im.vector.matrix.android.api.session.pushers.PushersService
import im.vector.matrix.android.api.session.room.RoomDirectoryService
import im.vector.matrix.android.api.session.room.RoomService import im.vector.matrix.android.api.session.room.RoomService
import im.vector.matrix.android.api.session.signout.SignOutService import im.vector.matrix.android.api.session.signout.SignOutService
import im.vector.matrix.android.api.session.sync.FilterService import im.vector.matrix.android.api.session.sync.FilterService
import im.vector.matrix.android.api.session.sync.SyncState
import im.vector.matrix.android.api.session.user.UserService import im.vector.matrix.android.api.session.user.UserService


/** /**
@ -34,40 +40,69 @@ import im.vector.matrix.android.api.session.user.UserService
*/ */
interface Session : interface Session :
RoomService, RoomService,
RoomDirectoryService,
GroupService, GroupService,
UserService, UserService,
CryptoService, CryptoService,
CacheService, CacheService,
SignOutService, SignOutService,
FilterService { FilterService,
FileService,
PushRuleService,
PushersService,
InitialSyncProgressService {


/** /**
* The params associated to the session * The params associated to the session
*/ */
val sessionParams: SessionParams val sessionParams: SessionParams


/**
* Useful shortcut to get access to the userId
*/
val myUserId: String
get() = sessionParams.credentials.userId


/** /**
* This method allow to open a session. It does start some service on the background. * This method allow to open a session. It does start some service on the background.
*/ */
@MainThread @MainThread
fun open() fun open()


/**
* Requires a one time background sync
*/
fun requireBackgroundSync()

/**
* Launches infinite periodic background syncs
* THis does not work in doze mode :/
* If battery optimization is on it can work in app standby but that's all :/
*/
fun startAutomaticBackgroundSync(repeatDelay: Long = 30_000L)

fun stopAnyBackgroundSync()

/** /**
* This method start the sync thread. * This method start the sync thread.
*/ */
@MainThread fun startSync(fromForeground : Boolean)
fun startSync()


/** /**
* This method stop the sync thread. * This method stop the sync thread.
*/ */
@MainThread
fun stopSync() fun stopSync()


/**
* This method allows to listen the sync state.
* @return a [LiveData] of [SyncState].
*/
fun syncState(): LiveData<SyncState>

/** /**
* This method allow to close a session. It does stop some services. * This method allow to close a session. It does stop some services.
*/ */
@MainThread
fun close() fun close()


/** /**
@ -100,6 +135,7 @@ interface Session :
* The access token is not valid anymore * The access token is not valid anymore
*/ */
fun onInvalidToken() fun onInvalidToken()

} }


} }

View File

@ -22,22 +22,17 @@ interface ContentUploadStateTracker {


fun untrack(key: String, updateListener: UpdateListener) fun untrack(key: String, updateListener: UpdateListener)


fun setFailure(key: String)

fun setSuccess(key: String)

fun setProgress(key: String, current: Long, total: Long)

interface UpdateListener { interface UpdateListener {
fun onUpdate(state: State) fun onUpdate(state: State)
} }


sealed class State { sealed class State {
object Idle : State() object Idle : State()
data class ProgressData(val current: Long, val total: Long) : State() object EncryptingThumbnail : State()
data class UploadingThumbnail(val current: Long, val total: Long) : State()
object Encrypting : State()
data class Uploading(val current: Long, val total: Long) : State()
object Success : State() object Success : State()
object Failure : State() data class Failure(val throwable: Throwable) : State()
} }


} }

View File

@ -16,8 +16,103 @@


package im.vector.matrix.android.api.session.crypto package im.vector.matrix.android.api.session.crypto


import android.content.Context
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.listeners.ProgressListener
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService
import im.vector.matrix.android.api.session.crypto.keyshare.RoomKeysRequestListener
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService
import im.vector.matrix.android.api.session.events.model.Content
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.crypto.NewSessionListener
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXEncryptEventContentResult
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody

interface CryptoService { interface CryptoService {


// Not supported for the moment fun setDeviceName(deviceId: String, deviceName: String, callback: MatrixCallback<Unit>)
fun isCryptoEnabled() = false
fun deleteDevice(deviceId: String, callback: MatrixCallback<Unit>)

fun deleteDeviceWithUserPassword(deviceId: String, authSession: String?, password: String, callback: MatrixCallback<Unit>)

fun getCryptoVersion(context: Context, longFormat: Boolean): String

fun isCryptoEnabled(): Boolean

fun getSasVerificationService(): SasVerificationService

fun getKeysBackupService(): KeysBackupService

fun isRoomBlacklistUnverifiedDevices(roomId: String?): Boolean

fun setWarnOnUnknownDevices(warn: Boolean)

fun setDeviceVerification(verificationStatus: Int, deviceId: String, userId: String)

fun getUserDevices(userId: String): MutableList<MXDeviceInfo>

fun setDevicesKnown(devices: List<MXDeviceInfo>, callback: MatrixCallback<Unit>?)

fun deviceWithIdentityKey(senderKey: String, algorithm: String): MXDeviceInfo?

fun getMyDevice(): MXDeviceInfo

fun getGlobalBlacklistUnverifiedDevices(): Boolean

fun setGlobalBlacklistUnverifiedDevices(block: Boolean)

fun setRoomUnBlacklistUnverifiedDevices(roomId: String)

fun getDeviceTrackingStatus(userId: String): Int

fun importRoomKeys(roomKeysAsArray: ByteArray, password: String, progressListener: ProgressListener?, callback: MatrixCallback<ImportRoomKeysResult>)

fun exportRoomKeys(password: String, callback: MatrixCallback<ByteArray>)

fun setRoomBlacklistUnverifiedDevices(roomId: String)

fun getDeviceInfo(userId: String, deviceId: String?): MXDeviceInfo?

fun reRequestRoomKeyForEvent(event: Event)

fun cancelRoomKeyRequest(requestBody: RoomKeyRequestBody)

fun addRoomKeysRequestListener(listener: RoomKeysRequestListener)

fun removeRoomKeysRequestListener(listener: RoomKeysRequestListener)

fun getDevicesList(callback: MatrixCallback<DevicesListResponse>)

fun inboundGroupSessionsCount(onlyBackedUp: Boolean): Int

fun isRoomEncrypted(roomId: String): Boolean

fun encryptEventContent(eventContent: Content,
eventType: String,
roomId: String,
callback: MatrixCallback<MXEncryptEventContentResult>)

@Throws(MXCryptoError::class)
fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult

fun decryptEventAsync(event: Event, timeline: String, callback: MatrixCallback<MXEventDecryptionResult>)

fun getEncryptionAlgorithm(roomId: String): String?

fun shouldEncryptForInvitedMembers(roomId: String): Boolean

fun downloadKeys(userIds: List<String>, forceDownload: Boolean, callback: MatrixCallback<MXUsersDevicesMap<MXDeviceInfo>>)

fun clearCryptoCache(callback: MatrixCallback<Unit>)

fun addNewSessionListener(newSessionListener: NewSessionListener)

fun removeSessionListener(listener: NewSessionListener)

} }

View File

@ -0,0 +1,93 @@
/*
* Copyright 2016 OpenMarket Ltd
* Copyright 2017 Vector Creations Ltd
* Copyright 2018 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.matrix.android.api.session.crypto

import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import org.matrix.olm.OlmException

/**
* Represents a crypto error response.
*/
sealed class MXCryptoError : Throwable() {

data class Base(val errorType: ErrorType,
val technicalMessage: String,
/**
* Describe the error with more details
*/
val detailedErrorDescription: String? = null) : MXCryptoError()

data class OlmError(val olmException: OlmException) : MXCryptoError()

data class UnknownDevice(val deviceList: MXUsersDevicesMap<MXDeviceInfo>) : MXCryptoError()

enum class ErrorType {
ENCRYPTING_NOT_ENABLED,
UNABLE_TO_ENCRYPT,
UNABLE_TO_DECRYPT,
UNKNOWN_INBOUND_SESSION_ID,
INBOUND_SESSION_MISMATCH_ROOM_ID,
MISSING_FIELDS,
BAD_EVENT_FORMAT,
MISSING_SENDER_KEY,
MISSING_CIPHER_TEXT,
BAD_DECRYPTED_FORMAT,
NOT_INCLUDE_IN_RECIPIENTS,
BAD_RECIPIENT,
BAD_RECIPIENT_KEY,
FORWARDED_MESSAGE,
BAD_ROOM,
BAD_ENCRYPTED_MESSAGE,
DUPLICATED_MESSAGE_INDEX,
MISSING_PROPERTY,
OLM,
UNKNOWN_DEVICES,
UNKNOWN_MESSAGE_INDEX
}

companion object {
/**
* Resource for technicalMessage
*/
const val UNABLE_TO_ENCRYPT_REASON = "Unable to encrypt %s"
const val UNABLE_TO_DECRYPT_REASON = "Unable to decrypt %1\$s. Algorithm: %2\$s"
const val OLM_REASON = "OLM error: %1\$s"
const val DETAILED_OLM_REASON = "Unable to decrypt %1\$s. OLM error: %2\$s"
const val UNKNOWN_INBOUND_SESSION_ID_REASON = "Unknown inbound session id"
const val INBOUND_SESSION_MISMATCH_ROOM_ID_REASON = "Mismatched room_id for inbound group session (expected %1\$s, was %2\$s)"
const val MISSING_FIELDS_REASON = "Missing fields in input"
const val BAD_EVENT_FORMAT_TEXT_REASON = "Bad event format"
const val MISSING_SENDER_KEY_TEXT_REASON = "Missing senderKey"
const val MISSING_CIPHER_TEXT_REASON = "Missing ciphertext"
const val BAD_DECRYPTED_FORMAT_TEXT_REASON = "Bad decrypted event format"
const val NOT_INCLUDED_IN_RECIPIENT_REASON = "Not included in recipients"
const val BAD_RECIPIENT_REASON = "Message was intended for %1\$s"
const val BAD_RECIPIENT_KEY_REASON = "Message not intended for this device"
const val FORWARDED_MESSAGE_REASON = "Message forwarded from %1\$s"
const val BAD_ROOM_REASON = "Message intended for room %1\$s"
const val BAD_ENCRYPTED_MESSAGE_REASON = "Bad Encrypted Message"
const val DUPLICATE_MESSAGE_INDEX_REASON = "Duplicate message index, possible replay attack %1\$s"
const val ERROR_MISSING_PROPERTY_REASON = "No '%1\$s' property. Cannot prevent unknown-key attack"
const val UNKNOWN_DEVICES_REASON = "This room contains unknown devices which have not been verified.\n" +
"We strongly recommend you verify them before continuing."
const val NO_MORE_ALGORITHM_REASON = "Room was previously configured to use encryption, but is no longer." +
" Perhaps the homeserver is hiding the configuration event."
}
}

View File

@ -0,0 +1,214 @@
/*
* Copyright 2019 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.matrix.android.api.session.crypto.keysbackup

import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.listeners.ProgressListener
import im.vector.matrix.android.api.listeners.StepProgressListener
import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrust
import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCreationInfo
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult

interface KeysBackupService {
/**
* Retrieve the current version of the backup from the home server
*
* It can be different than keysBackupVersion.
* @param callback onSuccess(null) will be called if there is no backup on the server
*/
fun getCurrentVersion(callback: MatrixCallback<KeysVersionResult?>)

/**
* Create a new keys backup version and enable it, using the information return from [prepareKeysBackupVersion].
*
* @param keysBackupCreationInfo the info object from [prepareKeysBackupVersion].
* @param callback Asynchronous callback
*/
fun createKeysBackupVersion(keysBackupCreationInfo: MegolmBackupCreationInfo,
callback: MatrixCallback<KeysVersion>)

/**
* Facility method to get the total number of locally stored keys
*/
fun getTotalNumbersOfKeys(): Int

/**
* Facility method to get the number of backed up keys
*/
fun getTotalNumbersOfBackedUpKeys(): Int

/**
* Start to back up keys immediately.
*
* @param progressListener the callback to follow the progress
* @param callback the main callback
*/
fun backupAllGroupSessions(progressListener: ProgressListener?,
callback: MatrixCallback<Unit>?)

/**
* Check trust on a key backup version.
*
* @param keysBackupVersion the backup version to check.
* @param callback block called when the operations completes.
*/
fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult,
callback: MatrixCallback<KeysBackupVersionTrust>)

/**
* Return the current progress of the backup
*/
fun getBackupProgress(progressListener: ProgressListener)

/**
* Get information about a backup version defined on the homeserver.
*
* It can be different than keysBackupVersion.
* @param version the backup version
* @param callback
*/
fun getVersion(version: String,
callback: MatrixCallback<KeysVersionResult?>)

/**
* This method fetches the last backup version on the server, then compare to the currently backup version use.
* If versions are not the same, the current backup is deleted (on server or locally), then the backup may be started again, using the last version.
*
* @param callback true if backup is already using the last version, and false if it is not the case
*/
fun forceUsingLastVersion(callback: MatrixCallback<Boolean>)

/**
* Check the server for an active key backup.
*
* If one is present and has a valid signature from one of the user's verified
* devices, start backing up to it.
*/
fun checkAndStartKeysBackup()

fun addListener(listener: KeysBackupStateListener)

fun removeListener(listener: KeysBackupStateListener)

/**
* Set up the data required to create a new backup version.
* The backup version will not be created and enabled until [createKeysBackupVersion]
* is called.
* The returned [MegolmBackupCreationInfo] object has a `recoveryKey` member with
* the user-facing recovery key string.
*
* @param password an optional passphrase string that can be entered by the user
* when restoring the backup as an alternative to entering the recovery key.
* @param progressListener a progress listener, as generating private key from password may take a while
* @param callback Asynchronous callback
*/
fun prepareKeysBackupVersion(password: String?,
progressListener: ProgressListener?,
callback: MatrixCallback<MegolmBackupCreationInfo>)

/**
* Delete a keys backup version. It will delete all backed up keys on the server, and the backup itself.
* If we are backing up to this version. Backup will be stopped.
*
* @param version the backup version to delete.
* @param callback Asynchronous callback
*/
fun deleteBackup(version: String,
callback: MatrixCallback<Unit>?)

/**
* Ask if the backup on the server contains keys that we may do not have locally.
* This should be called when entering in the state READY_TO_BACKUP
*/
fun canRestoreKeys(): Boolean

/**
* Set trust on a keys backup version.
* It adds (or removes) the signature of the current device to the authentication part of the keys backup version.
*
* @param keysBackupVersion the backup version to check.
* @param trust the trust to set to the keys backup.
* @param callback block called when the operations completes.
*/
fun trustKeysBackupVersion(keysBackupVersion: KeysVersionResult,
trust: Boolean,
callback: MatrixCallback<Unit>)

/**
* Set trust on a keys backup version.
*
* @param keysBackupVersion the backup version to check.
* @param recoveryKey the recovery key to challenge with the key backup public key.
* @param callback block called when the operations completes.
*/
fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult,
recoveryKey: String,
callback: MatrixCallback<Unit>)

/**
* Set trust on a keys backup version.
*
* @param keysBackupVersion the backup version to check.
* @param password the pass phrase to challenge with the keyBackupVersion public key.
* @param callback block called when the operations completes.
*/
fun trustKeysBackupVersionWithPassphrase(keysBackupVersion: KeysVersionResult,
password: String,
callback: MatrixCallback<Unit>)

/**
* Restore a backup with a recovery key from a given backup version stored on the homeserver.
*
* @param keysVersionResult the backup version to restore from.
* @param recoveryKey the recovery key to decrypt the retrieved backup.
* @param roomId the id of the room to get backup data from.
* @param sessionId the id of the session to restore.
* @param stepProgressListener the step progress listener
* @param callback Callback. It provides the number of found keys and the number of successfully imported keys.
*/
fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult,
recoveryKey: String, roomId: String?,
sessionId: String?,
stepProgressListener: StepProgressListener?,
callback: MatrixCallback<ImportRoomKeysResult>)

/**
* Restore a backup with a password from a given backup version stored on the homeserver.
*
* @param keysBackupVersion the backup version to restore from.
* @param password the password to decrypt the retrieved backup.
* @param roomId the id of the room to get backup data from.
* @param sessionId the id of the session to restore.
* @param stepProgressListener the step progress listener
* @param callback Callback. It provides the number of found keys and the number of successfully imported keys.
*/
fun restoreKeyBackupWithPassword(keysBackupVersion: KeysVersionResult,
password: String,
roomId: String?,
sessionId: String?,
stepProgressListener: StepProgressListener?,
callback: MatrixCallback<ImportRoomKeysResult>)

val keysBackupVersion: KeysVersionResult?
val currentBackupVersion: String?
val isEnabled: Boolean
val isStucked: Boolean
val state: KeysBackupState

}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2019 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.matrix.android.api.session.crypto.keysbackup

/**
* E2e keys backup states.
*
* <pre>
* |
* V deleteKeyBackupVersion (on current backup)
* +----------------------> UNKNOWN <-------------
* | |
* | | checkAndStartKeysBackup (at startup or on new verified device or a new detected backup)
* | V
* | CHECKING BACKUP
* | |
* | Network error |
* +<----------+----------------+-------> DISABLED <----------------------+
* | | | | |
* | | | | createKeysBackupVersion |
* | V | V |
* +<--- WRONG VERSION | ENABLING |
* | ^ | | |
* | | V ok | error |
* | | +------> READY <--------+----------------------------+
* V | | |
* NOT TRUSTED | | | on new key
* | | V
* | | WILL BACK UP (waiting a random duration)
* | | |
* | | |
* | | ok V
* | +----- BACKING UP
* | |
* | Error |
* +<---------------+
* </pre>
*/
enum class KeysBackupState {
// Need to check the current backup version on the homeserver
Unknown,
// Checking if backup is enabled on home server
CheckingBackUpOnHomeserver,
// Backup has been stopped because a new backup version has been detected on the homeserver
WrongBackUpVersion,
// Backup from this device is not enabled
Disabled,
// There is a backup available on the homeserver but it is not trusted.
// It is not trusted because the signature is invalid or the device that created it is not verified
// Use [KeysBackup.getKeysBackupTrust()] to get trust details.
// Consequently, the backup from this device is not enabled.
NotTrusted,
// Backup is being enabled: the backup version is being created on the homeserver
Enabling,
// Backup is enabled and ready to send backup to the homeserver
ReadyToBackUp,
// e2e keys are going to be sent to the homeserver
WillBackUp,
// e2e keys are being sent to the homeserver
BackingUp
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2019 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.matrix.android.api.session.crypto.keysbackup

interface KeysBackupStateListener {

/**
* The keys backup state has changed
* @param newState the new state
*/
fun onStateChange(newState: KeysBackupState)
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2018 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.matrix.android.api.session.crypto.keyshare

import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequest
import im.vector.matrix.android.internal.crypto.IncomingRoomKeyRequestCancellation

/**
* Room keys events listener
*/
interface RoomKeysRequestListener {
/**
* An room key request has been received.
*
* @param request the request
*/
fun onRoomKeyRequest(request: IncomingRoomKeyRequest)

/**
* A room key request cancellation has been received.
*
* @param request the cancellation request
*/
fun onRoomKeyRequestCancellation(request: IncomingRoomKeyRequestCancellation)
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2019 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.matrix.android.api.session.crypto.sas

enum class CancelCode(val value: String, val humanReadable: String) {
User("m.user", "the user cancelled the verification"),
Timeout("m.timeout", "the verification process timed out"),
UnknownTransaction("m.unknown_transaction", "the device does not know about that transaction"),
UnknownMethod("m.unknown_method", "the device cant agree on a key agreement, hash, MAC, or SAS method"),
MismatchedCommitment("m.mismatched_commitment", "the hash commitment did not match"),
MismatchedSas("m.mismatched_sas", "the SAS did not match"),
UnexpectedMessage("m.unexpected_message", "the device received an unexpected message"),
InvalidMessage("m.invalid_message", "an invalid message was received"),
MismatchedKeys("m.key_mismatch", "Key mismatch"),
UserMismatchError("m.user_error", "User mismatch")
}

fun safeValueOf(code: String?): CancelCode {
return CancelCode.values().firstOrNull { code == it.value } ?: CancelCode.User
}

View File

@ -0,0 +1,22 @@
/*
* Copyright 2019 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.matrix.android.api.session.crypto.sas

import androidx.annotation.StringRes

data class EmojiRepresentation(val emoji: String,
@StringRes val nameResId: Int)

View File

@ -0,0 +1,34 @@
/*
* Copyright 2019 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.matrix.android.api.session.crypto.sas

interface IncomingSasVerificationTransaction {
val uxState: UxState

fun performAccept()

enum class UxState {
UNKNOWN,
SHOW_ACCEPT,
WAIT_FOR_KEY_AGREEMENT,
SHOW_SAS,
WAIT_FOR_VERIFICATION,
VERIFIED,
CANCELLED_BY_ME,
CANCELLED_BY_OTHER
}
}

View File

@ -0,0 +1,22 @@
/*
* Copyright 2019 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.matrix.android.api.session.crypto.sas

object SasMode {
const val DECIMAL = "decimal"
const val EMOJI = "emoji"
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2019 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.matrix.android.api.session.crypto.sas

interface OutgoingSasVerificationRequest {
val uxState: UxState

enum class UxState {
UNKNOWN,
WAIT_FOR_START,
WAIT_FOR_KEY_AGREEMENT,
SHOW_SAS,
WAIT_FOR_VERIFICATION,
VERIFIED,
CANCELLED_BY_ME,
CANCELLED_BY_OTHER
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2019 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.matrix.android.api.session.crypto.sas

interface SasVerificationService {
fun addListener(listener: SasVerificationListener)

fun removeListener(listener: SasVerificationListener)

fun markedLocallyAsManuallyVerified(userId: String, deviceID: String)

fun getExistingTransaction(otherUser: String, tid: String): SasVerificationTransaction?

fun beginKeyVerificationSAS(userId: String, deviceID: String): String?

fun beginKeyVerification(method: String, userId: String, deviceID: String): String?

// fun transactionUpdated(tx: SasVerificationTransaction)

interface SasVerificationListener {
fun transactionCreated(tx: SasVerificationTransaction)
fun transactionUpdated(tx: SasVerificationTransaction)
fun markedAsManuallyVerified(userId: String, deviceId: String)
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2019 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.matrix.android.api.session.crypto.sas

interface SasVerificationTransaction {
val state: SasVerificationTxState

val cancelledReason: CancelCode?

val transactionId: String

val otherUserId: String

var otherDeviceId: String?

val isIncoming: Boolean

fun supportsEmoji(): Boolean

fun supportsDecimal(): Boolean

fun getEmojiCodeRepresentation(): List<EmojiRepresentation>

fun getDecimalCodeRepresentation(): String

/**
* User wants to cancel the transaction
*/
fun cancel()

/**
* To be called by the client when the user has verified that
* both short codes do match
*/
fun userHasVerifiedShortCode()
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 2019 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.matrix.android.api.session.crypto.sas

enum class SasVerificationTxState {
None,
// I have started a verification request
SendingStart,
Started,
// Other user/device sent me a request
OnStarted,
// I have accepted a request started by the other user/device
SendingAccept,
Accepted,
// My request has been accepted by the other user/device
OnAccepted,
// I have sent my public key
SendingKey,
KeySent,
// The other user/device has sent me his public key
OnKeyReceived,
// Short code is ready to be displayed
ShortCodeReady,
// I have compared the code and manually said that they match
ShortCodeAccepted,

SendingMac,
MacSent,
Verifying,
Verified,

//Global: The verification has been cancelled (by me or other), see cancelReason for details
Cancelled,
OnCancelled
}

View File

@ -16,22 +16,38 @@


package im.vector.matrix.android.api.session.events.model package im.vector.matrix.android.api.session.events.model


import android.text.TextUtils
import com.squareup.moshi.Json import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass
import com.squareup.moshi.Types import im.vector.matrix.android.api.session.crypto.MXCryptoError
import im.vector.matrix.android.api.session.room.model.message.MessageContent
import im.vector.matrix.android.api.session.room.model.message.MessageType
import im.vector.matrix.android.api.session.room.send.SendState
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.di.MoshiProvider
import java.lang.reflect.ParameterizedType import org.json.JSONObject
import timber.log.Timber


typealias Content = Map<String, @JvmSuppressWildcards Any> typealias Content = JsonDict


/** /**
* This methods is a facility method to map a json content to a model. * This methods is a facility method to map a json content to a model.
*/ */
inline fun <reified T> Content?.toModel(): T? { inline fun <reified T> Content?.toModel(catchError: Boolean = true): T? {
return this?.let { return this?.let {
val moshi = MoshiProvider.providesMoshi() val moshi = MoshiProvider.providesMoshi()
val moshiAdapter = moshi.adapter(T::class.java) val moshiAdapter = moshi.adapter(T::class.java)
return moshiAdapter.fromJsonValue(it) return try {
moshiAdapter.fromJsonValue(it)
} catch (e: Exception) {
if (catchError) {
Timber.e(e, "To model failed : $e")
null
} else {
throw e
}
}
} }
} }


@ -58,23 +74,144 @@ data class Event(
@Json(name = "content") val content: Content? = null, @Json(name = "content") val content: Content? = null,
@Json(name = "prev_content") val prevContent: Content? = null, @Json(name = "prev_content") val prevContent: Content? = null,
@Json(name = "origin_server_ts") val originServerTs: Long? = null, @Json(name = "origin_server_ts") val originServerTs: Long? = null,
@Json(name = "sender") val sender: String? = null, @Json(name = "sender") val senderId: String? = null,
@Json(name = "state_key") val stateKey: String? = null, @Json(name = "state_key") val stateKey: String? = null,
@Json(name = "room_id") val roomId: String? = null, @Json(name = "room_id") val roomId: String? = null,
@Json(name = "unsigned") val unsignedData: UnsignedData? = null, @Json(name = "unsigned") val unsignedData: UnsignedData? = null,
@Json(name = "redacts") val redacts: String? = null @Json(name = "redacts") val redacts: String? = null

) { ) {



@Transient
var mxDecryptionResult: OlmDecryptionResult? = null

@Transient
var mCryptoError: MXCryptoError.ErrorType? = null

@Transient
var sendState: SendState = SendState.UNKNOWN


/** /**
* Check if event is a state event. * Check if event is a state event.
* @return true if event is state event. * @return true if event is state event.
*/ */
fun isStateEvent(): Boolean { fun isStateEvent(): Boolean {
return EventType.isStateEvent(type) return EventType.isStateEvent(getClearType())
} }


companion object { //==============================================================================================================
internal val CONTENT_TYPE: ParameterizedType = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java) // Crypto
//==============================================================================================================

/**
* @return true if this event is encrypted.
*/
fun isEncrypted(): Boolean {
return TextUtils.equals(type, EventType.ENCRYPTED)
}

/**
* @return The curve25519 key that sent this event.
*/
fun getSenderKey(): String? {
return mxDecryptionResult?.senderKey
}

/**
* @return The additional keys the sender of this encrypted event claims to possess.
*/
fun getKeysClaimed(): Map<String, String> {
return mxDecryptionResult?.keysClaimed ?: HashMap()
}

/**
* @return the event type
*/
fun getClearType(): String {
return mxDecryptionResult?.payload?.get("type")?.toString() ?: type
}

/**
* @return the event content
*/
fun getClearContent(): Content? {
return mxDecryptionResult?.payload?.get("content") as? Content ?: content
}

fun toContentStringWithIndent(): String {
val contentMap = toContent()?.toMutableMap() ?: HashMap()
return JSONObject(contentMap).toString(4)
}

fun toClearContentStringWithIndent(): String? {
val contentMap = this.mxDecryptionResult?.payload?.toMutableMap()
val adapter = MoshiProvider.providesMoshi().adapter(Map::class.java)
return contentMap?.let { JSONObject(adapter.toJson(it)).toString(4) }
}

/**
* Tells if the event is redacted
*/
fun isRedacted() = unsignedData?.redactedEvent != null

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as Event

if (type != other.type) return false
if (eventId != other.eventId) return false
if (content != other.content) return false
if (prevContent != other.prevContent) return false
if (originServerTs != other.originServerTs) return false
if (senderId != other.senderId) return false
if (stateKey != other.stateKey) return false
if (roomId != other.roomId) return false
if (unsignedData != other.unsignedData) return false
if (redacts != other.redacts) return false
if (mxDecryptionResult != other.mxDecryptionResult) return false
if (mCryptoError != other.mCryptoError) return false
if (sendState != other.sendState) return false

return true
}

override fun hashCode(): Int {
var result = type.hashCode()
result = 31 * result + (eventId?.hashCode() ?: 0)
result = 31 * result + (content?.hashCode() ?: 0)
result = 31 * result + (prevContent?.hashCode() ?: 0)
result = 31 * result + (originServerTs?.hashCode() ?: 0)
result = 31 * result + (senderId?.hashCode() ?: 0)
result = 31 * result + (stateKey?.hashCode() ?: 0)
result = 31 * result + (roomId?.hashCode() ?: 0)
result = 31 * result + (unsignedData?.hashCode() ?: 0)
result = 31 * result + (redacts?.hashCode() ?: 0)
result = 31 * result + (mxDecryptionResult?.hashCode() ?: 0)
result = 31 * result + (mCryptoError?.hashCode() ?: 0)
result = 31 * result + sendState.hashCode()
return result
}

}


fun Event.isTextMessage(): Boolean {
return getClearType() == EventType.MESSAGE
&& when (getClearContent()?.toModel<MessageContent>()?.type) {
MessageType.MSGTYPE_TEXT,
MessageType.MSGTYPE_EMOTE,
MessageType.MSGTYPE_NOTICE -> true
else -> false
}
}

fun Event.isImageMessage(): Boolean {
return getClearType() == EventType.MESSAGE
&& when (getClearContent()?.toModel<MessageContent>()?.type) {
MessageType.MSGTYPE_IMAGE -> true
else -> false
} }
} }

View File

@ -36,8 +36,6 @@ object EventType {
const val FULLY_READ = "m.fully_read" const val FULLY_READ = "m.fully_read"
const val PLUMBING = "m.room.plumbing" const val PLUMBING = "m.room.plumbing"
const val BOT_OPTIONS = "m.room.bot.options" const val BOT_OPTIONS = "m.room.bot.options"
const val KEY_REQUEST = "m.room_key_request"
const val FORWARDED_ROOM_KEY = "m.forwarded_room_key"
const val PREVIEW_URLS = "org.matrix.room.preview_urls" const val PREVIEW_URLS = "org.matrix.room.preview_urls"


// State Events // State Events
@ -65,11 +63,20 @@ object EventType {
const val CALL_ANSWER = "m.call.answer" const val CALL_ANSWER = "m.call.answer"
const val CALL_HANGUP = "m.call.hangup" const val CALL_HANGUP = "m.call.hangup"


// Key share events
const val ROOM_KEY_REQUEST = "m.room_key_request"
const val FORWARDED_ROOM_KEY = "m.forwarded_room_key"

// Interactive key verification
const val KEY_VERIFICATION_START = "m.key.verification.start"
const val KEY_VERIFICATION_ACCEPT = "m.key.verification.accept"
const val KEY_VERIFICATION_KEY = "m.key.verification.key"
const val KEY_VERIFICATION_MAC = "m.key.verification.mac"
const val KEY_VERIFICATION_CANCEL = "m.key.verification.cancel"

// Relation Events // Relation Events

const val REACTION = "m.reaction" const val REACTION = "m.reaction"



private val STATE_EVENTS = listOf( private val STATE_EVENTS = listOf(
STATE_ROOM_NAME, STATE_ROOM_NAME,
STATE_ROOM_TOPIC, STATE_ROOM_TOPIC,

View File

@ -17,7 +17,7 @@ package im.vector.matrix.android.api.session.events.model




/** /**
* Constants defining known event relation types from Matrix specifications. * Constants defining known event relation types from Matrix specifications
*/ */
object RelationType { object RelationType {


@ -25,7 +25,7 @@ object RelationType {
const val ANNOTATION = "m.annotation" const val ANNOTATION = "m.annotation"
/** Lets you define an event which replaces an existing event.*/ /** Lets you define an event which replaces an existing event.*/
const val REPLACE = "m.replace" const val REPLACE = "m.replace"
/** ets you define an event which references an existing event.*/ /** Lets you define an event which references an existing event.*/
const val REFERENCE = "m.reference" const val REFERENCE = "m.reference"


} }

View File

@ -0,0 +1,52 @@
/*
* Copyright 2019 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.matrix.android.api.session.file

import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt
import java.io.File


/**
* This interface defines methods to get files.
*/
interface FileService {

enum class DownloadMode {
/**
* Download file in external storage
*/
TO_EXPORT,
/**
* Download file in cache
*/
FOR_INTERNAL_USE
}

/**
* Download a file.
* Result will be a decrypted file, stored in the cache folder. id parameter will be used to create a sub folder to avoid name collision.
* You can pass the eventId
*/
fun downloadFile(
downloadMode: DownloadMode,
id: String,
fileName: String,
url: String?,
elementToDecrypt: ElementToDecrypt?,
callback: MatrixCallback<File>)
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2019 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.matrix.android.api.session.pushers

data class Pusher(

val userId: String,

val pushKey: String,
val kind: String,
val appId: String,
val appDisplayName: String?,
val deviceDisplayName: String?,
val profileTag: String? = null,
val lang: String?,
val data: PusherData,

val state: PusherState
)

enum class PusherState {
UNREGISTERED,
REGISTERING,
UNREGISTERING,
REGISTERED,
FAILED_TO_REGISTER
}

data class PusherData(
val url: String? = null,
val format: String? = null
)

View File

@ -0,0 +1,66 @@
/*
* Copyright 2019 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.matrix.android.api.session.pushers

import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.MatrixCallback
import java.util.UUID


interface PushersService {

/**
* Refresh pushers from server state
*/
fun refreshPushers()

/**
* Add a new HTTP pusher.
*
* @param pushkey the pushkey
* @param appId the application id
* @param profileTag the profile tag
* @param lang the language
* @param appDisplayName a human-readable application name
* @param deviceDisplayName a human-readable device name
* @param url the URL that should be used to send notifications
* @param append append the pusher
* @param withEventIdOnly true to limit the push content
*
* @return A work request uuid. Can be used to listen to the status
* (LiveData<WorkInfo> status = workManager.getWorkInfoByIdLiveData(<UUID>))
*/
fun addHttpPusher(pushkey: String,
appId: String,
profileTag: String,
lang: String,
appDisplayName: String,
deviceDisplayName: String,
url: String,
append: Boolean,
withEventIdOnly: Boolean): UUID


fun removeHttpPusher(pushkey: String, appId: String, callback: MatrixCallback<Unit>)

companion object {
const val EVENT_ID_ONLY = "event_id_only"
}

fun livePushers(): LiveData<List<Pusher>>

fun pushers() : List<Pusher>
}

View File

@ -17,9 +17,10 @@
package im.vector.matrix.android.api.session.room package im.vector.matrix.android.api.session.room


import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.session.room.crypto.RoomCryptoService
import im.vector.matrix.android.api.session.room.members.MembershipService import im.vector.matrix.android.api.session.room.members.MembershipService
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.annotation.ReactionService import im.vector.matrix.android.api.session.room.model.relation.RelationService
import im.vector.matrix.android.api.session.room.read.ReadService import im.vector.matrix.android.api.session.room.read.ReadService
import im.vector.matrix.android.api.session.room.send.SendService import im.vector.matrix.android.api.session.room.send.SendService
import im.vector.matrix.android.api.session.room.state.StateService import im.vector.matrix.android.api.session.room.state.StateService
@ -28,7 +29,14 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineService
/** /**
* This interface defines methods to interact within a room. * This interface defines methods to interact within a room.
*/ */
interface Room : TimelineService, SendService, ReadService, MembershipService, StateService , ReactionService{ interface Room :
TimelineService,
SendService,
ReadService,
MembershipService,
StateService,
RelationService,
RoomCryptoService {


/** /**
* The roomId of this room * The roomId of this room
@ -39,6 +47,8 @@ interface Room : TimelineService, SendService, ReadService, MembershipService, S
* A live [RoomSummary] associated with the room * A live [RoomSummary] associated with the room
* You can observe this summary to get dynamic data from this room. * You can observe this summary to get dynamic data from this room.
*/ */
val roomSummary: LiveData<RoomSummary> fun liveRoomSummary(): LiveData<RoomSummary>

fun roomSummary(): RoomSummary?


} }

View File

@ -0,0 +1,46 @@
/*
* Copyright 2019 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.matrix.android.api.session.room

import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsParams
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsResponse
import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol
import im.vector.matrix.android.api.util.Cancelable

/**
* This interface defines methods to get and join public rooms. It's implemented at the session level.
*/
interface RoomDirectoryService {

/**
* Get rooms from directory
*/
fun getPublicRooms(server: String?, publicRoomsParams: PublicRoomsParams, callback: MatrixCallback<PublicRoomsResponse>): Cancelable

/**
* Join a room by id
*/
fun joinRoom(roomId: String, callback: MatrixCallback<Unit>): Cancelable

/**
* Fetches the overall metadata about protocols supported by the homeserver.
* Includes both the available protocols and all fields required for queries against each protocol.
*/
fun getThirdPartyProtocol(callback: MatrixCallback<Map<String, ThirdPartyProtocol>>): Cancelable

}

View File

@ -20,6 +20,7 @@ import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
import im.vector.matrix.android.api.util.Cancelable


/** /**
* This interface defines methods to get rooms. It's implemented at the session level. * This interface defines methods to get rooms. It's implemented at the session level.
@ -27,10 +28,18 @@ import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
interface RoomService { interface RoomService {


/** /**
* Create a room * Create a room asynchronously
*/ */
fun createRoom(createRoomParams: CreateRoomParams, fun createRoom(createRoomParams: CreateRoomParams, callback: MatrixCallback<String>): Cancelable
callback: MatrixCallback<String>)
/**
* Join a room by id
* @param roomId the roomId of the room to join
* @param viaServers the servers to attempt to join the room through. One of the servers must be participating in the room.
*/
fun joinRoom(roomId: String,
viaServers: List<String> = emptyList(),
callback: MatrixCallback<Unit>): Cancelable


/** /**
* Get a room from a roomId * Get a room from a roomId

View File

@ -0,0 +1,26 @@
/*
* Copyright 2019 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.matrix.android.api.session.room.crypto

interface RoomCryptoService {

fun isEncrypted(): Boolean

fun encryptionAlgorithm(): String?

fun shouldEncryptForInvitedMembers(): Boolean
}

View File

@ -14,11 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */


package im.vector.riotredesign.core.epoxy package im.vector.matrix.android.api.session.room.failure


import android.content.Context import im.vector.matrix.android.api.failure.Failure
import android.widget.ProgressBar
import com.airbnb.epoxy.ModelView


@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT) sealed class CreateRoomFailure : Failure.FeatureFailure() {
class LoadingItem(context: Context) : ProgressBar(context)
object CreatedWithTimeout: CreateRoomFailure()

}

View File

@ -0,0 +1,25 @@
/*
* Copyright 2019 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.matrix.android.api.session.room.failure

import im.vector.matrix.android.api.failure.Failure

sealed class JoinRoomFailure : Failure.FeatureFailure() {

object JoinedWithTimeout : JoinRoomFailure()

}

View File

@ -1,19 +1,17 @@
/* /*
* Copyright 2019 New Vector Ltd
* *
* * Copyright 2019 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.
* * Licensed under the Apache License, Version 2.0 (the "License"); * You may obtain a copy of the License at
* * 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.
* *
* 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.matrix.android.api.session.room.members package im.vector.matrix.android.api.session.room.members
@ -32,7 +30,7 @@ interface MembershipService {
* This methods load all room members if it was done yet. * This methods load all room members if it was done yet.
* @return a [Cancelable] * @return a [Cancelable]
*/ */
fun loadRoomMembersIfNeeded(): Cancelable fun loadRoomMembersIfNeeded(matrixCallback: MatrixCallback<Unit>): Cancelable


/** /**
* Return the roomMember with userId or null. * Return the roomMember with userId or null.
@ -49,20 +47,22 @@ interface MembershipService {
*/ */
fun getRoomMemberIdsLive(): LiveData<List<String>> fun getRoomMemberIdsLive(): LiveData<List<String>>


fun getNumberOfJoinedMembers(): Int

/** /**
* Invite a user in the room * Invite a user in the room
*/ */
fun invite(userId: String, callback: MatrixCallback<Unit>) fun invite(userId: String, callback: MatrixCallback<Unit>): Cancelable


/** /**
* Join the room * Join the room, or accept an invitation.
*/ */
fun join(callback: MatrixCallback<Unit>)
fun join(viaServers: List<String> = emptyList(), callback: MatrixCallback<Unit>): Cancelable


/** /**
* Leave the room. * Leave the room, or reject an invitation.
*
*/ */
fun leave(callback: MatrixCallback<Unit>) fun leave(callback: MatrixCallback<Unit>): Cancelable


} }

View File

@ -0,0 +1,26 @@
/*
* Copyright 2019 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.matrix.android.api.session.room.model

import im.vector.matrix.android.api.session.events.model.Content

data class EditAggregatedSummary(
val aggregatedContent: Content? = null,
// The list of the eventIDs used to build the summary (might be out of sync if chunked received from message chunk)
val sourceEvents: List<String>,
val localEchos: List<String>,
val lastEditTs: Long = 0
)

View File

@ -1,7 +1,22 @@
/*
* Copyright 2019 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.matrix.android.api.session.room.model package im.vector.matrix.android.api.session.room.model



data class EventAnnotationsSummary( data class EventAnnotationsSummary(
var eventId: String, var eventId: String,
var reactionsSummary: List<ReactionAggregatedSummary> var reactionsSummary: List<ReactionAggregatedSummary>,
var editSummary: EditAggregatedSummary?
) )

View File

@ -1,3 +1,19 @@
/*
* Copyright 2019 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.matrix.android.api.session.room.model package im.vector.matrix.android.api.session.room.model


data class ReactionAggregatedSummary( data class ReactionAggregatedSummary(
@ -5,5 +21,6 @@ data class ReactionAggregatedSummary(
val count: Int, // 8 val count: Int, // 8
val addedByMe: Boolean, // true val addedByMe: Boolean, // true
val firstTimestamp: Long, // unix timestamp val firstTimestamp: Long, // unix timestamp
val sourceEvents: List<String> val sourceEvents: List<String>,
val localEchoEvents: List<String>
) )

View File

@ -16,8 +16,9 @@


package im.vector.matrix.android.api.session.room.model package im.vector.matrix.android.api.session.room.model


import im.vector.matrix.android.api.session.user.model.User

data class ReadReceipt( data class ReadReceipt(
val userId: String, val user: User,
val eventId: String,
val originServerTs: Long val originServerTs: Long
) )

View File

@ -22,5 +22,5 @@ enum class RoomHistoryVisibility {
@Json(name = "shared") SHARED, @Json(name = "shared") SHARED,
@Json(name = "invited") INVITED, @Json(name = "invited") INVITED,
@Json(name = "joined") JOINED, @Json(name = "joined") JOINED,
@Json(name = "word_readable") WORLD_READABLE @Json(name = "world_readable") WORLD_READABLE
} }

View File

@ -1,19 +1,17 @@
/* /*
* Copyright 2019 New Vector Ltd
* *
* * Copyright 2019 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.
* * Licensed under the Apache License, Version 2.0 (the "License"); * You may obtain a copy of the License at
* * 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.
* *
* 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.matrix.android.api.session.room.model package im.vector.matrix.android.api.session.room.model
@ -23,5 +21,5 @@ import com.squareup.moshi.JsonClass


@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class RoomHistoryVisibilityContent( data class RoomHistoryVisibilityContent(
@Json(name = "history_visibility") val historyVisibility: RoomHistoryVisibility @Json(name = "history_visibility") val historyVisibility: RoomHistoryVisibility? = null
) )

View File

@ -16,8 +16,8 @@


package im.vector.matrix.android.api.session.room.model package im.vector.matrix.android.api.session.room.model


import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.room.model.tag.RoomTag import im.vector.matrix.android.api.session.room.model.tag.RoomTag
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent


/** /**
* This class holds some data of a room. * This class holds some data of a room.
@ -29,10 +29,15 @@ data class RoomSummary(
val topic: String = "", val topic: String = "",
val avatarUrl: String = "", val avatarUrl: String = "",
val isDirect: Boolean = false, val isDirect: Boolean = false,
val lastMessage: Event? = null, val latestEvent: TimelineEvent? = null,
val otherMemberIds: List<String> = emptyList(), val otherMemberIds: List<String> = emptyList(),
val notificationCount: Int = 0, val notificationCount: Int = 0,
val highlightCount: Int = 0, val highlightCount: Int = 0,
val tags: List<RoomTag> = emptyList(), val tags: List<RoomTag> = emptyList(),
val membership: Membership = Membership.NONE val membership: Membership = Membership.NONE,
) val versioningState: VersioningState = VersioningState.NONE
) {

val isVersioned: Boolean
get() = versioningState != VersioningState.NONE
}

View File

@ -0,0 +1,23 @@
/*
* Copyright 2019 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.matrix.android.api.session.room.model

enum class VersioningState {
NONE,
UPGRADED_ROOM_NOT_JOINED,
UPGRADED_ROOM_JOINED
}

View File

@ -1,9 +0,0 @@
package im.vector.matrix.android.api.session.room.model.annotation

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class ReactionContent(
@Json(name = "m.relates_to") val relatesTo: ReactionInfo? = null
)

View File

@ -1,11 +0,0 @@
package im.vector.matrix.android.api.session.room.model.annotation

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class ReactionInfo(
@Json(name = "rel_type") override val type: String,
@Json(name = "event_id") override val eventId: String,
val key: String
) : RelationContent

View File

@ -1,52 +0,0 @@
/*
* Copyright 2019 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.matrix.android.api.session.room.model.annotation

import im.vector.matrix.android.api.util.Cancelable

interface ReactionService {


/**
* Sends a reaction (emoji) to the targetedEvent.
* @param reaction the reaction (preferably emoji)
* @param targetEventId the id of the event being reacted
*/
fun sendReaction(reaction: String, targetEventId: String): Cancelable


/**
* Undo a reaction (emoji) to the targetedEvent.
* @param reaction the reaction (preferably emoji)
* @param targetEventId the id of the event being reacted
* @param myUserId used to know if a reaction event was made by the user
*/
fun undoReaction(reaction: String, targetEventId: String, myUserId: String)//: Cancelable


/**
* Update a quick reaction (toggle).
* If you have reacted with agree and then you click on disagree, this call will delete(redact)
* the disagree and add the agree
* If you click on a reaction that you already reacted with, it will undo it
* @param reaction the reaction (preferably emoji)
* @param oppositeReaction the opposite reaction(preferably emoji)
* @param targetEventId the id of the event being reacted
* @param myUserId used to know if a reaction event was made by the user
*/
fun updateQuickReaction(reaction: String, oppositeReaction: String, targetEventId: String, myUserId: String)

}

View File

@ -1,6 +0,0 @@
package im.vector.matrix.android.api.session.room.model.annotation

interface RelationContent {
val type: String
val eventId: String
}

View File

@ -1,8 +0,0 @@
package im.vector.matrix.android.api.session.room.model.annotation

import com.squareup.moshi.Json

data class RelationDefaultContent(
@Json(name = "rel_type") override val type: String,
@Json(name = "event_id") override val eventId: String
) : RelationContent

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