mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-22 01:15:54 +03:00
Merge branch 'develop' into feature/bca/rust_flavor
This commit is contained in:
commit
c52be1f5b1
43 changed files with 198 additions and 102 deletions
2
.github/workflows/danger.yml
vendored
2
.github/workflows/danger.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
||||||
- name: Danger
|
- name: Danger
|
||||||
uses: danger/danger-js@11.2.0
|
uses: danger/danger-js@11.2.0
|
||||||
with:
|
with:
|
||||||
args: "--dangerfile tools/danger/dangerfile.js"
|
args: "--dangerfile ./tools/danger/dangerfile.js"
|
||||||
env:
|
env:
|
||||||
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||||
# Fallback for forks
|
# Fallback for forks
|
||||||
|
|
2
.github/workflows/quality.yml
vendored
2
.github/workflows/quality.yml
vendored
|
@ -68,7 +68,7 @@ jobs:
|
||||||
if: always()
|
if: always()
|
||||||
uses: danger/danger-js@11.2.0
|
uses: danger/danger-js@11.2.0
|
||||||
with:
|
with:
|
||||||
args: "--dangerfile tools/danger/dangerfile-lint.js"
|
args: "--dangerfile ./tools/danger/dangerfile-lint.js"
|
||||||
env:
|
env:
|
||||||
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||||
# Fallback for forks
|
# Fallback for forks
|
||||||
|
|
16
.github/workflows/triage-labelled.yml
vendored
16
.github/workflows/triage-labelled.yml
vendored
|
@ -89,7 +89,7 @@ jobs:
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc0sUA"
|
PROJECT_ID: "PVT_kwDOAM0swc0sUA"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
add_product_issues:
|
add_product_issues:
|
||||||
|
@ -113,7 +113,7 @@ jobs:
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc4AAg6N"
|
PROJECT_ID: "PVT_kwDOAM0swc4AAg6N"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
delight_issues_to_board:
|
delight_issues_to_board:
|
||||||
|
@ -139,7 +139,7 @@ jobs:
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc1HvQ"
|
PROJECT_ID: "PVT_kwDOAM0swc1HvQ"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
move_voice-message_issues:
|
move_voice-message_issues:
|
||||||
|
@ -164,7 +164,7 @@ jobs:
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc2KCw"
|
PROJECT_ID: "PVT_kwDOAM0swc2KCw"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
move_message_bubbles_issues:
|
move_message_bubbles_issues:
|
||||||
name: A-Message-Bubbles to Message bubbles board
|
name: A-Message-Bubbles to Message bubbles board
|
||||||
|
@ -188,7 +188,7 @@ jobs:
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc3m-g"
|
PROJECT_ID: "PVT_kwDOAM0swc3m-g"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
move_ftue_issues:
|
move_ftue_issues:
|
||||||
|
@ -213,7 +213,7 @@ jobs:
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc4AAqVx"
|
PROJECT_ID: "PVT_kwDOAM0swc4AAqVx"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
move_WTF_issues:
|
move_WTF_issues:
|
||||||
|
@ -238,7 +238,7 @@ jobs:
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc4AArk0"
|
PROJECT_ID: "PVT_kwDOAM0swc4AArk0"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
move_element_x_issues:
|
move_element_x_issues:
|
||||||
|
@ -268,7 +268,7 @@ jobs:
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc4ABTXY"
|
PROJECT_ID: "PVT_kwDOAM0swc4ABTXY"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
ps_features1:
|
ps_features1:
|
||||||
|
|
|
@ -69,7 +69,7 @@ jobs:
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.pull_request.node_id }}
|
contentid: ${{ github.event.pull_request.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc0sUA"
|
PROJECT_ID: "PVT_kwDOAM0swc0sUA"
|
||||||
TEAM: "design"
|
TEAM: "design"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
|
@ -138,6 +138,6 @@ jobs:
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.pull_request.node_id }}
|
contentid: ${{ github.event.pull_request.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc4AAg6N"
|
PROJECT_ID: "PVT_kwDOAM0swc4AAg6N"
|
||||||
TEAM: "product"
|
TEAM: "product"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
1
changelog.d/7643.bugfix
Normal file
1
changelog.d/7643.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
[Notifications] Fixed a bug when push notification was automatically dismissed while app is on background
|
1
changelog.d/7691.bugfix
Normal file
1
changelog.d/7691.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Rich Text Editor: improve performance when entering reply/edit/quote mode.
|
1
changelog.d/7699.bugfix
Normal file
1
changelog.d/7699.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix E2EE set up failure whilst signing in using QR code
|
1
changelog.d/7733.bugfix
Normal file
1
changelog.d/7733.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
[Session manager] Sessions without encryption support should not prompt to verify
|
1
changelog.d/7743.bugfix
Normal file
1
changelog.d/7743.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Verification request is not showing when verify session popup is displayed
|
1
changelog.d/7744.bugfix
Normal file
1
changelog.d/7744.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix crash when inviting by email.
|
1
changelog.d/7751.bugfix
Normal file
1
changelog.d/7751.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Revert usage of stable fields in live location sharing and polls
|
|
@ -27,7 +27,7 @@ def jjwt = "0.11.5"
|
||||||
// the whole commit which set version 0.16.0-SNAPSHOT
|
// the whole commit which set version 0.16.0-SNAPSHOT
|
||||||
def vanniktechEmoji = "0.16.0-SNAPSHOT"
|
def vanniktechEmoji = "0.16.0-SNAPSHOT"
|
||||||
def sentry = "6.9.0"
|
def sentry = "6.9.0"
|
||||||
def fragment = "1.5.4"
|
def fragment = "1.5.5"
|
||||||
// Testing
|
// Testing
|
||||||
def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819
|
def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819
|
||||||
def espresso = "3.4.0"
|
def espresso = "3.4.0"
|
||||||
|
|
|
@ -3315,6 +3315,7 @@
|
||||||
<string name="device_manager_verification_status_detail_current_session_unverified">Verify your current session for enhanced secure messaging.</string>
|
<string name="device_manager_verification_status_detail_current_session_unverified">Verify your current session for enhanced secure messaging.</string>
|
||||||
<string name="device_manager_verification_status_detail_other_session_unverified">Verify or sign out from this session for best security and reliability.</string>
|
<string name="device_manager_verification_status_detail_other_session_unverified">Verify or sign out from this session for best security and reliability.</string>
|
||||||
<string name="device_manager_verification_status_detail_other_session_unknown">Verify your current session to reveal this session\'s verification status.</string>
|
<string name="device_manager_verification_status_detail_other_session_unknown">Verify your current session to reveal this session\'s verification status.</string>
|
||||||
|
<string name="device_manager_verification_status_detail_session_encryption_not_supported">This session doesn\'t support encryption and thus can\'t be verified.</string>
|
||||||
<string name="device_manager_verify_session">Verify Session</string>
|
<string name="device_manager_verify_session">Verify Session</string>
|
||||||
<string name="device_manager_view_details">View Details</string>
|
<string name="device_manager_view_details">View Details</string>
|
||||||
<string name="device_manager_other_sessions_view_all">View All (%1$d)</string>
|
<string name="device_manager_other_sessions_view_all">View All (%1$d)</string>
|
||||||
|
@ -3407,6 +3408,7 @@
|
||||||
<!-- TODO TO BE REMOVED -->
|
<!-- TODO TO BE REMOVED -->
|
||||||
<string name="device_manager_learn_more_sessions_verified" tools:ignore="UnusedResources">Verified sessions have logged in with your credentials and then been verified, either using your secure passphrase or by cross-verifying.\n\nThis means they hold encryption keys for your previous messages, and confirm to other users you are communicating with that these sessions are really you.</string>
|
<string name="device_manager_learn_more_sessions_verified" tools:ignore="UnusedResources">Verified sessions have logged in with your credentials and then been verified, either using your secure passphrase or by cross-verifying.\n\nThis means they hold encryption keys for your previous messages, and confirm to other users you are communicating with that these sessions are really you.</string>
|
||||||
<string name="device_manager_learn_more_sessions_verified_description">Verified sessions are anywhere you are using this account after entering your passphrase or confirming your identity with another verified session.\n\nThis means that you have all the keys needed to unlock your encrypted messages and confirm to other users that you trust this session.</string>
|
<string name="device_manager_learn_more_sessions_verified_description">Verified sessions are anywhere you are using this account after entering your passphrase or confirming your identity with another verified session.\n\nThis means that you have all the keys needed to unlock your encrypted messages and confirm to other users that you trust this session.</string>
|
||||||
|
<string name="device_manager_learn_more_sessions_encryption_not_supported">This session doesn\'t support encryption, so it can\'t be verified.\n\nYou won\'t be able to participate in rooms where encryption is enabled when using this session.\n\nFor best security and privacy, it is recommended to use Matrix clients that support encryption.</string>
|
||||||
<string name="device_manager_learn_more_session_rename_title">Renaming sessions</string>
|
<string name="device_manager_learn_more_session_rename_title">Renaming sessions</string>
|
||||||
<string name="device_manager_learn_more_session_rename">Other users in direct messages and rooms that you join are able to view a full list of your sessions.\n\nThis provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here.</string>
|
<string name="device_manager_learn_more_session_rename">Other users in direct messages and rooms that you join are able to view a full list of your sessions.\n\nThis provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here.</string>
|
||||||
<string name="labs_enable_session_manager_title">Enable new session manager</string>
|
<string name="labs_enable_session_manager_title">Enable new session manager</string>
|
||||||
|
|
|
@ -35,7 +35,10 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_S
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
|
||||||
import org.matrix.android.sdk.api.util.MatrixJsonParser
|
import org.matrix.android.sdk.api.util.MatrixJsonParser
|
||||||
|
import org.matrix.android.sdk.api.util.awaitCallback
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -147,6 +150,14 @@ class Rendezvous(
|
||||||
val deviceKey = crypto.getMyCryptoDevice().fingerprint()
|
val deviceKey = crypto.getMyCryptoDevice().fingerprint()
|
||||||
send(Payload(PayloadType.PROGRESS, outcome = Outcome.SUCCESS, deviceId = deviceId, deviceKey = deviceKey))
|
send(Payload(PayloadType.PROGRESS, outcome = Outcome.SUCCESS, deviceId = deviceId, deviceKey = deviceKey))
|
||||||
|
|
||||||
|
try {
|
||||||
|
// explicitly download keys for ourself rather than racing with initial sync which might not complete in time
|
||||||
|
awaitCallback<MXUsersDevicesMap<CryptoDeviceInfo>> { crypto.downloadKeys(listOf(userId), false, it) }
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
// log as warning and continue as initial sync might still complete
|
||||||
|
Timber.tag(TAG).w(e, "Failed to download keys for self")
|
||||||
|
}
|
||||||
|
|
||||||
// await confirmation of verification
|
// await confirmation of verification
|
||||||
val verificationResponse = receive()
|
val verificationResponse = receive()
|
||||||
if (verificationResponse?.outcome == Outcome.VERIFIED) {
|
if (verificationResponse?.outcome == Outcome.VERIFIED) {
|
||||||
|
|
|
@ -46,7 +46,7 @@ internal class DefaultStartLiveLocationShareTask @Inject constructor(
|
||||||
isLive = true,
|
isLive = true,
|
||||||
unstableTimestampMillis = clock.epochMillis()
|
unstableTimestampMillis = clock.epochMillis()
|
||||||
).toContent()
|
).toContent()
|
||||||
val eventType = EventType.STATE_ROOM_BEACON_INFO.stable
|
val eventType = EventType.STATE_ROOM_BEACON_INFO.unstable
|
||||||
val sendStateTaskParams = SendStateTask.Params(
|
val sendStateTaskParams = SendStateTask.Params(
|
||||||
roomId = params.roomId,
|
roomId = params.roomId,
|
||||||
stateKey = userId,
|
stateKey = userId,
|
||||||
|
|
|
@ -45,7 +45,7 @@ internal class DefaultStopLiveLocationShareTask @Inject constructor(
|
||||||
val sendStateTaskParams = SendStateTask.Params(
|
val sendStateTaskParams = SendStateTask.Params(
|
||||||
roomId = params.roomId,
|
roomId = params.roomId,
|
||||||
stateKey = stateKey,
|
stateKey = stateKey,
|
||||||
eventType = EventType.STATE_ROOM_BEACON_INFO.stable,
|
eventType = EventType.STATE_ROOM_BEACON_INFO.unstable,
|
||||||
body = updatedContent
|
body = updatedContent
|
||||||
)
|
)
|
||||||
return try {
|
return try {
|
||||||
|
|
|
@ -181,7 +181,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
originServerTs = dummyOriginServerTs(),
|
originServerTs = dummyOriginServerTs(),
|
||||||
senderId = userId,
|
senderId = userId,
|
||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.POLL_START.stable,
|
type = EventType.POLL_START.unstable,
|
||||||
content = newContent.toContent().plus(additionalContent.orEmpty())
|
content = newContent.toContent().plus(additionalContent.orEmpty())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
originServerTs = dummyOriginServerTs(),
|
originServerTs = dummyOriginServerTs(),
|
||||||
senderId = userId,
|
senderId = userId,
|
||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.POLL_RESPONSE.stable,
|
type = EventType.POLL_RESPONSE.unstable,
|
||||||
content = content.toContent().plus(additionalContent.orEmpty()),
|
content = content.toContent().plus(additionalContent.orEmpty()),
|
||||||
unsignedData = UnsignedData(age = null, transactionId = localId)
|
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||||
)
|
)
|
||||||
|
@ -226,7 +226,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
originServerTs = dummyOriginServerTs(),
|
originServerTs = dummyOriginServerTs(),
|
||||||
senderId = userId,
|
senderId = userId,
|
||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.POLL_START.stable,
|
type = EventType.POLL_START.unstable,
|
||||||
content = content.toContent().plus(additionalContent.orEmpty()),
|
content = content.toContent().plus(additionalContent.orEmpty()),
|
||||||
unsignedData = UnsignedData(age = null, transactionId = localId)
|
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||||
)
|
)
|
||||||
|
@ -249,7 +249,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
originServerTs = dummyOriginServerTs(),
|
originServerTs = dummyOriginServerTs(),
|
||||||
senderId = userId,
|
senderId = userId,
|
||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.POLL_END.stable,
|
type = EventType.POLL_END.unstable,
|
||||||
content = content.toContent().plus(additionalContent.orEmpty()),
|
content = content.toContent().plus(additionalContent.orEmpty()),
|
||||||
unsignedData = UnsignedData(age = null, transactionId = localId)
|
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||||
)
|
)
|
||||||
|
@ -300,7 +300,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
originServerTs = dummyOriginServerTs(),
|
originServerTs = dummyOriginServerTs(),
|
||||||
senderId = userId,
|
senderId = userId,
|
||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.BEACON_LOCATION_DATA.stable,
|
type = EventType.BEACON_LOCATION_DATA.unstable,
|
||||||
content = content.toContent().plus(additionalContent.orEmpty()),
|
content = content.toContent().plus(additionalContent.orEmpty()),
|
||||||
unsignedData = UnsignedData(age = null, transactionId = localId)
|
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||||
)
|
)
|
||||||
|
|
|
@ -87,7 +87,7 @@ object PollEventsTestData {
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val A_POLL_START_EVENT = Event(
|
internal val A_POLL_START_EVENT = Event(
|
||||||
type = EventType.POLL_START.stable,
|
type = EventType.POLL_START.unstable,
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
originServerTs = 1652435922563,
|
originServerTs = 1652435922563,
|
||||||
senderId = A_USER_ID_1,
|
senderId = A_USER_ID_1,
|
||||||
|
@ -96,7 +96,7 @@ object PollEventsTestData {
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val A_POLL_RESPONSE_EVENT = Event(
|
internal val A_POLL_RESPONSE_EVENT = Event(
|
||||||
type = EventType.POLL_RESPONSE.stable,
|
type = EventType.POLL_RESPONSE.unstable,
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
originServerTs = 1652435922563,
|
originServerTs = 1652435922563,
|
||||||
senderId = A_USER_ID_1,
|
senderId = A_USER_ID_1,
|
||||||
|
@ -105,7 +105,7 @@ object PollEventsTestData {
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val A_POLL_END_EVENT = Event(
|
internal val A_POLL_END_EVENT = Event(
|
||||||
type = EventType.POLL_END.stable,
|
type = EventType.POLL_END.unstable,
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
originServerTs = 1652435922563,
|
originServerTs = 1652435922563,
|
||||||
senderId = A_USER_ID_1,
|
senderId = A_USER_ID_1,
|
||||||
|
|
|
@ -69,7 +69,7 @@ class DefaultGetActiveBeaconInfoForUserTaskTest {
|
||||||
result shouldBeEqualTo currentStateEvent
|
result shouldBeEqualTo currentStateEvent
|
||||||
fakeStateEventDataSource.verifyGetStateEvent(
|
fakeStateEventDataSource.verifyGetStateEvent(
|
||||||
roomId = params.roomId,
|
roomId = params.roomId,
|
||||||
eventType = EventType.STATE_ROOM_BEACON_INFO.stable,
|
eventType = EventType.STATE_ROOM_BEACON_INFO.unstable,
|
||||||
stateKey = QueryStringValue.Equals(A_USER_ID)
|
stateKey = QueryStringValue.Equals(A_USER_ID)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ internal class DefaultStartLiveLocationShareTaskTest {
|
||||||
val expectedParams = SendStateTask.Params(
|
val expectedParams = SendStateTask.Params(
|
||||||
roomId = params.roomId,
|
roomId = params.roomId,
|
||||||
stateKey = A_USER_ID,
|
stateKey = A_USER_ID,
|
||||||
eventType = EventType.STATE_ROOM_BEACON_INFO.stable,
|
eventType = EventType.STATE_ROOM_BEACON_INFO.unstable,
|
||||||
body = expectedBeaconContent
|
body = expectedBeaconContent
|
||||||
)
|
)
|
||||||
fakeSendStateTask.verifyExecuteRetry(
|
fakeSendStateTask.verifyExecuteRetry(
|
||||||
|
|
|
@ -79,7 +79,7 @@ class DefaultStopLiveLocationShareTaskTest {
|
||||||
val expectedSendParams = SendStateTask.Params(
|
val expectedSendParams = SendStateTask.Params(
|
||||||
roomId = params.roomId,
|
roomId = params.roomId,
|
||||||
stateKey = A_USER_ID,
|
stateKey = A_USER_ID,
|
||||||
eventType = EventType.STATE_ROOM_BEACON_INFO.stable,
|
eventType = EventType.STATE_ROOM_BEACON_INFO.unstable,
|
||||||
body = expectedBeaconContent
|
body = expectedBeaconContent
|
||||||
)
|
)
|
||||||
fakeSendStateTask.verifyExecuteRetry(
|
fakeSendStateTask.verifyExecuteRetry(
|
||||||
|
|
|
@ -79,7 +79,7 @@ class LiveLocationShareRedactionEventProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `given a redacted live location share event when processing it then related summaries are deleted from database`() = runTest {
|
fun `given a redacted live location share event when processing it then related summaries are deleted from database`() = runTest {
|
||||||
val event = Event(eventId = AN_EVENT_ID, redacts = A_REDACTED_EVENT_ID)
|
val event = Event(eventId = AN_EVENT_ID, redacts = A_REDACTED_EVENT_ID)
|
||||||
val redactedEventEntity = EventEntity(eventId = A_REDACTED_EVENT_ID, type = EventType.STATE_ROOM_BEACON_INFO.stable)
|
val redactedEventEntity = EventEntity(eventId = A_REDACTED_EVENT_ID, type = EventType.STATE_ROOM_BEACON_INFO.unstable)
|
||||||
fakeRealm.givenWhere<EventEntity>()
|
fakeRealm.givenWhere<EventEntity>()
|
||||||
.givenEqualTo(EventEntityFields.EVENT_ID, A_REDACTED_EVENT_ID)
|
.givenEqualTo(EventEntityFields.EVENT_ID, A_REDACTED_EVENT_ID)
|
||||||
.givenFindFirst(redactedEventEntity)
|
.givenFindFirst(redactedEventEntity)
|
||||||
|
|
|
@ -40,20 +40,26 @@ class ShieldImageView @JvmOverloads constructor(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders device shield with the support of unknown shields instead of black shields which is used for rooms.
|
* Renders device shield with the support of unknown shields instead of black shields which is used for rooms.
|
||||||
* @param roomEncryptionTrustLevel trust level that is usally calculated with [im.vector.app.features.settings.devices.TrustUtils.shieldForTrust]
|
* @param roomEncryptionTrustLevel trust level that is usually calculated with [im.vector.app.features.settings.devices.TrustUtils.shieldForTrust]
|
||||||
* @param borderLess if true then the shield icon with border around is used
|
* @param borderLess if true then the shield icon with border around is used
|
||||||
*/
|
*/
|
||||||
fun renderDeviceShield(roomEncryptionTrustLevel: RoomEncryptionTrustLevel?, borderLess: Boolean = false) {
|
fun renderDeviceShield(roomEncryptionTrustLevel: RoomEncryptionTrustLevel?, borderLess: Boolean = false) {
|
||||||
isVisible = roomEncryptionTrustLevel != null
|
when (roomEncryptionTrustLevel) {
|
||||||
|
null -> {
|
||||||
if (roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Default) {
|
contentDescription = context.getString(R.string.a11y_trust_level_warning)
|
||||||
|
setImageResource(
|
||||||
|
if (borderLess) R.drawable.ic_shield_warning_no_border
|
||||||
|
else R.drawable.ic_shield_warning
|
||||||
|
)
|
||||||
|
}
|
||||||
|
RoomEncryptionTrustLevel.Default -> {
|
||||||
contentDescription = context.getString(R.string.a11y_trust_level_default)
|
contentDescription = context.getString(R.string.a11y_trust_level_default)
|
||||||
setImageResource(
|
setImageResource(
|
||||||
if (borderLess) R.drawable.ic_shield_unknown_no_border
|
if (borderLess) R.drawable.ic_shield_unknown_no_border
|
||||||
else R.drawable.ic_shield_unknown
|
else R.drawable.ic_shield_unknown
|
||||||
)
|
)
|
||||||
} else {
|
}
|
||||||
render(roomEncryptionTrustLevel, borderLess)
|
else -> render(roomEncryptionTrustLevel, borderLess)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,12 +155,9 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
||||||
// For incoming request we should prompt (if not in activity where this request apply)
|
// For incoming request we should prompt (if not in activity where this request apply)
|
||||||
if (pr.isIncoming) {
|
if (pr.isIncoming) {
|
||||||
// if it's a self verification for my devices, we can discard the review login alert
|
// if it's a self verification for my devices, we can discard the review login alert
|
||||||
// if not this request will be underneath and not visible by the user...
|
// if not, this request will be underneath and not visible by the user...
|
||||||
// it will re-appear later
|
// it will re-appear later
|
||||||
if (pr.otherUserId == session?.myUserId) {
|
cancelAnyVerifySessionAlerts(pr)
|
||||||
// XXX this is a bit hard coded :/
|
|
||||||
popupAlertManager.cancelAlert("review_login")
|
|
||||||
}
|
|
||||||
val user = session.getUserOrDefault(pr.otherUserId).toMatrixItem()
|
val user = session.getUserOrDefault(pr.otherUserId).toMatrixItem()
|
||||||
val name = user.getBestName()
|
val name = user.getBestName()
|
||||||
val description = if (name == pr.otherUserId) {
|
val description = if (name == pr.otherUserId) {
|
||||||
|
@ -170,21 +167,23 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
val alert = VerificationVectorAlert(
|
val alert = VerificationVectorAlert(
|
||||||
uniqueIdForVerificationRequest(pr),
|
uid = uniqueIdForVerificationRequest(pr),
|
||||||
context.getString(R.string.sas_incoming_request_notif_title),
|
title = context.getString(R.string.sas_incoming_request_notif_title),
|
||||||
description,
|
description = description,
|
||||||
R.drawable.ic_shield_black,
|
iconId = R.drawable.ic_shield_black,
|
||||||
|
priority = PopupAlertManager.INCOMING_VERIFICATION_REQUEST_PRIORITY,
|
||||||
shouldBeDisplayedIn = { activity ->
|
shouldBeDisplayedIn = { activity ->
|
||||||
if (activity is RoomDetailActivity) {
|
if (activity is RoomDetailActivity) {
|
||||||
activity.intent?.extras?.getParcelableCompat<TimelineArgs>(RoomDetailActivity.EXTRA_ROOM_DETAIL_ARGS)?.let {
|
activity.intent?.extras?.getParcelableCompat<TimelineArgs>(RoomDetailActivity.EXTRA_ROOM_DETAIL_ARGS)?.let {
|
||||||
it.roomId != pr.roomId
|
it.roomId != pr.roomId
|
||||||
} ?: true
|
} ?: true
|
||||||
} else true
|
} else true
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
.apply {
|
.apply {
|
||||||
viewBinder = VerificationVectorAlert.ViewBinder(user, avatarRenderer.get())
|
viewBinder = VerificationVectorAlert.ViewBinder(user, avatarRenderer.get())
|
||||||
contentAction = Runnable {
|
contentAction = Runnable {
|
||||||
|
cancelAnyVerifySessionAlerts(pr)
|
||||||
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
(weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let {
|
||||||
val roomId = pr.roomId
|
val roomId = pr.roomId
|
||||||
if (roomId.isNullOrBlank()) {
|
if (roomId.isNullOrBlank()) {
|
||||||
|
@ -215,6 +214,13 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun cancelAnyVerifySessionAlerts(pr: PendingVerificationRequest) {
|
||||||
|
if (pr.otherUserId == session?.myUserId) {
|
||||||
|
popupAlertManager.cancelAlert(PopupAlertManager.REVIEW_LOGIN_UID)
|
||||||
|
popupAlertManager.cancelAlert(PopupAlertManager.VERIFY_SESSION_UID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun verificationRequestUpdated(pr: PendingVerificationRequest) {
|
override fun verificationRequestUpdated(pr: PendingVerificationRequest) {
|
||||||
// If an incoming request is readied (by another device?) we should discard the alert
|
// If an incoming request is readied (by another device?) we should discard the alert
|
||||||
if (pr.isIncoming && (pr.state == EVerificationState.HandledByOtherSession ||
|
if (pr.isIncoming && (pr.state == EVerificationState.HandledByOtherSession ||
|
||||||
|
|
|
@ -441,9 +441,10 @@ class HomeActivity :
|
||||||
private fun handleAskPasswordToInitCrossSigning(events: HomeActivityViewEvents.AskPasswordToInitCrossSigning) {
|
private fun handleAskPasswordToInitCrossSigning(events: HomeActivityViewEvents.AskPasswordToInitCrossSigning) {
|
||||||
// We need to ask
|
// We need to ask
|
||||||
promptSecurityEvent(
|
promptSecurityEvent(
|
||||||
events.userItem,
|
uid = PopupAlertManager.UPGRADE_SECURITY_UID,
|
||||||
R.string.upgrade_security,
|
userItem = events.userItem,
|
||||||
R.string.security_prompt_text
|
titleRes = R.string.upgrade_security,
|
||||||
|
descRes = R.string.security_prompt_text,
|
||||||
) {
|
) {
|
||||||
it.navigator.upgradeSessionSecurity(it, true)
|
it.navigator.upgradeSessionSecurity(it, true)
|
||||||
}
|
}
|
||||||
|
@ -452,9 +453,10 @@ class HomeActivity :
|
||||||
private fun handleCrossSigningInvalidated(event: HomeActivityViewEvents.OnCrossSignedInvalidated) {
|
private fun handleCrossSigningInvalidated(event: HomeActivityViewEvents.OnCrossSignedInvalidated) {
|
||||||
// We need to ask
|
// We need to ask
|
||||||
promptSecurityEvent(
|
promptSecurityEvent(
|
||||||
event.userItem,
|
uid = PopupAlertManager.VERIFY_SESSION_UID,
|
||||||
R.string.crosssigning_verify_this_session,
|
userItem = event.userItem,
|
||||||
R.string.confirm_your_identity
|
titleRes = R.string.crosssigning_verify_this_session,
|
||||||
|
descRes = R.string.confirm_your_identity,
|
||||||
) {
|
) {
|
||||||
// check first if it's not an outdated request?
|
// check first if it's not an outdated request?
|
||||||
activeSessionHolder.getSafeActiveSession()?.let { session ->
|
activeSessionHolder.getSafeActiveSession()?.let { session ->
|
||||||
|
@ -472,9 +474,10 @@ class HomeActivity :
|
||||||
private fun handleOnNewSession(event: HomeActivityViewEvents.CurrentSessionNotVerified) {
|
private fun handleOnNewSession(event: HomeActivityViewEvents.CurrentSessionNotVerified) {
|
||||||
// We need to ask
|
// We need to ask
|
||||||
promptSecurityEvent(
|
promptSecurityEvent(
|
||||||
event.userItem,
|
uid = PopupAlertManager.VERIFY_SESSION_UID,
|
||||||
R.string.crosssigning_verify_this_session,
|
userItem = event.userItem,
|
||||||
R.string.confirm_your_identity
|
titleRes = R.string.crosssigning_verify_this_session,
|
||||||
|
descRes = R.string.confirm_your_identity,
|
||||||
) {
|
) {
|
||||||
// navigator.openSettings(this, SettingsActivityPayload.SecurityPrivacy)
|
// navigator.openSettings(this, SettingsActivityPayload.SecurityPrivacy)
|
||||||
// if (event.waitForIncomingRequest) {
|
// if (event.waitForIncomingRequest) {
|
||||||
|
@ -488,9 +491,10 @@ class HomeActivity :
|
||||||
private fun handleCantVerify(event: HomeActivityViewEvents.CurrentSessionCannotBeVerified) {
|
private fun handleCantVerify(event: HomeActivityViewEvents.CurrentSessionCannotBeVerified) {
|
||||||
// We need to ask
|
// We need to ask
|
||||||
promptSecurityEvent(
|
promptSecurityEvent(
|
||||||
event.userItem,
|
uid = PopupAlertManager.UPGRADE_SECURITY_UID,
|
||||||
R.string.crosssigning_cannot_verify_this_session,
|
userItem = event.userItem,
|
||||||
R.string.crosssigning_cannot_verify_this_session_desc
|
titleRes = R.string.crosssigning_cannot_verify_this_session,
|
||||||
|
descRes = R.string.crosssigning_cannot_verify_this_session_desc,
|
||||||
) {
|
) {
|
||||||
it.navigator.open4SSetup(it, SetupMode.PASSPHRASE_AND_NEEDED_SECRETS_RESET)
|
it.navigator.open4SSetup(it, SetupMode.PASSPHRASE_AND_NEEDED_SECRETS_RESET)
|
||||||
}
|
}
|
||||||
|
@ -499,7 +503,7 @@ class HomeActivity :
|
||||||
private fun handlePromptToEnablePush() {
|
private fun handlePromptToEnablePush() {
|
||||||
popupAlertManager.postVectorAlert(
|
popupAlertManager.postVectorAlert(
|
||||||
DefaultVectorAlert(
|
DefaultVectorAlert(
|
||||||
uid = "enablePush",
|
uid = PopupAlertManager.ENABLE_PUSH_UID,
|
||||||
title = getString(R.string.alert_push_are_disabled_title),
|
title = getString(R.string.alert_push_are_disabled_title),
|
||||||
description = getString(R.string.alert_push_are_disabled_description),
|
description = getString(R.string.alert_push_are_disabled_description),
|
||||||
iconId = R.drawable.ic_room_actions_notifications_mutes,
|
iconId = R.drawable.ic_room_actions_notifications_mutes,
|
||||||
|
@ -532,10 +536,16 @@ class HomeActivity :
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun promptSecurityEvent(userItem: MatrixItem.UserItem, titleRes: Int, descRes: Int, action: ((VectorBaseActivity<*>) -> Unit)) {
|
private fun promptSecurityEvent(
|
||||||
|
uid: String,
|
||||||
|
userItem: MatrixItem.UserItem,
|
||||||
|
titleRes: Int,
|
||||||
|
descRes: Int,
|
||||||
|
action: ((VectorBaseActivity<*>) -> Unit),
|
||||||
|
) {
|
||||||
popupAlertManager.postVectorAlert(
|
popupAlertManager.postVectorAlert(
|
||||||
VerificationVectorAlert(
|
VerificationVectorAlert(
|
||||||
uid = "upgradeSecurity",
|
uid = uid,
|
||||||
title = getString(titleRes),
|
title = getString(titleRes),
|
||||||
description = getString(descRes),
|
description = getString(descRes),
|
||||||
iconId = R.drawable.ic_shield_warning
|
iconId = R.drawable.ic_shield_warning
|
||||||
|
|
|
@ -156,7 +156,7 @@ class HomeDetailFragment :
|
||||||
unknownDeviceDetectorSharedViewModel.onEach { state ->
|
unknownDeviceDetectorSharedViewModel.onEach { state ->
|
||||||
state.unknownSessions.invoke()?.let { unknownDevices ->
|
state.unknownSessions.invoke()?.let { unknownDevices ->
|
||||||
if (unknownDevices.firstOrNull()?.currentSessionTrust == true) {
|
if (unknownDevices.firstOrNull()?.currentSessionTrust == true) {
|
||||||
val uid = "review_login"
|
val uid = PopupAlertManager.REVIEW_LOGIN_UID
|
||||||
alertManager.cancelAlert(uid)
|
alertManager.cancelAlert(uid)
|
||||||
val olderUnverified = unknownDevices.filter { !it.isNew }
|
val olderUnverified = unknownDevices.filter { !it.isNew }
|
||||||
val newest = unknownDevices.firstOrNull { it.isNew }?.deviceInfo
|
val newest = unknownDevices.firstOrNull { it.isNew }?.deviceInfo
|
||||||
|
|
|
@ -160,7 +160,7 @@ class NewHomeDetailFragment :
|
||||||
unknownDeviceDetectorSharedViewModel.onEach { state ->
|
unknownDeviceDetectorSharedViewModel.onEach { state ->
|
||||||
state.unknownSessions.invoke()?.let { unknownDevices ->
|
state.unknownSessions.invoke()?.let { unknownDevices ->
|
||||||
if (unknownDevices.firstOrNull()?.currentSessionTrust == true) {
|
if (unknownDevices.firstOrNull()?.currentSessionTrust == true) {
|
||||||
val uid = "review_login"
|
val uid = PopupAlertManager.REVIEW_LOGIN_UID
|
||||||
alertManager.cancelAlert(uid)
|
alertManager.cancelAlert(uid)
|
||||||
val olderUnverified = unknownDevices.filter { !it.isNew }
|
val olderUnverified = unknownDevices.filter { !it.isNew }
|
||||||
val newest = unknownDevices.firstOrNull { it.isNew }?.deviceInfo
|
val newest = unknownDevices.firstOrNull { it.isNew }?.deviceInfo
|
||||||
|
|
|
@ -105,7 +105,7 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(
|
||||||
// Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}")
|
// Timber.v("## Detector trigger canCrossSign ${pInfo.get().selfSigned != null}")
|
||||||
infoList
|
infoList
|
||||||
.filter { info ->
|
.filter { info ->
|
||||||
// filter verified session, by checking the crypto device info
|
// filter out verified sessions or those which do not support encryption (i.e. without crypto info)
|
||||||
cryptoList.firstOrNull { info.deviceId == it.deviceId }?.isVerified?.not().orFalse()
|
cryptoList.firstOrNull { info.deviceId == it.deviceId }?.isVerified?.not().orFalse()
|
||||||
}
|
}
|
||||||
// filter out ignored devices
|
// filter out ignored devices
|
||||||
|
|
|
@ -975,6 +975,7 @@ class TimelineFragment :
|
||||||
notificationDrawerManager.setCurrentThread(timelineArgs.threadTimelineArgs?.rootThreadEventId)
|
notificationDrawerManager.setCurrentThread(timelineArgs.threadTimelineArgs?.rootThreadEventId)
|
||||||
roomDetailPendingActionStore.data?.let { handlePendingAction(it) }
|
roomDetailPendingActionStore.data?.let { handlePendingAction(it) }
|
||||||
roomDetailPendingActionStore.data = null
|
roomDetailPendingActionStore.data = null
|
||||||
|
views.timelineRecyclerView.adapter = timelineEventController.adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handlePendingAction(roomDetailPendingAction: RoomDetailPendingAction) {
|
private fun handlePendingAction(roomDetailPendingAction: RoomDetailPendingAction) {
|
||||||
|
@ -993,6 +994,7 @@ class TimelineFragment :
|
||||||
super.onPause()
|
super.onPause()
|
||||||
notificationDrawerManager.setCurrentRoom(null)
|
notificationDrawerManager.setCurrentRoom(null)
|
||||||
notificationDrawerManager.setCurrentThread(null)
|
notificationDrawerManager.setCurrentThread(null)
|
||||||
|
views.timelineRecyclerView.adapter = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private val emojiActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
private val emojiActivityResultLauncher = registerStartForActivityResult { activityResult ->
|
||||||
|
@ -1058,7 +1060,6 @@ class TimelineFragment :
|
||||||
it.dispatchTo(scrollOnHighlightedEventCallback)
|
it.dispatchTo(scrollOnHighlightedEventCallback)
|
||||||
}
|
}
|
||||||
timelineEventController.addModelBuildListener(modelBuildListener)
|
timelineEventController.addModelBuildListener(modelBuildListener)
|
||||||
views.timelineRecyclerView.adapter = timelineEventController.adapter
|
|
||||||
|
|
||||||
if (vectorPreferences.swipeToReplyIsEnabled()) {
|
if (vectorPreferences.swipeToReplyIsEnabled()) {
|
||||||
val quickReplyHandler = object : RoomMessageTouchHelperCallback.QuickReplayHandler {
|
val quickReplyHandler = object : RoomMessageTouchHelperCallback.QuickReplayHandler {
|
||||||
|
|
|
@ -285,7 +285,7 @@ class MessageComposerFragment : VectorBaseFragment<FragmentComposerBinding>(), A
|
||||||
else -> return
|
else -> return
|
||||||
}
|
}
|
||||||
|
|
||||||
(composer as? RichTextComposerLayout)?.setFullScreen(setFullScreen)
|
(composer as? RichTextComposerLayout)?.setFullScreen(setFullScreen, true)
|
||||||
|
|
||||||
messageComposerViewModel.handle(MessageComposerAction.SetFullScreen(setFullScreen))
|
messageComposerViewModel.handle(MessageComposerAction.SetFullScreen(setFullScreen))
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,6 @@ sealed interface MessageComposerMode {
|
||||||
|
|
||||||
sealed class Special(open val event: TimelineEvent, open val defaultContent: CharSequence) : MessageComposerMode
|
sealed class Special(open val event: TimelineEvent, open val defaultContent: CharSequence) : MessageComposerMode
|
||||||
data class Edit(override val event: TimelineEvent, override val defaultContent: CharSequence) : Special(event, defaultContent)
|
data class Edit(override val event: TimelineEvent, override val defaultContent: CharSequence) : Special(event, defaultContent)
|
||||||
class Quote(override val event: TimelineEvent, override val defaultContent: CharSequence) : Special(event, defaultContent)
|
data class Quote(override val event: TimelineEvent, override val defaultContent: CharSequence) : Special(event, defaultContent)
|
||||||
class Reply(override val event: TimelineEvent, override val defaultContent: CharSequence) : Special(event, defaultContent)
|
data class Reply(override val event: TimelineEvent, override val defaultContent: CharSequence) : Special(event, defaultContent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ internal class RichTextComposerLayout @JvmOverloads constructor(
|
||||||
// There is no need to persist these values since they're always updated by the parent fragment
|
// There is no need to persist these values since they're always updated by the parent fragment
|
||||||
private var isFullScreen = false
|
private var isFullScreen = false
|
||||||
private var hasRelatedMessage = false
|
private var hasRelatedMessage = false
|
||||||
|
private var composerMode: MessageComposerMode? = null
|
||||||
|
|
||||||
var isTextFormattingEnabled = true
|
var isTextFormattingEnabled = true
|
||||||
set(value) {
|
set(value) {
|
||||||
|
@ -114,9 +115,15 @@ internal class RichTextComposerLayout @JvmOverloads constructor(
|
||||||
|
|
||||||
private val dimensionConverter = DimensionConverter(resources)
|
private val dimensionConverter = DimensionConverter(resources)
|
||||||
|
|
||||||
fun setFullScreen(isFullScreen: Boolean) {
|
fun setFullScreen(isFullScreen: Boolean, animated: Boolean) {
|
||||||
|
if (!animated && views.composerLayout.layoutParams != null) {
|
||||||
|
views.composerLayout.updateLayoutParams<ViewGroup.LayoutParams> {
|
||||||
|
height =
|
||||||
|
if (isFullScreen) ViewGroup.LayoutParams.MATCH_PARENT else ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
}
|
||||||
|
}
|
||||||
editText.updateLayoutParams<ViewGroup.LayoutParams> {
|
editText.updateLayoutParams<ViewGroup.LayoutParams> {
|
||||||
height = if (isFullScreen) 0 else ViewGroup.LayoutParams.WRAP_CONTENT
|
height = if (isFullScreen) ViewGroup.LayoutParams.MATCH_PARENT else ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTextFieldBorder(isFullScreen)
|
updateTextFieldBorder(isFullScreen)
|
||||||
|
@ -371,7 +378,11 @@ internal class RichTextComposerLayout @JvmOverloads constructor(
|
||||||
override fun renderComposerMode(mode: MessageComposerMode) {
|
override fun renderComposerMode(mode: MessageComposerMode) {
|
||||||
if (mode is MessageComposerMode.Special) {
|
if (mode is MessageComposerMode.Special) {
|
||||||
views.composerModeGroup.isVisible = true
|
views.composerModeGroup.isVisible = true
|
||||||
|
if (isTextFormattingEnabled) {
|
||||||
replaceFormattedContent(mode.defaultContent)
|
replaceFormattedContent(mode.defaultContent)
|
||||||
|
} else {
|
||||||
|
views.plainTextComposerEditText.setText(mode.defaultContent)
|
||||||
|
}
|
||||||
hasRelatedMessage = true
|
hasRelatedMessage = true
|
||||||
editText.showKeyboard(andRequestFocus = true)
|
editText.showKeyboard(andRequestFocus = true)
|
||||||
} else {
|
} else {
|
||||||
|
@ -383,10 +394,14 @@ internal class RichTextComposerLayout @JvmOverloads constructor(
|
||||||
views.plainTextComposerEditText.setText(text)
|
views.plainTextComposerEditText.setText(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
views.sendButton.contentDescription = resources.getString(R.string.action_send)
|
|
||||||
hasRelatedMessage = false
|
hasRelatedMessage = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTextFieldBorder(isFullScreen)
|
||||||
|
|
||||||
|
if (this.composerMode == mode) return
|
||||||
|
this.composerMode = mode
|
||||||
|
|
||||||
views.sendButton.apply {
|
views.sendButton.apply {
|
||||||
if (mode is MessageComposerMode.Edit) {
|
if (mode is MessageComposerMode.Edit) {
|
||||||
contentDescription = resources.getString(R.string.action_save)
|
contentDescription = resources.getString(R.string.action_save)
|
||||||
|
@ -397,8 +412,6 @@ internal class RichTextComposerLayout @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTextFieldBorder(isFullScreen)
|
|
||||||
|
|
||||||
when (mode) {
|
when (mode) {
|
||||||
is MessageComposerMode.Edit -> {
|
is MessageComposerMode.Edit -> {
|
||||||
views.composerModeTitleView.setText(R.string.editing)
|
views.composerModeTitleView.setText(R.string.editing)
|
||||||
|
|
|
@ -50,6 +50,12 @@ class PopupAlertManager @Inject constructor(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val INCOMING_CALL_PRIORITY = Int.MAX_VALUE
|
const val INCOMING_CALL_PRIORITY = Int.MAX_VALUE
|
||||||
|
const val INCOMING_VERIFICATION_REQUEST_PRIORITY = 1
|
||||||
|
const val DEFAULT_PRIORITY = 0
|
||||||
|
const val REVIEW_LOGIN_UID = "review_login"
|
||||||
|
const val UPGRADE_SECURITY_UID = "upgrade_security"
|
||||||
|
const val VERIFY_SESSION_UID = "verify_session"
|
||||||
|
const val ENABLE_PUSH_UID = "enable_push"
|
||||||
}
|
}
|
||||||
|
|
||||||
private var weakCurrentActivity: WeakReference<Activity>? = null
|
private var weakCurrentActivity: WeakReference<Activity>? = null
|
||||||
|
@ -145,7 +151,7 @@ class PopupAlertManager @Inject constructor(
|
||||||
|
|
||||||
private fun displayNextIfPossible() {
|
private fun displayNextIfPossible() {
|
||||||
val currentActivity = weakCurrentActivity?.get()
|
val currentActivity = weakCurrentActivity?.get()
|
||||||
if (Alerter.isShowing || currentActivity == null || currentActivity.isDestroyed) {
|
if (currentActivity == null || currentActivity.isDestroyed) {
|
||||||
// will retry later
|
// will retry later
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ open class DefaultVectorAlert(
|
||||||
|
|
||||||
override val dismissOnClick: Boolean = true
|
override val dismissOnClick: Boolean = true
|
||||||
|
|
||||||
override val priority: Int = 0
|
override val priority: Int = PopupAlertManager.DEFAULT_PRIORITY
|
||||||
|
|
||||||
override val isLight: Boolean = false
|
override val isLight: Boolean = false
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ class VerificationVectorAlert(
|
||||||
title: String,
|
title: String,
|
||||||
override val description: String,
|
override val description: String,
|
||||||
@DrawableRes override val iconId: Int?,
|
@DrawableRes override val iconId: Int?,
|
||||||
|
override val priority: Int = PopupAlertManager.DEFAULT_PRIORITY,
|
||||||
/**
|
/**
|
||||||
* Alert are displayed by default, but let this lambda return false to prevent displaying.
|
* Alert are displayed by default, but let this lambda return false to prevent displaying.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -83,7 +83,7 @@ data class DevicesViewState(
|
||||||
data class DeviceFullInfo(
|
data class DeviceFullInfo(
|
||||||
val deviceInfo: DeviceInfo,
|
val deviceInfo: DeviceInfo,
|
||||||
val cryptoDeviceInfo: CryptoDeviceInfo?,
|
val cryptoDeviceInfo: CryptoDeviceInfo?,
|
||||||
val trustLevelForShield: RoomEncryptionTrustLevel,
|
val trustLevelForShield: RoomEncryptionTrustLevel?,
|
||||||
val isInactive: Boolean,
|
val isInactive: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
data class DeviceFullInfo(
|
data class DeviceFullInfo(
|
||||||
val deviceInfo: DeviceInfo,
|
val deviceInfo: DeviceInfo,
|
||||||
val cryptoDeviceInfo: CryptoDeviceInfo?,
|
val cryptoDeviceInfo: CryptoDeviceInfo?,
|
||||||
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel,
|
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel?,
|
||||||
val isInactive: Boolean,
|
val isInactive: Boolean,
|
||||||
val isCurrentDevice: Boolean,
|
val isCurrentDevice: Boolean,
|
||||||
val deviceExtendedInfo: DeviceExtendedInfo,
|
val deviceExtendedInfo: DeviceExtendedInfo,
|
||||||
|
|
|
@ -85,13 +85,14 @@ class SessionInfoView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderVerificationStatus(
|
private fun renderVerificationStatus(
|
||||||
encryptionTrustLevel: RoomEncryptionTrustLevel,
|
encryptionTrustLevel: RoomEncryptionTrustLevel?,
|
||||||
isCurrentSession: Boolean,
|
isCurrentSession: Boolean,
|
||||||
hasLearnMoreLink: Boolean,
|
hasLearnMoreLink: Boolean,
|
||||||
isVerifyButtonVisible: Boolean,
|
isVerifyButtonVisible: Boolean,
|
||||||
) {
|
) {
|
||||||
views.sessionInfoVerificationStatusImageView.renderDeviceShield(encryptionTrustLevel)
|
views.sessionInfoVerificationStatusImageView.renderDeviceShield(encryptionTrustLevel)
|
||||||
when {
|
when {
|
||||||
|
encryptionTrustLevel == null -> renderCrossSigningEncryptionNotSupported()
|
||||||
encryptionTrustLevel == RoomEncryptionTrustLevel.Trusted -> renderCrossSigningVerified(isCurrentSession)
|
encryptionTrustLevel == RoomEncryptionTrustLevel.Trusted -> renderCrossSigningVerified(isCurrentSession)
|
||||||
encryptionTrustLevel == RoomEncryptionTrustLevel.Default && !isCurrentSession -> renderCrossSigningUnknown()
|
encryptionTrustLevel == RoomEncryptionTrustLevel.Default && !isCurrentSession -> renderCrossSigningUnknown()
|
||||||
else -> renderCrossSigningUnverified(isCurrentSession, isVerifyButtonVisible)
|
else -> renderCrossSigningUnverified(isCurrentSession, isVerifyButtonVisible)
|
||||||
|
@ -149,6 +150,14 @@ class SessionInfoView @JvmOverloads constructor(
|
||||||
views.sessionInfoVerifySessionButton.isVisible = false
|
views.sessionInfoVerifySessionButton.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun renderCrossSigningEncryptionNotSupported() {
|
||||||
|
views.sessionInfoVerificationStatusTextView.text = context.getString(R.string.device_manager_verification_status_unverified)
|
||||||
|
views.sessionInfoVerificationStatusTextView.setTextColor(ThemeUtils.getColor(context, R.attr.colorError))
|
||||||
|
views.sessionInfoVerificationStatusDetailTextView.text =
|
||||||
|
context.getString(R.string.device_manager_verification_status_detail_session_encryption_not_supported)
|
||||||
|
views.sessionInfoVerifySessionButton.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
private fun renderDeviceInfo(sessionName: String, deviceType: DeviceType, stringProvider: StringProvider) {
|
private fun renderDeviceInfo(sessionName: String, deviceType: DeviceType, stringProvider: StringProvider) {
|
||||||
setDeviceTypeIconUseCase.execute(deviceType, views.sessionInfoDeviceTypeImageView, stringProvider)
|
setDeviceTypeIconUseCase.execute(deviceType, views.sessionInfoDeviceTypeImageView, stringProvider)
|
||||||
views.sessionInfoNameTextView.text = sessionName
|
views.sessionInfoNameTextView.text = sessionName
|
||||||
|
|
|
@ -229,7 +229,7 @@ class SessionOverviewFragment :
|
||||||
)
|
)
|
||||||
views.sessionOverviewInfo.render(infoViewState, dateFormatter, drawableProvider, colorProvider, stringProvider)
|
views.sessionOverviewInfo.render(infoViewState, dateFormatter, drawableProvider, colorProvider, stringProvider)
|
||||||
views.sessionOverviewInfo.onLearnMoreClickListener = {
|
views.sessionOverviewInfo.onLearnMoreClickListener = {
|
||||||
showLearnMoreInfoVerificationStatus(deviceInfo.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted)
|
showLearnMoreInfoVerificationStatus(deviceInfo.roomEncryptionTrustLevel)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
views.sessionOverviewInfo.isVisible = false
|
views.sessionOverviewInfo.isVisible = false
|
||||||
|
@ -293,21 +293,28 @@ class SessionOverviewFragment :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showLearnMoreInfoVerificationStatus(isVerified: Boolean) {
|
private fun showLearnMoreInfoVerificationStatus(roomEncryptionTrustLevel: RoomEncryptionTrustLevel?) {
|
||||||
val titleResId = if (isVerified) {
|
val args = when (roomEncryptionTrustLevel) {
|
||||||
R.string.device_manager_verification_status_verified
|
null -> {
|
||||||
} else {
|
// encryption not supported
|
||||||
R.string.device_manager_verification_status_unverified
|
SessionLearnMoreBottomSheet.Args(
|
||||||
}
|
title = getString(R.string.device_manager_verification_status_unverified),
|
||||||
val descriptionResId = if (isVerified) {
|
description = getString(R.string.device_manager_learn_more_sessions_encryption_not_supported),
|
||||||
R.string.device_manager_learn_more_sessions_verified_description
|
|
||||||
} else {
|
|
||||||
R.string.device_manager_learn_more_sessions_unverified
|
|
||||||
}
|
|
||||||
val args = SessionLearnMoreBottomSheet.Args(
|
|
||||||
title = getString(titleResId),
|
|
||||||
description = getString(descriptionResId),
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
RoomEncryptionTrustLevel.Trusted -> {
|
||||||
|
SessionLearnMoreBottomSheet.Args(
|
||||||
|
title = getString(R.string.device_manager_verification_status_verified),
|
||||||
|
description = getString(R.string.device_manager_learn_more_sessions_verified_description),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
SessionLearnMoreBottomSheet.Args(
|
||||||
|
title = getString(R.string.device_manager_verification_status_unverified),
|
||||||
|
description = getString(R.string.device_manager_learn_more_sessions_unverified),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
SessionLearnMoreBottomSheet.show(childFragmentManager, args)
|
SessionLearnMoreBottomSheet.show(childFragmentManager, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,15 @@ class GetEncryptionTrustLevelForDeviceUseCase @Inject constructor(
|
||||||
private val getEncryptionTrustLevelForOtherDeviceUseCase: GetEncryptionTrustLevelForOtherDeviceUseCase,
|
private val getEncryptionTrustLevelForOtherDeviceUseCase: GetEncryptionTrustLevelForOtherDeviceUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun execute(currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo, cryptoDeviceInfo: CryptoDeviceInfo?): RoomEncryptionTrustLevel {
|
fun execute(currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo, cryptoDeviceInfo: CryptoDeviceInfo?): RoomEncryptionTrustLevel? {
|
||||||
|
if (cryptoDeviceInfo == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
val legacyMode = !currentSessionCrossSigningInfo.isCrossSigningInitialized
|
val legacyMode = !currentSessionCrossSigningInfo.isCrossSigningInitialized
|
||||||
val trustMSK = currentSessionCrossSigningInfo.isCrossSigningVerified
|
val trustMSK = currentSessionCrossSigningInfo.isCrossSigningVerified
|
||||||
val isCurrentDevice = !cryptoDeviceInfo?.deviceId.isNullOrEmpty() && cryptoDeviceInfo?.deviceId == currentSessionCrossSigningInfo.deviceId
|
val isCurrentDevice = !cryptoDeviceInfo.deviceId.isNullOrEmpty() && cryptoDeviceInfo.deviceId == currentSessionCrossSigningInfo.deviceId
|
||||||
val deviceTrustLevel = cryptoDeviceInfo?.trustLevel
|
val deviceTrustLevel = cryptoDeviceInfo.trustLevel
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
isCurrentDevice -> getEncryptionTrustLevelForCurrentDeviceUseCase.execute(trustMSK, legacyMode)
|
isCurrentDevice -> getEncryptionTrustLevelForCurrentDeviceUseCase.execute(trustMSK, legacyMode)
|
||||||
|
|
|
@ -25,12 +25,10 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.ClickListener
|
import im.vector.app.core.epoxy.ClickListener
|
||||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
|
||||||
|
|
||||||
@EpoxyModelClass
|
@EpoxyModelClass
|
||||||
abstract class InviteByEmailItem : VectorEpoxyModel<InviteByEmailItem.Holder>(R.layout.item_invite_by_mail) {
|
abstract class InviteByEmailItem : VectorEpoxyModel<InviteByEmailItem.Holder>(R.layout.item_invite_by_mail) {
|
||||||
|
|
||||||
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
|
|
||||||
@EpoxyAttribute lateinit var foundItem: ThreePidUser
|
@EpoxyAttribute lateinit var foundItem: ThreePidUser
|
||||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var clickListener: ClickListener? = null
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var clickListener: ClickListener? = null
|
||||||
@EpoxyAttribute var selected: Boolean = false
|
@EpoxyAttribute var selected: Boolean = false
|
||||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2.verification
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
|
import org.amshove.kluent.shouldBe
|
||||||
import org.amshove.kluent.shouldBeEqualTo
|
import org.amshove.kluent.shouldBeEqualTo
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
|
||||||
|
@ -89,6 +90,20 @@ class GetEncryptionTrustLevelForDeviceUseCaseTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given no crypto device info when computing trust level then result is null`() {
|
||||||
|
val currentSessionCrossSigningInfo = givenCurrentSessionCrossSigningInfo(
|
||||||
|
deviceId = A_DEVICE_ID,
|
||||||
|
isCrossSigningInitialized = true,
|
||||||
|
isCrossSigningVerified = false
|
||||||
|
)
|
||||||
|
val cryptoDeviceInfo = null
|
||||||
|
|
||||||
|
val result = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo)
|
||||||
|
|
||||||
|
result shouldBe null
|
||||||
|
}
|
||||||
|
|
||||||
private fun givenCurrentSessionCrossSigningInfo(
|
private fun givenCurrentSessionCrossSigningInfo(
|
||||||
deviceId: String,
|
deviceId: String,
|
||||||
isCrossSigningInitialized: Boolean,
|
isCrossSigningInitialized: Boolean,
|
||||||
|
|
|
@ -63,7 +63,7 @@ object FakeCreatePollViewStates {
|
||||||
)
|
)
|
||||||
|
|
||||||
private val A_POLL_START_EVENT = Event(
|
private val A_POLL_START_EVENT = Event(
|
||||||
type = EventType.POLL_START.stable,
|
type = EventType.POLL_START.unstable,
|
||||||
eventId = A_FAKE_EVENT_ID,
|
eventId = A_FAKE_EVENT_ID,
|
||||||
originServerTs = 1652435922563,
|
originServerTs = 1652435922563,
|
||||||
senderId = A_FAKE_USER_ID,
|
senderId = A_FAKE_USER_ID,
|
||||||
|
|
Loading…
Reference in a new issue