mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-03-17 19:58:57 +03:00
Merge commit '67fc2feacb8e2563cc25f61ed6da48cb4de57ed7' into sc
Merge v1.0.5 pt. 1 Conflicts: vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt vector/src/main/res/layout/fragment_login_server_selection.xml vector/src/main/res/values/theme_dark.xml vector/src/main/res/values/theme_light.xml
This commit is contained in:
commit
c2e1a33864
95 changed files with 989 additions and 163 deletions
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -2,9 +2,9 @@
|
|||
|
||||
<!-- Please read [CONTRIBUTING.md](https://github.com/vector-im/riotX-android/blob/develop/CONTRIBUTING.md) before submitting your pull request -->
|
||||
|
||||
- [ ] Changes has been tested on an Android device or Android emulator with API 16
|
||||
- [ ] Changes has been tested on an Android device or Android emulator with API 21
|
||||
- [ ] UI change has been tested on both light and dark themes
|
||||
- [ ] Pull request is based on the develop branch
|
||||
- [ ] Pull request updates [CHANGES.md](https://github.com/vector-im/riotX-android/blob/develop/CHANGES.md)
|
||||
- [ ] Pull request updates [CHANGES.md](https://github.com/vector-im/element-android/blob/develop/CHANGES.md)
|
||||
- [ ] Pull request includes screenshots or videos if containing UI changes
|
||||
- [ ] Pull request includes a [sign off](https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md#sign-off)
|
||||
|
|
26
CHANGES.md
26
CHANGES.md
|
@ -1,3 +1,29 @@
|
|||
Changes in Element 1.0.5 (2020-XX-XX)
|
||||
===================================================
|
||||
|
||||
Features ✨:
|
||||
- Protect access to the app by a pin code (#1700)
|
||||
|
||||
Improvements 🙌:
|
||||
-
|
||||
|
||||
Bugfix 🐛:
|
||||
- Fix invisible toolbar (Status.im theme) (#1746)
|
||||
|
||||
Translations 🗣:
|
||||
-
|
||||
|
||||
SDK API changes ⚠️:
|
||||
-
|
||||
|
||||
Build 🧱:
|
||||
-
|
||||
|
||||
Other changes:
|
||||
- Hide Flair settings, this is not implemented yet.
|
||||
- Rename package `im.vector.riotx.attachmentviewer` to `im.vector.lib.attachmentviewer`
|
||||
- Rename package `im.vector.riotx.multipicker` to `im.vector.lib.multipicker`
|
||||
|
||||
Changes in Element 1.0.4 (2020-08-03)
|
||||
===================================================
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="im.vector.riotx.attachmentviewer" />
|
||||
<manifest package="im.vector.lib.attachmentviewer" />
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
sealed class AttachmentEvents {
|
||||
data class VideoEvent(val isPlaying: Boolean, val progress: Int, val duration: Int) : AttachmentEvents()
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.graphics.drawable.Drawable
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
sealed class SwipeDirection {
|
||||
object NotDetected : SwipeDirection()
|
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
* Copyright (C) 2018 stfalcon.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -15,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.content.Context
|
||||
import android.view.MotionEvent
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.widget.ImageView
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.attachmentviewer
|
||||
package im.vector.lib.attachmentviewer
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ProgressBar
|
|
@ -41,6 +41,8 @@ allprojects {
|
|||
includeGroupByRegex 'com\\.github\\.BillCarsonFr'
|
||||
// PhotoView
|
||||
includeGroupByRegex 'com\\.github\\.chrisbanes'
|
||||
// PFLockScreen-Android
|
||||
includeGroupByRegex 'com\\.github\\.ganfra'
|
||||
}
|
||||
}
|
||||
maven {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
* Copyright 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,10 +17,9 @@
|
|||
package im.vector.matrix.android.api.session.accountdata
|
||||
|
||||
object UserAccountDataTypes {
|
||||
|
||||
const val TYPE_IGNORED_USER_LIST = "m.ignored_user_list"
|
||||
const val TYPE_DIRECT_MESSAGES = "m.direct"
|
||||
const val TYPE_BREADCRUMBS = "im.vector.setting.breadcrumbs" // Was previously "im.vector.riot.breadcrumb_rooms"
|
||||
const val TYPE_BREADCRUMBS = "im.vector.setting.breadcrumbs"
|
||||
const val TYPE_PREVIEW_URLS = "org.matrix.preview_urls"
|
||||
const val TYPE_WIDGETS = "m.widgets"
|
||||
const val TYPE_PUSH_RULES = "m.push_rules"
|
||||
|
|
|
@ -67,13 +67,15 @@ internal interface AuthAPI {
|
|||
* https://github.com/matrix-org/matrix-doc/pull/2290
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "register/{threePid}/requestToken")
|
||||
fun add3Pid(@Path("threePid") threePid: String, @Body params: AddThreePidRegistrationParams): Call<AddThreePidRegistrationResponse>
|
||||
fun add3Pid(@Path("threePid") threePid: String,
|
||||
@Body params: AddThreePidRegistrationParams): Call<AddThreePidRegistrationResponse>
|
||||
|
||||
/**
|
||||
* Validate 3pid
|
||||
*/
|
||||
@POST
|
||||
fun validate3Pid(@Url url: String, @Body params: ValidationCodeBody): Call<SuccessResult>
|
||||
fun validate3Pid(@Url url: String,
|
||||
@Body params: ValidationCodeBody): Call<SuccessResult>
|
||||
|
||||
/**
|
||||
* Get the supported login flow
|
||||
|
|
|
@ -119,7 +119,9 @@ internal interface CryptoApi {
|
|||
* @param body the body
|
||||
*/
|
||||
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "sendToDevice/{eventType}/{txnId}")
|
||||
fun sendToDevice(@Path("eventType") eventType: String, @Path("txnId") transactionId: String, @Body body: SendToDeviceBody): Call<Unit>
|
||||
fun sendToDevice(@Path("eventType") eventType: String,
|
||||
@Path("txnId") transactionId: String,
|
||||
@Body body: SendToDeviceBody): Call<Unit>
|
||||
|
||||
/**
|
||||
* Delete a device.
|
||||
|
@ -129,7 +131,8 @@ internal interface CryptoApi {
|
|||
* @param params the deletion parameters
|
||||
*/
|
||||
@HTTP(path = NetworkConstants.URI_API_PREFIX_PATH_R0 + "devices/{device_id}", method = "DELETE", hasBody = true)
|
||||
fun deleteDevice(@Path("device_id") deviceId: String, @Body params: DeleteDeviceParams): Call<Unit>
|
||||
fun deleteDevice(@Path("device_id") deviceId: String,
|
||||
@Body params: DeleteDeviceParams): Call<Unit>
|
||||
|
||||
/**
|
||||
* Update the device information.
|
||||
|
@ -139,7 +142,8 @@ internal interface CryptoApi {
|
|||
* @param params the params
|
||||
*/
|
||||
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "devices/{device_id}")
|
||||
fun updateDeviceInfo(@Path("device_id") deviceId: String, @Body params: UpdateDeviceInfoBody): Call<Unit>
|
||||
fun updateDeviceInfo(@Path("device_id") deviceId: String,
|
||||
@Body params: UpdateDeviceInfoBody): Call<Unit>
|
||||
|
||||
/**
|
||||
* Get the update devices list from two sync token.
|
||||
|
@ -149,5 +153,6 @@ internal interface CryptoApi {
|
|||
* @param newToken the up-to token.
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "keys/changes")
|
||||
fun getKeyChanges(@Query("from") oldToken: String, @Query("to") newToken: String): Call<KeyChangesResponse>
|
||||
fun getKeyChanges(@Query("from") oldToken: String,
|
||||
@Query("to") newToken: String): Call<KeyChangesResponse>
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ internal class AccessTokenInterceptor(private val accessTokenProvider: AccessTok
|
|||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
var request = chain.request()
|
||||
|
||||
accessTokenProvider.getToken()?.let {
|
||||
// Add the access token to all requests if it is set
|
||||
accessTokenProvider.getToken()?.let { token ->
|
||||
val newRequestBuilder = request.newBuilder()
|
||||
// Add the access token to all requests if it is set
|
||||
newRequestBuilder.addHeader(HttpHeaders.Authorization, "Bearer $it")
|
||||
newRequestBuilder.header(HttpHeaders.Authorization, "Bearer $token")
|
||||
request = newRequestBuilder.build()
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ internal interface FilterApi {
|
|||
* @param body the Json representation of a FilterBody object
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/filter")
|
||||
fun uploadFilter(@Path("userId") userId: String, @Body body: Filter): Call<FilterResponse>
|
||||
fun uploadFilter(@Path("userId") userId: String,
|
||||
@Body body: Filter): Call<FilterResponse>
|
||||
|
||||
/**
|
||||
* Gets a filter with a given filterId from the homeserver
|
||||
|
@ -42,5 +43,6 @@ internal interface FilterApi {
|
|||
* @return Filter
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/filter/{filterId}")
|
||||
fun getFilterById(@Path("userId") userId: String, @Path("filterId") filterId: String): Call<Filter>
|
||||
fun getFilterById(@Path("userId") userId: String,
|
||||
@Path("filterId") filterId: String): Call<Filter>
|
||||
}
|
||||
|
|
|
@ -94,5 +94,6 @@ internal interface IdentityAPI {
|
|||
* - https://matrix.org/docs/spec/identity_service/latest#post-matrix-identity-v2-validate-email-submittoken
|
||||
*/
|
||||
@POST(NetworkConstants.URI_IDENTITY_PATH_V2 + "validate/{medium}/submitToken")
|
||||
fun submitToken(@Path("medium") medium: String, @Body body: IdentityRequestOwnershipParams): Call<SuccessResult>
|
||||
fun submitToken(@Path("medium") medium: String,
|
||||
@Body body: IdentityRequestOwnershipParams): Call<SuccessResult>
|
||||
}
|
||||
|
|
|
@ -34,5 +34,6 @@ internal interface OpenIdAPI {
|
|||
* @param userId the user id
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/openid/request_token")
|
||||
fun openIdToken(@Path("userId") userId: String, @Body body: JsonDict = emptyMap()): Call<RequestOpenIdTokenResponse>
|
||||
fun openIdToken(@Path("userId") userId: String,
|
||||
@Body body: JsonDict = emptyMap()): Call<RequestOpenIdTokenResponse>
|
||||
}
|
||||
|
|
|
@ -47,13 +47,15 @@ internal interface ProfileAPI {
|
|||
* Change user display name
|
||||
*/
|
||||
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}/displayname")
|
||||
fun setDisplayName(@Path("userId") userId: String, @Body body: SetDisplayNameBody): Call<Unit>
|
||||
fun setDisplayName(@Path("userId") userId: String,
|
||||
@Body body: SetDisplayNameBody): Call<Unit>
|
||||
|
||||
/**
|
||||
* Change user avatar url.
|
||||
*/
|
||||
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "profile/{userId}/avatar_url")
|
||||
fun setAvatarUrl(@Path("userId") userId: String, @Body body: SetAvatarUrlBody): Call<Unit>
|
||||
fun setAvatarUrl(@Path("userId") userId: String,
|
||||
@Body body: SetAvatarUrlBody): Call<Unit>
|
||||
|
||||
/**
|
||||
* Bind a threePid
|
||||
|
|
|
@ -165,7 +165,8 @@ internal interface RoomAPI {
|
|||
* @param eventId the event Id
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/event/{eventId}")
|
||||
fun getEvent(@Path("roomId") roomId: String, @Path("eventId") eventId: String): Call<Event>
|
||||
fun getEvent(@Path("roomId") roomId: String,
|
||||
@Path("eventId") eventId: String): Call<Event>
|
||||
|
||||
/**
|
||||
* Send read markers.
|
||||
|
@ -174,7 +175,8 @@ internal interface RoomAPI {
|
|||
* @param markers the read markers
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/read_markers")
|
||||
fun sendReadMarker(@Path("roomId") roomId: String, @Body markers: Map<String, String>): Call<Unit>
|
||||
fun sendReadMarker(@Path("roomId") roomId: String,
|
||||
@Body markers: Map<String, String>): Call<Unit>
|
||||
|
||||
/**
|
||||
* Invite a user to the given room.
|
||||
|
@ -184,7 +186,8 @@ internal interface RoomAPI {
|
|||
* @param body a object that just contains a user id
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/invite")
|
||||
fun invite(@Path("roomId") roomId: String, @Body body: InviteBody): Call<Unit>
|
||||
fun invite(@Path("roomId") roomId: String,
|
||||
@Body body: InviteBody): Call<Unit>
|
||||
|
||||
/**
|
||||
* Invite a user to a room, using a ThreePid
|
||||
|
@ -192,7 +195,8 @@ internal interface RoomAPI {
|
|||
* @param roomId Required. The room identifier (not alias) to which to invite the user.
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/invite")
|
||||
fun invite3pid(@Path("roomId") roomId: String, @Body body: ThreePidInviteBody): Call<Unit>
|
||||
fun invite3pid(@Path("roomId") roomId: String,
|
||||
@Body body: ThreePidInviteBody): Call<Unit>
|
||||
|
||||
/**
|
||||
* Send a generic state events
|
||||
|
@ -278,7 +282,8 @@ internal interface RoomAPI {
|
|||
* @param userIdAndReason the banned user object (userId and reason for ban)
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/ban")
|
||||
fun ban(@Path("roomId") roomId: String, @Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
fun ban(@Path("roomId") roomId: String,
|
||||
@Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
|
||||
/**
|
||||
* unban a user from the given room.
|
||||
|
@ -287,7 +292,8 @@ internal interface RoomAPI {
|
|||
* @param userIdAndReason the unbanned user object (userId and reason for unban)
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/unban")
|
||||
fun unban(@Path("roomId") roomId: String, @Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
fun unban(@Path("roomId") roomId: String,
|
||||
@Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
|
||||
/**
|
||||
* Kick a user from the given room.
|
||||
|
@ -296,7 +302,8 @@ internal interface RoomAPI {
|
|||
* @param userIdAndReason the kicked user object (userId and reason for kicking)
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/kick")
|
||||
fun kick(@Path("roomId") roomId: String, @Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
fun kick(@Path("roomId") roomId: String,
|
||||
@Body userIdAndReason: UserIdAndReason): Call<Unit>
|
||||
|
||||
/**
|
||||
* Strips all information out of an event which isn't critical to the integrity of the server-side representation of the room.
|
||||
|
|
|
@ -35,5 +35,7 @@ internal interface TermsAPI {
|
|||
* This request requires authentication
|
||||
*/
|
||||
@POST
|
||||
fun agreeToTerms(@Url url: String, @Body params: AcceptTermsBody, @Header(HttpHeaders.Authorization) token: String): Call<Unit>
|
||||
fun agreeToTerms(@Url url: String,
|
||||
@Body params: AcceptTermsBody,
|
||||
@Header(HttpHeaders.Authorization) token: String): Call<Unit>
|
||||
}
|
||||
|
|
|
@ -32,5 +32,7 @@ interface AccountDataAPI {
|
|||
* @param params the put params
|
||||
*/
|
||||
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/account_data/{type}")
|
||||
fun setAccountData(@Path("userId") userId: String, @Path("type") type: String, @Body params: Any): Call<Unit>
|
||||
fun setAccountData(@Path("userId") userId: String,
|
||||
@Path("type") type: String,
|
||||
@Body params: Any): Call<Unit>
|
||||
}
|
||||
|
|
|
@ -30,8 +30,10 @@ internal interface WidgetsAPI {
|
|||
* @param body the body content (Ref: https://github.com/matrix-org/matrix-doc/pull/1961)
|
||||
*/
|
||||
@POST("register")
|
||||
fun register(@Body body: RequestOpenIdTokenResponse, @Query("v") version: String?): Call<RegisterWidgetResponse>
|
||||
fun register(@Body body: RequestOpenIdTokenResponse,
|
||||
@Query("v") version: String?): Call<RegisterWidgetResponse>
|
||||
|
||||
@GET("account")
|
||||
fun validateToken(@Query("scalar_token") scalarToken: String?, @Query("v") version: String?): Call<Unit>
|
||||
fun validateToken(@Query("scalar_token") scalarToken: String?,
|
||||
@Query("v") version: String?): Call<Unit>
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="im.vector.riotx.multipicker">
|
||||
package="im.vector.lib.multipicker">
|
||||
|
||||
<application>
|
||||
<provider
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.provider.MediaStore
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerAudioType
|
||||
import im.vector.lib.multipicker.entity.MultiPickerAudioType
|
||||
|
||||
/**
|
||||
* Audio file picker implementation
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
|
@ -23,8 +23,8 @@ import android.net.Uri
|
|||
import android.provider.MediaStore
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerImageType
|
||||
import im.vector.riotx.multipicker.utils.ImageUtils
|
||||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||
import im.vector.lib.multipicker.utils.ImageUtils
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
|
@ -14,14 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.ContactsContract
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerContactType
|
||||
import im.vector.lib.multipicker.entity.MultiPickerContactType
|
||||
|
||||
/**
|
||||
* Contact Picker implementation
|
|
@ -14,13 +14,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.OpenableColumns
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerFileType
|
||||
import im.vector.lib.multipicker.entity.MultiPickerFileType
|
||||
|
||||
/**
|
||||
* Implementation of selecting any type of files
|
|
@ -14,14 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.MediaStore
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerImageType
|
||||
import im.vector.riotx.multipicker.utils.ImageUtils
|
||||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||
import im.vector.lib.multipicker.utils.ImageUtils
|
||||
|
||||
/**
|
||||
* Image Picker implementation
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
class MultiPicker<T> {
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
|
@ -14,14 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker
|
||||
package im.vector.lib.multipicker
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.provider.MediaStore
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerVideoType
|
||||
import im.vector.lib.multipicker.entity.MultiPickerVideoType
|
||||
|
||||
/**
|
||||
* Video Picker implementation
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker.entity
|
||||
package im.vector.lib.multipicker.entity
|
||||
|
||||
import android.net.Uri
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker.entity
|
||||
package im.vector.lib.multipicker.entity
|
||||
|
||||
import android.net.Uri
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker.entity
|
||||
package im.vector.lib.multipicker.entity
|
||||
|
||||
data class MultiPickerContactType(
|
||||
val displayName: String,
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker.entity
|
||||
package im.vector.lib.multipicker.entity
|
||||
|
||||
import android.net.Uri
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker.entity
|
||||
package im.vector.lib.multipicker.entity
|
||||
|
||||
import android.net.Uri
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker.entity
|
||||
package im.vector.lib.multipicker.entity
|
||||
|
||||
import android.net.Uri
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker.provider
|
||||
package im.vector.lib.multipicker.provider
|
||||
|
||||
import androidx.core.content.FileProvider
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.multipicker.utils
|
||||
package im.vector.lib.multipicker.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
|
@ -164,7 +164,7 @@ Formatter\.formatShortFileSize===1
|
|||
# android\.text\.TextUtils
|
||||
|
||||
### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If it is ok, change the value in file forbidden_strings_in_code.txt
|
||||
enum class===74
|
||||
enum class===76
|
||||
|
||||
### Do not import temporary legacy classes
|
||||
import im.vector.matrix.android.internal.legacy.riot===3
|
||||
|
|
|
@ -17,7 +17,7 @@ androidExtensions {
|
|||
// Note: 2 digits max for each value
|
||||
ext.versionMajor = 1
|
||||
ext.versionMinor = 0
|
||||
ext.versionPatch = 4
|
||||
ext.versionPatch = 5
|
||||
|
||||
ext.scVersion = 13
|
||||
|
||||
|
@ -348,6 +348,7 @@ dependencies {
|
|||
implementation 'me.saket:better-link-movement-method:2.2.0'
|
||||
implementation 'com.google.android:flexbox:1.1.1'
|
||||
implementation "androidx.autofill:autofill:$autofill_version"
|
||||
implementation 'com.github.ganfra:PFLockScreen-Android:1.0.0-beta8'
|
||||
|
||||
// Custom Tab
|
||||
implementation 'androidx.browser:browser:1.2.0'
|
||||
|
|
|
@ -206,6 +206,7 @@
|
|||
|
||||
<activity android:name=".features.terms.ReviewTermsActivity" />
|
||||
<activity android:name=".features.widgets.WidgetActivity" />
|
||||
<activity android:name=".features.pin.PinActivity" />
|
||||
|
||||
<!-- Services -->
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ import im.vector.riotx.features.disclaimer.doNotShowDisclaimerDialog
|
|||
import im.vector.riotx.features.lifecycle.VectorActivityLifecycleCallbacks
|
||||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||
import im.vector.riotx.features.notifications.NotificationUtils
|
||||
import im.vector.riotx.features.pin.PinLocker
|
||||
import im.vector.riotx.features.popup.PopupAlertManager
|
||||
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
||||
import im.vector.riotx.features.settings.VectorPreferences
|
||||
|
@ -82,6 +83,7 @@ class VectorApplication :
|
|||
@Inject lateinit var appStateHandler: AppStateHandler
|
||||
@Inject lateinit var rxConfig: RxConfig
|
||||
@Inject lateinit var popupAlertManager: PopupAlertManager
|
||||
@Inject lateinit var pinLocker: PinLocker
|
||||
|
||||
lateinit var vectorComponent: VectorComponent
|
||||
|
||||
|
@ -153,6 +155,7 @@ class VectorApplication :
|
|||
}
|
||||
})
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(appStateHandler)
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(pinLocker)
|
||||
// This should be done as early as possible
|
||||
// initKnownEmojiHashSet(appContext)
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ import im.vector.riotx.features.login.LoginSplashFragment
|
|||
import im.vector.riotx.features.login.LoginWaitForEmailFragment
|
||||
import im.vector.riotx.features.login.LoginWebFragment
|
||||
import im.vector.riotx.features.login.terms.LoginTermsFragment
|
||||
import im.vector.riotx.features.pin.PinFragment
|
||||
import im.vector.riotx.features.qrcode.QrCodeScannerFragment
|
||||
import im.vector.riotx.features.reactions.EmojiChooserFragment
|
||||
import im.vector.riotx.features.reactions.EmojiSearchResultFragment
|
||||
|
@ -536,6 +537,11 @@ interface FragmentModule {
|
|||
@FragmentKey(ContactsBookFragment::class)
|
||||
fun bindPhoneBookFragment(fragment: ContactsBookFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(PinFragment::class)
|
||||
fun bindPinFragment(fragment: PinFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomBannedMemberListFragment::class)
|
||||
|
|
|
@ -54,6 +54,7 @@ import im.vector.riotx.features.media.ImageMediaViewerActivity
|
|||
import im.vector.riotx.features.media.VideoMediaViewerActivity
|
||||
import im.vector.riotx.features.navigation.Navigator
|
||||
import im.vector.riotx.features.permalink.PermalinkHandlerActivity
|
||||
import im.vector.riotx.features.pin.PinLocker
|
||||
import im.vector.riotx.features.qrcode.QrCodeScannerActivity
|
||||
import im.vector.riotx.features.rageshake.BugReportActivity
|
||||
import im.vector.riotx.features.rageshake.BugReporter
|
||||
|
@ -101,6 +102,7 @@ interface ScreenComponent {
|
|||
fun bugReporter(): BugReporter
|
||||
fun rageShake(): RageShake
|
||||
fun navigator(): Navigator
|
||||
fun pinLocker(): PinLocker
|
||||
fun errorFormatter(): ErrorFormatter
|
||||
fun uiStateRepository(): UiStateRepository
|
||||
fun unrecognizedCertificateDialog(): UnrecognizedCertificateDialog
|
||||
|
|
|
@ -48,6 +48,8 @@ import im.vector.riotx.features.notifications.NotificationBroadcastReceiver
|
|||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||
import im.vector.riotx.features.notifications.NotificationUtils
|
||||
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
||||
import im.vector.riotx.features.pin.PinCodeStore
|
||||
import im.vector.riotx.features.pin.PinLocker
|
||||
import im.vector.riotx.features.popup.PopupAlertManager
|
||||
import im.vector.riotx.features.rageshake.BugReporter
|
||||
import im.vector.riotx.features.rageshake.VectorFileLogger
|
||||
|
@ -132,12 +134,16 @@ interface VectorComponent {
|
|||
|
||||
fun uiStateRepository(): UiStateRepository
|
||||
|
||||
fun pinCodeStore(): PinCodeStore
|
||||
|
||||
fun emojiDataSource(): EmojiDataSource
|
||||
|
||||
fun alertManager(): PopupAlertManager
|
||||
|
||||
fun reAuthHelper(): ReAuthHelper
|
||||
|
||||
fun pinLocker(): PinLocker
|
||||
|
||||
fun webRtcPeerConnectionManager(): WebRtcPeerConnectionManager
|
||||
|
||||
@Component.Factory
|
||||
|
|
|
@ -31,6 +31,8 @@ import im.vector.riotx.core.error.DefaultErrorFormatter
|
|||
import im.vector.riotx.core.error.ErrorFormatter
|
||||
import im.vector.riotx.features.navigation.DefaultNavigator
|
||||
import im.vector.riotx.features.navigation.Navigator
|
||||
import im.vector.riotx.features.pin.PinCodeStore
|
||||
import im.vector.riotx.features.pin.SharedPrefPinCodeStore
|
||||
import im.vector.riotx.features.ui.SharedPreferencesUiStateRepository
|
||||
import im.vector.riotx.features.ui.UiStateRepository
|
||||
|
||||
|
@ -86,4 +88,7 @@ abstract class VectorModule {
|
|||
|
||||
@Binds
|
||||
abstract fun bindUiStateRepository(repository: SharedPreferencesUiStateRepository): UiStateRepository
|
||||
|
||||
@Binds
|
||||
abstract fun bindPinCodeStore(store: SharedPrefPinCodeStore): PinCodeStore
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
package im.vector.riotx.core.platform
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
|
@ -58,6 +60,7 @@ import im.vector.riotx.core.dialogs.DialogLocker
|
|||
import im.vector.riotx.core.dialogs.UnrecognizedCertificateDialog
|
||||
import im.vector.riotx.core.extensions.exhaustive
|
||||
import im.vector.riotx.core.extensions.observeEvent
|
||||
import im.vector.riotx.core.extensions.observeNotNull
|
||||
import im.vector.riotx.core.extensions.vectorComponent
|
||||
import im.vector.riotx.core.utils.toast
|
||||
import im.vector.riotx.features.MainActivity
|
||||
|
@ -65,6 +68,10 @@ import im.vector.riotx.features.MainActivityArgs
|
|||
import im.vector.riotx.features.configuration.VectorConfiguration
|
||||
import im.vector.riotx.features.consent.ConsentNotGivenHelper
|
||||
import im.vector.riotx.features.navigation.Navigator
|
||||
import im.vector.riotx.features.pin.PinActivity
|
||||
import im.vector.riotx.features.pin.PinLocker
|
||||
import im.vector.riotx.features.pin.PinMode
|
||||
import im.vector.riotx.features.pin.UnlockedActivity
|
||||
import im.vector.riotx.features.rageshake.BugReportActivity
|
||||
import im.vector.riotx.features.rageshake.BugReporter
|
||||
import im.vector.riotx.features.rageshake.RageShake
|
||||
|
@ -116,6 +123,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
private lateinit var configurationViewModel: ConfigurationViewModel
|
||||
private lateinit var sessionListener: SessionListener
|
||||
protected lateinit var bugReporter: BugReporter
|
||||
private lateinit var pinLocker: PinLocker
|
||||
lateinit var rageShake: RageShake
|
||||
|
||||
lateinit var navigator: Navigator
|
||||
|
@ -181,6 +189,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
viewModelFactory = screenComponent.viewModelFactory()
|
||||
configurationViewModel = viewModelProvider.get(ConfigurationViewModel::class.java)
|
||||
bugReporter = screenComponent.bugReporter()
|
||||
pinLocker = screenComponent.pinLocker()
|
||||
// Shake detector
|
||||
rageShake = screenComponent.rageShake()
|
||||
navigator = screenComponent.navigator()
|
||||
|
@ -193,7 +202,11 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
finish()
|
||||
}
|
||||
})
|
||||
|
||||
pinLocker.getLiveState().observeNotNull(this) {
|
||||
if (this@VectorBaseActivity !is UnlockedActivity && it == PinLocker.State.LOCKED) {
|
||||
navigator.openPinCode(this, PinMode.AUTH)
|
||||
}
|
||||
}
|
||||
sessionListener = vectorComponent.sessionListener()
|
||||
sessionListener.globalErrorLiveData.observeEvent(this) {
|
||||
handleGlobalError(it)
|
||||
|
@ -285,6 +298,21 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
uiDisposables.dispose()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == PinActivity.PIN_REQUEST_CODE) {
|
||||
when (resultCode) {
|
||||
Activity.RESULT_OK -> {
|
||||
pinLocker.unlock()
|
||||
}
|
||||
else -> {
|
||||
pinLocker.block()
|
||||
moveTaskToBack(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
Timber.i("onResume Activity ${this.javaClass.simpleName}")
|
||||
|
@ -294,7 +322,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
|||
if (this !is BugReportActivity && vectorPreferences.useRageshake()) {
|
||||
rageShake.start()
|
||||
}
|
||||
|
||||
DebugReceiver
|
||||
.getIntentFilter(this)
|
||||
.takeIf { BuildConfig.DEBUG }
|
||||
|
|
|
@ -35,6 +35,9 @@ import im.vector.riotx.features.home.HomeActivity
|
|||
import im.vector.riotx.features.home.ShortcutsHandler
|
||||
import im.vector.riotx.features.login.LoginActivity
|
||||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||
import im.vector.riotx.features.pin.PinCodeStore
|
||||
import im.vector.riotx.features.pin.PinLocker
|
||||
import im.vector.riotx.features.pin.UnlockedActivity
|
||||
import im.vector.riotx.features.settings.VectorPreferences
|
||||
import im.vector.riotx.features.signout.hard.SignedOutActivity
|
||||
import im.vector.riotx.features.signout.soft.SoftLogoutActivity
|
||||
|
@ -61,7 +64,7 @@ data class MainActivityArgs(
|
|||
* This Activity, when started with argument, is also doing some cleanup when user disconnects,
|
||||
* clears cache, is logged out, or is soft logged out
|
||||
*/
|
||||
class MainActivity : VectorBaseActivity() {
|
||||
class MainActivity : VectorBaseActivity(), UnlockedActivity {
|
||||
|
||||
companion object {
|
||||
private const val EXTRA_ARGS = "EXTRA_ARGS"
|
||||
|
@ -84,6 +87,8 @@ class MainActivity : VectorBaseActivity() {
|
|||
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||
@Inject lateinit var uiStateRepository: UiStateRepository
|
||||
@Inject lateinit var shortcutsHandler: ShortcutsHandler
|
||||
@Inject lateinit var pinCodeStore: PinCodeStore
|
||||
@Inject lateinit var pinLocker: PinLocker
|
||||
|
||||
override fun injectWith(injector: ScreenComponent) {
|
||||
injector.inject(this)
|
||||
|
@ -181,6 +186,8 @@ class MainActivity : VectorBaseActivity() {
|
|||
if (clearPreferences) {
|
||||
vectorPreferences.clearPreferences()
|
||||
uiStateRepository.reset()
|
||||
pinLocker.unlock()
|
||||
pinCodeStore.deleteEncodedPin()
|
||||
}
|
||||
withContext(Dispatchers.IO) {
|
||||
// On BG thread
|
||||
|
|
|
@ -21,10 +21,10 @@ import android.content.Intent
|
|||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.lib.multipicker.MultiPicker
|
||||
import im.vector.matrix.android.BuildConfig
|
||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
import im.vector.riotx.core.platform.Restorable
|
||||
import im.vector.riotx.multipicker.MultiPicker
|
||||
import timber.log.Timber
|
||||
|
||||
private const val CAPTURE_PATH_KEY = "CAPTURE_PATH_KEY"
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
|
||||
package im.vector.riotx.features.attachments
|
||||
|
||||
import im.vector.lib.multipicker.entity.MultiPickerAudioType
|
||||
import im.vector.lib.multipicker.entity.MultiPickerBaseType
|
||||
import im.vector.lib.multipicker.entity.MultiPickerContactType
|
||||
import im.vector.lib.multipicker.entity.MultiPickerFileType
|
||||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||
import im.vector.lib.multipicker.entity.MultiPickerVideoType
|
||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerAudioType
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerBaseType
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerContactType
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerFileType
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerImageType
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerVideoType
|
||||
import timber.log.Timber
|
||||
|
||||
fun MultiPickerContactType.toContactAttachment(): ContactAttachment {
|
||||
|
|
|
@ -46,13 +46,14 @@ import im.vector.riotx.features.home.HomeActivity
|
|||
import im.vector.riotx.features.login.terms.LoginTermsFragment
|
||||
import im.vector.riotx.features.login.terms.LoginTermsFragmentArgument
|
||||
import im.vector.riotx.features.login.terms.toLocalizedLoginTerms
|
||||
import im.vector.riotx.features.pin.UnlockedActivity
|
||||
import kotlinx.android.synthetic.main.activity_login.*
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* The LoginActivity manages the fragment navigation and also display the loading View
|
||||
*/
|
||||
open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||
open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable, UnlockedActivity {
|
||||
|
||||
private val loginViewModel: LoginViewModel by viewModel()
|
||||
|
||||
|
|
|
@ -43,13 +43,13 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment
|
|||
}
|
||||
|
||||
private fun initTextViews() {
|
||||
loginServerChoiceEMSLearnMore.text = span {
|
||||
loginServerChoiceEmsLearnMore.text = span {
|
||||
text = getString(R.string.login_server_modular_learn_more)
|
||||
textDecorationLine = "underline"
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.loginServerChoiceEMSLearnMore)
|
||||
@OnClick(R.id.loginServerChoiceEmsLearnMore)
|
||||
fun learnMore() {
|
||||
openUrlInChromeCustomTab(requireActivity(), null, EMS_LINK)
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment
|
|||
loginViewModel.handle(LoginAction.UpdateServerType(ServerType.MatrixOrg))
|
||||
}
|
||||
|
||||
@OnClick(R.id.loginServerChoiceEMS)
|
||||
@OnClick(R.id.loginServerChoiceEms)
|
||||
fun selectEMS() {
|
||||
loginViewModel.handle(LoginAction.UpdateServerType(ServerType.EMS))
|
||||
}
|
||||
|
|
|
@ -25,9 +25,9 @@ import android.widget.SeekBar
|
|||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.Group
|
||||
import im.vector.lib.attachmentviewer.AttachmentEventListener
|
||||
import im.vector.lib.attachmentviewer.AttachmentEvents
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.attachmentviewer.AttachmentEventListener
|
||||
import im.vector.riotx.attachmentviewer.AttachmentEvents
|
||||
|
||||
class AttachmentOverlayView @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
|
|
|
@ -22,12 +22,12 @@ import android.view.View
|
|||
import android.widget.ImageView
|
||||
import com.bumptech.glide.request.target.CustomViewTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import im.vector.lib.attachmentviewer.AttachmentInfo
|
||||
import im.vector.lib.attachmentviewer.AttachmentSourceProvider
|
||||
import im.vector.lib.attachmentviewer.ImageLoaderTarget
|
||||
import im.vector.lib.attachmentviewer.VideoLoaderTarget
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.riotx.attachmentviewer.AttachmentInfo
|
||||
import im.vector.riotx.attachmentviewer.AttachmentSourceProvider
|
||||
import im.vector.riotx.attachmentviewer.ImageLoaderTarget
|
||||
import im.vector.riotx.attachmentviewer.VideoLoaderTarget
|
||||
import java.io.File
|
||||
|
||||
abstract class BaseAttachmentProvider(val imageContentRenderer: ImageContentRenderer, val fileService: FileService) : AttachmentSourceProvider {
|
||||
|
|
|
@ -27,6 +27,8 @@ import android.widget.Toast
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.net.toUri
|
||||
import com.yalantis.ucrop.UCrop
|
||||
import im.vector.lib.multipicker.MultiPicker
|
||||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
|
@ -37,8 +39,6 @@ import im.vector.riotx.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
|||
import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||
import im.vector.riotx.core.utils.allGranted
|
||||
import im.vector.riotx.core.utils.checkPermissions
|
||||
import im.vector.riotx.multipicker.MultiPicker
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerImageType
|
||||
import kotlinx.android.synthetic.main.activity_big_image_viewer.*
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
|
|
@ -19,11 +19,11 @@ package im.vector.riotx.features.media
|
|||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.lib.attachmentviewer.AttachmentInfo
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.events.model.isVideoMessage
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.riotx.attachmentviewer.AttachmentInfo
|
||||
import im.vector.riotx.core.date.VectorDateFormatter
|
||||
import im.vector.riotx.core.extensions.localDateTime
|
||||
import java.io.File
|
||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.riotx.features.media
|
|||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.lib.attachmentviewer.AttachmentInfo
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.events.model.isVideoMessage
|
||||
|
@ -32,7 +33,6 @@ import im.vector.matrix.android.api.session.room.model.message.MessageWithAttach
|
|||
import im.vector.matrix.android.api.session.room.model.message.getFileUrl
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt
|
||||
import im.vector.riotx.attachmentviewer.AttachmentInfo
|
||||
import im.vector.riotx.core.date.VectorDateFormatter
|
||||
import im.vector.riotx.core.extensions.localDateTime
|
||||
import java.io.File
|
||||
|
@ -147,7 +147,7 @@ class RoomEventsAttachmentProvider(
|
|||
elementToDecrypt = messageContent.encryptedFileInfo?.toElementToDecrypt(),
|
||||
callback = object : MatrixCallback<File> {
|
||||
override fun onSuccess(data: File) {
|
||||
callback(data)
|
||||
callback(data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
|
|
|
@ -30,9 +30,9 @@ import androidx.core.view.isInvisible
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.transition.Transition
|
||||
import im.vector.lib.attachmentviewer.AttachmentCommands
|
||||
import im.vector.lib.attachmentviewer.AttachmentViewerActivity
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.attachmentviewer.AttachmentCommands
|
||||
import im.vector.riotx.attachmentviewer.AttachmentViewerActivity
|
||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||
import im.vector.riotx.core.di.DaggerScreenComponent
|
||||
import im.vector.riotx.core.di.HasVectorInjector
|
||||
|
|
|
@ -52,6 +52,9 @@ import im.vector.riotx.features.invite.InviteUsersToRoomActivity
|
|||
import im.vector.riotx.features.media.AttachmentData
|
||||
import im.vector.riotx.features.media.BigImageViewerActivity
|
||||
import im.vector.riotx.features.media.VectorAttachmentViewerActivity
|
||||
import im.vector.riotx.features.pin.PinActivity
|
||||
import im.vector.riotx.features.pin.PinArgs
|
||||
import im.vector.riotx.features.pin.PinMode
|
||||
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
|
||||
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomActivity
|
||||
import im.vector.riotx.features.roomdirectory.roompreview.RoomPreviewActivity
|
||||
|
@ -272,6 +275,16 @@ class DefaultNavigator @Inject constructor(
|
|||
context.startActivity(WidgetActivity.newIntent(context, widgetArgs))
|
||||
}
|
||||
|
||||
override fun openPinCode(fragment: Fragment, pinMode: PinMode, requestCode: Int) {
|
||||
val intent = PinActivity.newIntent(fragment.requireContext(), PinArgs(pinMode))
|
||||
fragment.startActivityForResult(intent, requestCode)
|
||||
}
|
||||
|
||||
override fun openPinCode(activity: Activity, pinMode: PinMode, requestCode: Int) {
|
||||
val intent = PinActivity.newIntent(activity, PinArgs(pinMode))
|
||||
activity.startActivityForResult(intent, requestCode)
|
||||
}
|
||||
|
||||
override fun openMediaViewer(activity: Activity,
|
||||
roomId: String,
|
||||
mediaData: AttachmentData,
|
||||
|
|
|
@ -28,6 +28,8 @@ import im.vector.matrix.android.api.session.widgets.model.Widget
|
|||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.riotx.features.home.room.detail.widget.WidgetRequestCodes
|
||||
import im.vector.riotx.features.media.AttachmentData
|
||||
import im.vector.riotx.features.pin.PinActivity
|
||||
import im.vector.riotx.features.pin.PinMode
|
||||
import im.vector.riotx.features.settings.VectorSettingsActivity
|
||||
import im.vector.riotx.features.share.SharedData
|
||||
import im.vector.riotx.features.terms.ReviewTermsActivity
|
||||
|
@ -78,6 +80,10 @@ interface Navigator {
|
|||
|
||||
fun openBigImageViewer(activity: Activity, sharedElement: View?, matrixItem: MatrixItem)
|
||||
|
||||
fun openPinCode(fragment: Fragment, pinMode: PinMode, requestCode: Int = PinActivity.PIN_REQUEST_CODE)
|
||||
|
||||
fun openPinCode(activity: Activity, pinMode: PinMode, requestCode: Int = PinActivity.PIN_REQUEST_CODE)
|
||||
|
||||
fun openTerms(fragment: Fragment,
|
||||
serviceType: TermsService.ServiceType,
|
||||
baseUrl: String,
|
||||
|
|
|
@ -46,6 +46,7 @@ import im.vector.riotx.features.call.service.CallHeadsUpActionReceiver
|
|||
import im.vector.riotx.features.home.HomeActivity
|
||||
import im.vector.riotx.features.home.room.detail.RoomDetailActivity
|
||||
import im.vector.riotx.features.home.room.detail.RoomDetailArgs
|
||||
import im.vector.riotx.features.pin.PinLocker
|
||||
import im.vector.riotx.features.settings.VectorPreferences
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
@ -59,6 +60,7 @@ import kotlin.random.Random
|
|||
@Singleton
|
||||
class NotificationUtils @Inject constructor(private val context: Context,
|
||||
private val stringProvider: StringProvider,
|
||||
private val pinLocker: PinLocker,
|
||||
private val vectorPreferences: VectorPreferences) {
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.pin
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.addFragment
|
||||
import im.vector.riotx.core.platform.ToolbarConfigurable
|
||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
|
||||
class PinActivity : VectorBaseActivity(), ToolbarConfigurable, UnlockedActivity {
|
||||
|
||||
companion object {
|
||||
|
||||
const val PIN_REQUEST_CODE = 17890
|
||||
|
||||
fun newIntent(context: Context, args: PinArgs): Intent {
|
||||
return Intent(context, PinActivity::class.java).apply {
|
||||
putExtra(MvRx.KEY_ARG, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_simple
|
||||
|
||||
override fun initUiAndData() {
|
||||
if (isFirstCreation()) {
|
||||
val fragmentArgs: PinArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return
|
||||
addFragment(R.id.simpleFragmentContainer, PinFragment::class.java, fragmentArgs)
|
||||
}
|
||||
}
|
||||
|
||||
override fun configure(toolbar: Toolbar) {
|
||||
configureToolbar(toolbar)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.pin
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import com.beautycoder.pflockscreen.security.PFResult
|
||||
import com.beautycoder.pflockscreen.security.PFSecurityManager
|
||||
import com.beautycoder.pflockscreen.security.callbacks.PFPinCodeHelperCallback
|
||||
import im.vector.matrix.android.api.extensions.orFalse
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
interface PinCodeStore {
|
||||
|
||||
suspend fun storeEncodedPin(encodePin: String)
|
||||
|
||||
suspend fun deleteEncodedPin()
|
||||
|
||||
fun getEncodedPin(): String?
|
||||
|
||||
suspend fun hasEncodedPin(): Boolean
|
||||
}
|
||||
|
||||
class SharedPrefPinCodeStore @Inject constructor(private val sharedPreferences: SharedPreferences) : PinCodeStore {
|
||||
|
||||
override suspend fun storeEncodedPin(encodePin: String) = withContext(Dispatchers.IO) {
|
||||
sharedPreferences.edit {
|
||||
putString(ENCODED_PIN_CODE_KEY, encodePin)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteEncodedPin() = withContext(Dispatchers.IO) {
|
||||
sharedPreferences.edit {
|
||||
remove(ENCODED_PIN_CODE_KEY)
|
||||
}
|
||||
awaitPinCodeCallback<Boolean> {
|
||||
PFSecurityManager.getInstance().pinCodeHelper.delete(it)
|
||||
}
|
||||
return@withContext
|
||||
}
|
||||
|
||||
override fun getEncodedPin(): String? {
|
||||
return sharedPreferences.getString(ENCODED_PIN_CODE_KEY, null)
|
||||
}
|
||||
|
||||
override suspend fun hasEncodedPin(): Boolean = withContext(Dispatchers.IO) {
|
||||
val hasEncodedPin = getEncodedPin()?.isNotBlank().orFalse()
|
||||
if (!hasEncodedPin) {
|
||||
return@withContext false
|
||||
}
|
||||
val result = awaitPinCodeCallback<Boolean> {
|
||||
PFSecurityManager.getInstance().pinCodeHelper.isPinCodeEncryptionKeyExist(it)
|
||||
}
|
||||
result.error == null && result.result
|
||||
}
|
||||
|
||||
private suspend inline fun <T> awaitPinCodeCallback(crossinline callback: (PFPinCodeHelperCallback<T>) -> Unit) = suspendCoroutine<PFResult<T>> { cont ->
|
||||
callback(PFPinCodeHelperCallback<T> { result -> cont.resume(result) })
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ENCODED_PIN_CODE_KEY = "ENCODED_PIN_CODE_KEY"
|
||||
}
|
||||
}
|
169
vector/src/main/java/im/vector/riotx/features/pin/PinFragment.kt
Normal file
169
vector/src/main/java/im/vector/riotx/features/pin/PinFragment.kt
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.pin
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.airbnb.mvrx.args
|
||||
import com.beautycoder.pflockscreen.PFFLockScreenConfiguration
|
||||
import com.beautycoder.pflockscreen.fragments.PFLockScreenFragment
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.replaceFragment
|
||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
import im.vector.riotx.features.MainActivity
|
||||
import im.vector.riotx.features.MainActivityArgs
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@Parcelize
|
||||
data class PinArgs(
|
||||
val pinMode: PinMode
|
||||
) : Parcelable
|
||||
|
||||
class PinFragment @Inject constructor(
|
||||
private val pinCodeStore: PinCodeStore
|
||||
) : VectorBaseFragment() {
|
||||
|
||||
private val fragmentArgs: PinArgs by args()
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_pin
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
when (fragmentArgs.pinMode) {
|
||||
PinMode.CREATE -> showCreateFragment()
|
||||
PinMode.DELETE -> showDeleteFragment()
|
||||
PinMode.AUTH -> showAuthFragment()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDeleteFragment() {
|
||||
val encodedPin = pinCodeStore.getEncodedPin() ?: return
|
||||
val authFragment = PFLockScreenFragment()
|
||||
val builder = PFFLockScreenConfiguration.Builder(requireContext())
|
||||
.setUseFingerprint(true)
|
||||
.setTitle(getString(R.string.auth_pin_confirm_to_disable_title))
|
||||
.setClearCodeOnError(true)
|
||||
.setMode(PFFLockScreenConfiguration.MODE_AUTH)
|
||||
authFragment.setConfiguration(builder.build())
|
||||
authFragment.setEncodedPinCode(encodedPin)
|
||||
authFragment.setLoginListener(object : PFLockScreenFragment.OnPFLockScreenLoginListener {
|
||||
override fun onPinLoginFailed() {
|
||||
}
|
||||
|
||||
override fun onFingerprintSuccessful() {
|
||||
lifecycleScope.launch {
|
||||
pinCodeStore.deleteEncodedPin()
|
||||
vectorBaseActivity.setResult(Activity.RESULT_OK)
|
||||
vectorBaseActivity.finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFingerprintLoginFailed() {
|
||||
}
|
||||
|
||||
override fun onCodeInputSuccessful() {
|
||||
lifecycleScope.launch {
|
||||
pinCodeStore.deleteEncodedPin()
|
||||
vectorBaseActivity.setResult(Activity.RESULT_OK)
|
||||
vectorBaseActivity.finish()
|
||||
}
|
||||
}
|
||||
})
|
||||
replaceFragment(R.id.pinFragmentContainer, authFragment)
|
||||
}
|
||||
|
||||
private fun showCreateFragment() {
|
||||
val createFragment = PFLockScreenFragment()
|
||||
val builder = PFFLockScreenConfiguration.Builder(requireContext())
|
||||
.setNewCodeValidation(true)
|
||||
.setTitle(getString(R.string.create_pin_title))
|
||||
.setNewCodeValidationTitle(getString(R.string.create_pin_confirm_title))
|
||||
.setMode(PFFLockScreenConfiguration.MODE_CREATE)
|
||||
|
||||
createFragment.setConfiguration(builder.build())
|
||||
createFragment.setCodeCreateListener(object : PFLockScreenFragment.OnPFLockScreenCodeCreateListener {
|
||||
override fun onNewCodeValidationFailed() {
|
||||
Toast.makeText(requireContext(), getString(R.string.create_pin_confirm_failure), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
override fun onCodeCreated(encodedCode: String) {
|
||||
lifecycleScope.launch {
|
||||
pinCodeStore.storeEncodedPin(encodedCode)
|
||||
vectorBaseActivity.setResult(Activity.RESULT_OK)
|
||||
vectorBaseActivity.finish()
|
||||
}
|
||||
}
|
||||
})
|
||||
replaceFragment(R.id.pinFragmentContainer, createFragment)
|
||||
}
|
||||
|
||||
private fun showAuthFragment() {
|
||||
val encodedPin = pinCodeStore.getEncodedPin() ?: return
|
||||
val authFragment = PFLockScreenFragment()
|
||||
val builder = PFFLockScreenConfiguration.Builder(requireContext())
|
||||
.setUseFingerprint(true)
|
||||
.setTitle(getString(R.string.auth_pin_title))
|
||||
.setLeftButton(getString(R.string.auth_pin_forgot))
|
||||
.setClearCodeOnError(true)
|
||||
.setMode(PFFLockScreenConfiguration.MODE_AUTH)
|
||||
authFragment.setConfiguration(builder.build())
|
||||
authFragment.setEncodedPinCode(encodedPin)
|
||||
authFragment.setOnLeftButtonClickListener {
|
||||
displayForgotPinWarningDialog()
|
||||
}
|
||||
authFragment.setLoginListener(object : PFLockScreenFragment.OnPFLockScreenLoginListener {
|
||||
override fun onPinLoginFailed() {
|
||||
}
|
||||
|
||||
override fun onFingerprintSuccessful() {
|
||||
vectorBaseActivity.setResult(Activity.RESULT_OK)
|
||||
vectorBaseActivity.finish()
|
||||
}
|
||||
|
||||
override fun onFingerprintLoginFailed() {
|
||||
}
|
||||
|
||||
override fun onCodeInputSuccessful() {
|
||||
vectorBaseActivity.setResult(Activity.RESULT_OK)
|
||||
vectorBaseActivity.finish()
|
||||
}
|
||||
})
|
||||
replaceFragment(R.id.pinFragmentContainer, authFragment)
|
||||
}
|
||||
|
||||
private fun displayForgotPinWarningDialog() {
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(getString(R.string.auth_pin_reset_title))
|
||||
.setMessage(getString(R.string.auth_pin_reset_content))
|
||||
.setPositiveButton(getString(R.string.auth_pin_new_pin_action)) { _, _ ->
|
||||
launchResetPinFlow()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun launchResetPinFlow() {
|
||||
MainActivity.restartApp(requireActivity(), MainActivityArgs(clearCredentials = true))
|
||||
}
|
||||
}
|
103
vector/src/main/java/im/vector/riotx/features/pin/PinLocker.kt
Normal file
103
vector/src/main/java/im/vector/riotx/features/pin/PinLocker.kt
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.pin
|
||||
|
||||
import android.os.SystemClock
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
private const val PERIOD_OF_GRACE_IN_MS = 2 * 60 * 1000L
|
||||
|
||||
/**
|
||||
* This class is responsible for keeping the status of locking
|
||||
* It automatically locks when entering background/foreground with a grace period.
|
||||
* You can force to unlock with unlock method, use it whenever the pin code has been validated.
|
||||
*/
|
||||
|
||||
@Singleton
|
||||
class PinLocker @Inject constructor(private val pinCodeStore: PinCodeStore) : LifecycleObserver {
|
||||
|
||||
enum class State {
|
||||
// App is locked, can be unlock
|
||||
LOCKED,
|
||||
|
||||
// App is blocked and can't be unlocked as long as the app is in foreground
|
||||
BLOCKED,
|
||||
|
||||
// is unlocked, the app can be used
|
||||
UNLOCKED
|
||||
}
|
||||
|
||||
private val liveState = MutableLiveData<State>()
|
||||
|
||||
private var isBlocked = false
|
||||
private var shouldBeLocked = true
|
||||
private var entersBackgroundTs = 0L
|
||||
|
||||
fun getLiveState(): LiveData<State> {
|
||||
return liveState
|
||||
}
|
||||
|
||||
private fun computeState() {
|
||||
GlobalScope.launch {
|
||||
val state = if (isBlocked) {
|
||||
State.BLOCKED
|
||||
} else if (shouldBeLocked && pinCodeStore.hasEncodedPin()) {
|
||||
State.LOCKED
|
||||
} else {
|
||||
State.UNLOCKED
|
||||
}
|
||||
if (liveState.value != state) {
|
||||
liveState.postValue(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun unlock() {
|
||||
Timber.v("Unlock app")
|
||||
shouldBeLocked = false
|
||||
computeState()
|
||||
}
|
||||
|
||||
fun block() {
|
||||
Timber.v("Block app")
|
||||
isBlocked = true
|
||||
computeState()
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
fun entersForeground() {
|
||||
val timeElapsedSinceBackground = SystemClock.elapsedRealtime() - entersBackgroundTs
|
||||
shouldBeLocked = shouldBeLocked || timeElapsedSinceBackground >= PERIOD_OF_GRACE_IN_MS
|
||||
Timber.v("App enters foreground after $timeElapsedSinceBackground ms spent in background")
|
||||
computeState()
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
fun entersBackground() {
|
||||
isBlocked = false
|
||||
entersBackgroundTs = SystemClock.elapsedRealtime()
|
||||
}
|
||||
}
|
23
vector/src/main/java/im/vector/riotx/features/pin/PinMode.kt
Normal file
23
vector/src/main/java/im/vector/riotx/features/pin/PinMode.kt
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.pin
|
||||
|
||||
enum class PinMode {
|
||||
CREATE,
|
||||
DELETE,
|
||||
AUTH
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.pin
|
||||
|
||||
/**
|
||||
* Tag class for activities that should not be protected by PIN code.
|
||||
*/
|
||||
interface UnlockedActivity
|
|
@ -28,6 +28,7 @@ import dagger.Lazy
|
|||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.pin.PinActivity
|
||||
import im.vector.riotx.features.themes.ThemeUtils
|
||||
import timber.log.Timber
|
||||
import java.lang.ref.WeakReference
|
||||
|
@ -84,12 +85,10 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<Ava
|
|||
setLightStatusBar()
|
||||
}
|
||||
}
|
||||
if (currentAlerter?.shouldBeDisplayedIn?.invoke(activity) == false || activity !is VectorBaseActivity) {
|
||||
weakCurrentActivity = WeakReference(activity)
|
||||
if (!shouldBeDisplayedIn(currentAlerter, activity)) {
|
||||
return
|
||||
}
|
||||
|
||||
weakCurrentActivity = WeakReference(activity)
|
||||
|
||||
if (currentAlerter != null) {
|
||||
if (currentAlerter!!.expirationTimestamp != null && System.currentTimeMillis() > currentAlerter!!.expirationTimestamp!!) {
|
||||
// this alert has expired, remove it
|
||||
|
@ -126,7 +125,7 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<Ava
|
|||
}
|
||||
currentAlerter = next
|
||||
next?.let {
|
||||
if (next.shouldBeDisplayedIn?.invoke(currentActivity) == false) return
|
||||
if (!shouldBeDisplayedIn(next, currentActivity)) return
|
||||
val currentTime = System.currentTimeMillis()
|
||||
if (next.expirationTimestamp != null && currentTime > next.expirationTimestamp!!) {
|
||||
// skip
|
||||
|
@ -250,4 +249,11 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<Ava
|
|||
displayNextIfPossible()
|
||||
}, 500)
|
||||
}
|
||||
|
||||
private fun shouldBeDisplayedIn(alert: VectorAlert?, activity: Activity): Boolean {
|
||||
return alert != null
|
||||
&& activity !is PinActivity
|
||||
&& activity is VectorBaseActivity
|
||||
&& alert.shouldBeDisplayedIn?.invoke(activity) == true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,8 +104,11 @@ class CreateRoomController @Inject constructor(private val stringProvider: Strin
|
|||
enabled(enableFormElement)
|
||||
title(stringProvider.getString(R.string.create_room_encryption_title))
|
||||
summary(
|
||||
if (viewState.hsAdminHasDisabledE2E) stringProvider.getString(R.string.settings_hs_admin_e2e_disabled)
|
||||
else stringProvider.getString(R.string.create_room_encryption_description)
|
||||
if (viewState.hsAdminHasDisabledE2E) {
|
||||
stringProvider.getString(R.string.settings_hs_admin_e2e_disabled)
|
||||
} else {
|
||||
stringProvider.getString(R.string.create_room_encryption_description)
|
||||
}
|
||||
)
|
||||
switchChecked(viewState.isEncrypted)
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ import com.airbnb.mvrx.args
|
|||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.yalantis.ucrop.UCrop
|
||||
import im.vector.lib.multipicker.MultiPicker
|
||||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.matrix.android.api.util.toMatrixItem
|
||||
|
@ -60,8 +62,6 @@ import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsShare
|
|||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
||||
import im.vector.riotx.features.media.BigImageViewerActivity
|
||||
import im.vector.riotx.features.media.createUCropWithDefaultSettings
|
||||
import im.vector.riotx.multipicker.MultiPicker
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerImageType
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
|
||||
import kotlinx.android.synthetic.main.view_stub_room_profile_header.*
|
||||
|
|
|
@ -51,42 +51,46 @@ class RoomBannedMemberListController @Inject constructor(
|
|||
override fun buildModels(data: RoomBannedMemberListViewState?) {
|
||||
val bannedList = data?.bannedMemberSummaries?.invoke() ?: return
|
||||
|
||||
buildProfileSection(
|
||||
stringProvider.getString(R.string.room_settings_banned_users_title)
|
||||
)
|
||||
val quantityString = stringProvider.getQuantityString(R.plurals.room_settings_banned_users_count, bannedList.size, bannedList.size)
|
||||
|
||||
bannedList.join(
|
||||
each = { _, roomMember ->
|
||||
val actionInProgress = data.onGoingModerationAction.contains(roomMember.userId)
|
||||
profileMatrixItemWithProgress {
|
||||
id(roomMember.userId)
|
||||
matrixItem(roomMember.toMatrixItem())
|
||||
avatarRenderer(avatarRenderer)
|
||||
apply {
|
||||
if (actionInProgress) {
|
||||
inProgress(true)
|
||||
editable(false)
|
||||
} else {
|
||||
inProgress(false)
|
||||
editable(true)
|
||||
clickListener { _ ->
|
||||
callback?.onUnbanClicked(roomMember)
|
||||
if (bannedList.isEmpty()) {
|
||||
buildProfileSection(stringProvider.getString(R.string.room_settings_banned_users_title))
|
||||
|
||||
genericFooterItem {
|
||||
id("footer")
|
||||
text(quantityString)
|
||||
}
|
||||
} else {
|
||||
buildProfileSection(quantityString)
|
||||
|
||||
bannedList.join(
|
||||
each = { _, roomMember ->
|
||||
val actionInProgress = data.onGoingModerationAction.contains(roomMember.userId)
|
||||
profileMatrixItemWithProgress {
|
||||
id(roomMember.userId)
|
||||
matrixItem(roomMember.toMatrixItem())
|
||||
avatarRenderer(avatarRenderer)
|
||||
apply {
|
||||
if (actionInProgress) {
|
||||
inProgress(true)
|
||||
editable(false)
|
||||
} else {
|
||||
inProgress(false)
|
||||
editable(true)
|
||||
clickListener { _ ->
|
||||
callback?.onUnbanClicked(roomMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
between = { _, roomMemberBefore ->
|
||||
dividerItem {
|
||||
id("divider_${roomMemberBefore.userId}")
|
||||
color(dividerColor)
|
||||
}
|
||||
}
|
||||
},
|
||||
between = { _, roomMemberBefore ->
|
||||
dividerItem {
|
||||
id("divider_${roomMemberBefore.userId}")
|
||||
color(dividerColor)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
genericFooterItem {
|
||||
id("footer")
|
||||
text(stringProvider.getQuantityString(R.plurals.room_settings_banned_users_count, bannedList.size, bannedList.size))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,6 +161,7 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
|||
|
||||
// Security
|
||||
const val SETTINGS_SECURITY_USE_FLAG_SECURE = "SETTINGS_SECURITY_USE_FLAG_SECURE"
|
||||
const val SETTINGS_SECURITY_USE_PIN_CODE_FLAG = "SETTINGS_SECURITY_USE_PIN_CODE_FLAG"
|
||||
|
||||
// other
|
||||
const val SETTINGS_MEDIA_SAVING_PERIOD_KEY = "SETTINGS_MEDIA_SAVING_PERIOD_KEY"
|
||||
|
@ -817,4 +818,11 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
|||
fun singleOverview(): Boolean {
|
||||
return defaultPrefs.getBoolean(SETTINGS_SINGLE_OVERVIEW, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* The user enable protecting app access with pin code
|
||||
*/
|
||||
fun useFlagPinCode(): Boolean {
|
||||
return defaultPrefs.getBoolean(SETTINGS_SECURITY_USE_PIN_CODE_FLAG, false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ import com.bumptech.glide.load.engine.cache.DiskCache
|
|||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.yalantis.ucrop.UCrop
|
||||
import im.vector.lib.multipicker.MultiPicker
|
||||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.NoOpMatrixCallback
|
||||
import im.vector.matrix.android.api.failure.isInvalidPassword
|
||||
|
@ -66,8 +68,6 @@ import im.vector.riotx.features.MainActivityArgs
|
|||
import im.vector.riotx.features.media.createUCropWithDefaultSettings
|
||||
import im.vector.riotx.features.themes.ThemeUtils
|
||||
import im.vector.riotx.features.workers.signout.SignOutUiWorker
|
||||
import im.vector.riotx.multipicker.MultiPicker
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerImageType
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.widget.TextView
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.SwitchPreference
|
||||
|
@ -56,6 +57,11 @@ import im.vector.riotx.features.crypto.keys.KeysExporter
|
|||
import im.vector.riotx.features.crypto.keys.KeysImporter
|
||||
import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
||||
import im.vector.riotx.features.crypto.recover.BootstrapBottomSheet
|
||||
import im.vector.riotx.features.navigation.Navigator
|
||||
import im.vector.riotx.features.pin.PinActivity
|
||||
import im.vector.riotx.features.pin.PinCodeStore
|
||||
import im.vector.riotx.features.pin.PinLocker
|
||||
import im.vector.riotx.features.pin.PinMode
|
||||
import im.vector.riotx.features.themes.ThemeUtils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
|
@ -64,7 +70,10 @@ import javax.inject.Inject
|
|||
|
||||
class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
||||
private val vectorPreferences: VectorPreferences,
|
||||
private val activeSessionHolder: ActiveSessionHolder
|
||||
private val pinLocker: PinLocker,
|
||||
private val activeSessionHolder: ActiveSessionHolder,
|
||||
private val pinCodeStore: PinCodeStore,
|
||||
private val navigator: Navigator
|
||||
) : VectorSettingsBaseFragment() {
|
||||
|
||||
override var titleRes = R.string.settings_security_and_privacy
|
||||
|
@ -101,6 +110,10 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
findPreference<SwitchPreference>(VectorPreferences.SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY)!!
|
||||
}
|
||||
|
||||
private val usePinCodePref by lazy {
|
||||
findPreference<SwitchPreference>(VectorPreferences.SETTINGS_SECURITY_USE_PIN_CODE_FLAG)!!
|
||||
}
|
||||
|
||||
override fun onCreateRecyclerView(inflater: LayoutInflater?, parent: ViewGroup?, savedInstanceState: Bundle?): RecyclerView {
|
||||
return super.onCreateRecyclerView(inflater, parent, savedInstanceState).also {
|
||||
// Insert animation are really annoying the first time the list is shown
|
||||
|
@ -231,6 +244,8 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
refreshPinCodeStatus()
|
||||
|
||||
refreshXSigningStatus()
|
||||
|
||||
secureBackupPreference.icon = activity?.let {
|
||||
|
@ -313,10 +328,28 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
|
|||
})
|
||||
}
|
||||
}
|
||||
} else if (requestCode == PinActivity.PIN_REQUEST_CODE) {
|
||||
pinLocker.unlock()
|
||||
refreshPinCodeStatus()
|
||||
} else if (requestCode == REQUEST_E2E_FILE_REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
importKeys(data)
|
||||
}
|
||||
}
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
REQUEST_E2E_FILE_REQUEST_CODE -> importKeys(data)
|
||||
}
|
||||
|
||||
private fun refreshPinCodeStatus() {
|
||||
lifecycleScope.launchWhenResumed {
|
||||
val hasPinCode = pinCodeStore.hasEncodedPin()
|
||||
usePinCodePref.isChecked = hasPinCode
|
||||
usePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
val pinMode = if (hasPinCode) {
|
||||
PinMode.DELETE
|
||||
} else {
|
||||
PinMode.CREATE
|
||||
}
|
||||
navigator.openPinCode(this@VectorSettingsSecurityPrivacyFragment, pinMode)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
13
vector/src/main/res/drawable/bg_pin_key.xml
Normal file
13
vector/src/main/res/drawable/bg_pin_key.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="?attr/colorControlHighlight">
|
||||
<item
|
||||
android:gravity="center">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="#44FFFFFF" />
|
||||
<size
|
||||
android:width="70dp"
|
||||
android:height="70dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
13
vector/src/main/res/drawable/pin_code_dot_empty.xml
Normal file
13
vector/src/main/res/drawable/pin_code_dot_empty.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
|
||||
<stroke
|
||||
android:color="?riotx_text_secondary"
|
||||
android:width="1px"/>
|
||||
|
||||
<size
|
||||
android:width="24dp"
|
||||
android:height="24dp"/>
|
||||
</shape>
|
12
vector/src/main/res/drawable/pin_code_dot_fill.xml
Normal file
12
vector/src/main/res/drawable/pin_code_dot_fill.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
|
||||
<solid
|
||||
android:color="?colorPrimary"/>
|
||||
|
||||
<size
|
||||
android:width="24dp"
|
||||
android:height="24dp"/>
|
||||
</shape>
|
9
vector/src/main/res/drawable/pin_code_dots.xml
Normal file
9
vector/src/main/res/drawable/pin_code_dots.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- NOTE: order is important (the first matching state(s) is what is rendered) -->
|
||||
<item
|
||||
android:state_checked="true"
|
||||
android:drawable="@drawable/pin_code_dot_fill"/>
|
||||
<item
|
||||
android:drawable="@drawable/pin_code_dot_empty"/>
|
||||
</selector>
|
|
@ -172,7 +172,7 @@
|
|||
</im.vector.riotx.core.platform.CheckableConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/loginServerChoiceEMS"
|
||||
android:id="@+id/loginServerChoiceEms"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||
|
@ -187,19 +187,19 @@
|
|||
app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceMatrixOrg">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/loginServerChoiceEMSIcon"
|
||||
android:id="@+id/loginServerChoiceEmsIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_logo_element_matrix_services"
|
||||
android:tint="?riotx_text_primary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/loginServerChoiceEMSText"
|
||||
app:layout_constraintBottom_toTopOf="@+id/loginServerChoiceEmsText"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginServerChoiceEMSText"
|
||||
android:id="@+id/loginServerChoiceEmsText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="7dp"
|
||||
|
@ -207,25 +207,68 @@
|
|||
android:text="@string/login_server_modular_text"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Text.Small"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/loginServerChoiceEMSLearnMore"
|
||||
app:layout_constraintEnd_toStartOf="@+id/loginServerChoiceEmsLearnMore"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceEMSIcon" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceEmsIcon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginServerChoiceEMSLearnMore"
|
||||
android:id="@+id/loginServerChoiceEmsLearnMore"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:text="@string/login_server_modular_learn_more"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Text.Small"
|
||||
android:textColor="?colorAccent"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/loginServerChoiceEMSText"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/loginServerChoiceEmsText"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/loginServerChoiceEMSText" />
|
||||
app:layout_constraintTop_toTopOf="@+id/loginServerChoiceEmsText" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<!--
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/loginServerChoiceOther"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_vertical_margin"
|
||||
android:background="@drawable/bg_login_server_selector"
|
||||
android:contentDescription="@string/login_a11y_choose_other"
|
||||
android:minHeight="80dp"
|
||||
android:paddingStart="@dimen/layout_horizontal_margin"
|
||||
android:paddingEnd="@dimen/layout_horizontal_margin"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceEms">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginServerChoiceOtherTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start"
|
||||
android:text="@string/login_server_other_title"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Text"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/loginServerChoiceOtherText"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginServerChoiceOtherText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="start"
|
||||
android:text="@string/login_server_other_text"
|
||||
android:textAppearance="@style/TextAppearance.Vector.Login.Text.Small"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/loginServerChoiceOtherTitle" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/loginServerIKnowMyIdSubmit"
|
||||
style="@style/Style.Vector.Login.Button.Text"
|
||||
|
|
18
vector/src/main/res/layout/fragment_pin.xml
Normal file
18
vector/src/main/res/layout/fragment_pin.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/rootConstraintLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/pinFragmentContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -2573,4 +2573,15 @@ Not all features in Riot are implemented in SchildiChat yet. Main missing (and c
|
|||
|
||||
<string name="alert_push_are_disabled_title">Push notifications are disabled</string>
|
||||
<string name="alert_push_are_disabled_description">Review your settings to enable push notifications</string>
|
||||
<string name="create_pin_title">Choose a PIN for security</string>
|
||||
<string name="create_pin_confirm_title">Confirm PIN</string>
|
||||
<string name="create_pin_confirm_failure">Failed to validate pin, please tap a new one.</string>
|
||||
<string name="auth_pin_title">Enter your PIN</string>
|
||||
<string name="auth_pin_forgot">Forgot PIN?</string>
|
||||
<string name="auth_pin_reset_title">Reset pin</string>
|
||||
<string name="auth_pin_new_pin_action">New pin</string>
|
||||
<string name="auth_pin_reset_content">To reset your PIN, you\'ll need to re-login and create a new one.</string>
|
||||
<string name="settings_security_pin_code_title">Enable PIN</string>
|
||||
<string name="settings_security_pin_code_summary">If you want to reset your PIN, tap Forgot PIN to logout and reset.</string>
|
||||
<string name="auth_pin_confirm_to_disable_title">Confirm PIN to disable PIN</string>
|
||||
</resources>
|
||||
|
|
44
vector/src/main/res/values/styles_pin_code.xml
Normal file
44
vector/src/main/res/values/styles_pin_code.xml
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="PinCodeScreenStyle" >
|
||||
<item name="android:background">?riotx_background</item>
|
||||
</style>
|
||||
|
||||
<style name="PinCodeKeyButtonStyle">
|
||||
<item name="android:textColor">?riotx_text_primary</item>
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:background">@drawable/bg_pin_key</item>
|
||||
</style>
|
||||
|
||||
<style name="PinCodeDotsViewStyle">
|
||||
<item name="android:button">@drawable/pin_code_dots</item>
|
||||
</style>
|
||||
|
||||
<style name="PinCodeNextButtonStyle" parent="VectorButtonStylePositive">
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:backgroundTint">@android:color/transparent</item>
|
||||
<item name="android:layout_marginBottom">24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="PinCodeDeleteButtonStyle">
|
||||
<item name="android:src">@drawable/delete_lockscreen_pf</item>
|
||||
<item name="android:tint">?riotx_text_primary</item>
|
||||
<item name="background">@drawable/bg_pin_key</item>
|
||||
</style>
|
||||
|
||||
<style name="PinCodeFingerprintButtonStyle">
|
||||
<item name="android:src">@drawable/fingerprint_lockscreen_pf</item>
|
||||
<item name="android:tint">?riotx_text_primary</item>
|
||||
<item name="background">@drawable/bg_pin_key</item>
|
||||
</style>
|
||||
|
||||
<style name="PinCodeTitleStyle">
|
||||
<item name="android:textColor">?riotx_text_primary</item>
|
||||
</style>
|
||||
|
||||
<style name="PinCodeHintStyle">
|
||||
<item name="android:textColor">?riotx_text_primary</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
|
@ -223,11 +223,21 @@
|
|||
<!-- Style to use for message text within a SnackBar in this theme. -->
|
||||
<item name="snackbarTextViewStyle">@style/VectorSnackBarText</item>
|
||||
|
||||
<item name="pf_lock_screen">@style/PinCodeScreenStyle</item>
|
||||
<item name="pf_key_button">@style/PinCodeKeyButtonStyle</item>
|
||||
<item name="pf_title">@style/PinCodeTitleStyle</item>
|
||||
<item name="pf_hint">@style/PinCodeHintStyle</item>
|
||||
<item name="pf_code_view">@style/PinCodeDotsViewStyle</item>
|
||||
<item name="pf_delete_button">@style/PinCodeDeleteButtonStyle</item>
|
||||
<item name="pf_fingerprint_button">@style/PinCodeFingerprintButtonStyle</item>
|
||||
<item name="pf_next">@style/PinCodeNextButtonStyle</item>
|
||||
|
||||
<item name="sc_message_bg_incoming">#FF465561</item>
|
||||
<item name="sc_message_bg_outgoing">#ff343b47</item>
|
||||
<item name="riotx_positive_accent">@color/riotx_positive_accent</item>
|
||||
<item name="riotx_positive_accent_alpha12">@color/riotx_positive_accent_alpha12</item>
|
||||
<item name="riotx_toolbar_bg">?riotx_background</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Dark" parent="AppTheme.Base.Dark" />
|
||||
|
|
|
@ -223,11 +223,21 @@
|
|||
<!-- Style to use for message text within a SnackBar in this theme. -->
|
||||
<item name="snackbarTextViewStyle">@style/VectorSnackBarText</item>
|
||||
|
||||
<item name="pf_lock_screen">@style/PinCodeScreenStyle</item>
|
||||
<item name="pf_key_button">@style/PinCodeKeyButtonStyle</item>
|
||||
<item name="pf_title">@style/PinCodeTitleStyle</item>
|
||||
<item name="pf_hint">@style/PinCodeHintStyle</item>
|
||||
<item name="pf_code_view">@style/PinCodeDotsViewStyle</item>
|
||||
<item name="pf_delete_button">@style/PinCodeDeleteButtonStyle</item>
|
||||
<item name="pf_fingerprint_button">@style/PinCodeFingerprintButtonStyle</item>
|
||||
<item name="pf_next">@style/PinCodeNextButtonStyle</item>
|
||||
|
||||
<item name="sc_message_bg_incoming">#FFEEEEEE</item>
|
||||
<item name="sc_message_bg_outgoing">#FFDDDDDD</item>
|
||||
<item name="riotx_positive_accent">@color/riotx_positive_accent</item>
|
||||
<item name="riotx_positive_accent_alpha12">@color/riotx_positive_accent_alpha12</item>
|
||||
<item name="riotx_toolbar_bg">?riotx_background</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Light" parent="AppTheme.Base.Light" />
|
||||
|
|
|
@ -29,9 +29,9 @@
|
|||
<item name="riotx_waiting_background_color">@color/riotx_waiting_background_color_status</item>
|
||||
|
||||
<!-- application bar text color -->
|
||||
<item name="vctr_toolbar_primary_text_color">#FFFFFFFF</item>
|
||||
<item name="vctr_toolbar_secondary_text_color">#FFD8D8D8</item>
|
||||
<item name="vctr_toolbar_link_text_color">#FFD8D8D8</item>
|
||||
<item name="vctr_toolbar_primary_text_color">@color/primary_color_status</item>
|
||||
<item name="vctr_toolbar_secondary_text_color">@color/primary_color_dark_status</item>
|
||||
<item name="vctr_toolbar_link_text_color">@color/primary_color_dark_status</item>
|
||||
|
||||
<!-- application bar text hint color -->
|
||||
<item name="vctr_primary_hint_text_color">@color/primary_hint_text_color_light</item>
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
app:fragment="im.vector.riotx.features.settings.VectorSettingsGeneralFragment" />
|
||||
|
||||
<im.vector.riotx.core.preference.VectorPreference
|
||||
android:enabled="@bool/false_not_implemented"
|
||||
android:icon="@drawable/ic_settings_root_flair"
|
||||
android:title="@string/settings_flair"
|
||||
app:fragment="im.vector.riotx.features.settings.VectorSettingsFlairFragment" />
|
||||
app:fragment="im.vector.riotx.features.settings.VectorSettingsFlairFragment"
|
||||
app:isPreferenceVisible="@bool/false_not_implemented" />
|
||||
|
||||
<im.vector.riotx.core.preference.VectorPreference
|
||||
android:icon="@drawable/ic_settings_root_notification"
|
||||
|
@ -24,11 +24,10 @@
|
|||
app:fragment="im.vector.riotx.features.settings.VectorSettingsPreferencesFragment" />
|
||||
|
||||
<im.vector.riotx.core.preference.VectorPreference
|
||||
app:isPreferenceVisible="@bool/false_not_implemented"
|
||||
android:enabled="@bool/false_not_implemented"
|
||||
android:icon="@drawable/ic_settings_root_call"
|
||||
android:title="@string/preference_voice_and_video"
|
||||
app:fragment="im.vector.riotx.features.settings.VectorSettingsVoiceVideoFragment" />
|
||||
app:fragment="im.vector.riotx.features.settings.VectorSettingsVoiceVideoFragment"
|
||||
app:isPreferenceVisible="@bool/false_not_implemented" />
|
||||
|
||||
<im.vector.riotx.core.preference.VectorPreference
|
||||
android:icon="@drawable/ic_settings_root_ignored_users"
|
||||
|
|
|
@ -117,6 +117,12 @@
|
|||
android:summary="@string/settings_security_prevent_screenshots_summary"
|
||||
android:title="@string/settings_security_prevent_screenshots_title" />
|
||||
|
||||
<im.vector.riotx.core.preference.VectorSwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="SETTINGS_SECURITY_USE_PIN_CODE_FLAG"
|
||||
android:summary="@string/settings_security_pin_code_summary"
|
||||
android:title="@string/settings_security_pin_code_title" />
|
||||
|
||||
</im.vector.riotx.core.preference.VectorPreferenceCategory>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
Loading…
Add table
Reference in a new issue