Merge remote-tracking branch 'origin/develop' into feature/eric/space-list-modal

# Conflicts:
#	vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt
This commit is contained in:
ericdecanini 2022-08-10 08:24:55 +02:00
commit e87eefb319
56 changed files with 1089 additions and 454 deletions

1
changelog.d/6735.bugfix Normal file
View File

@ -0,0 +1 @@
Fixes crash when entering non ascii characters during account creation

1
changelog.d/6768.bugfix Normal file
View File

@ -0,0 +1 @@
Fix crash when biometric key is used when coming back to foreground and KeyStore reports that the device is still locked.

1
changelog.d/6769.bugfix Normal file
View File

@ -0,0 +1 @@
Catch all exceptions on lockscreen system key migrations.

View File

@ -74,6 +74,7 @@ ext.groups = [
'com.github.javaparser',
'com.github.piasy',
'com.github.shyiko.klob',
'com.github.rubensousa',
'com.google',
'com.google.android',
'com.google.api.grpc',

View File

@ -62,7 +62,10 @@ fun Throwable.isUsernameInUse() = this is Failure.ServerError &&
error.code == MatrixError.M_USER_IN_USE
fun Throwable.isInvalidUsername() = this is Failure.ServerError &&
error.code == MatrixError.M_INVALID_USERNAME
(error.code == MatrixError.M_INVALID_USERNAME || usernameContainsNonAsciiCharacters())
private fun Failure.ServerError.usernameContainsNonAsciiCharacters() = error.code == MatrixError.M_UNKNOWN &&
error.message == "Query parameter \'username\' must be ascii"
fun Throwable.isInvalidPassword() = this is Failure.ServerError &&
error.code == MatrixError.M_FORBIDDEN &&

View File

@ -28,6 +28,7 @@ mv ./fastlane/metadata/android/fy ./fastlane_tmp
mv ./fastlane/metadata/android/ga ./fastlane_tmp
mv ./fastlane/metadata/android/kab ./fastlane_tmp
mv ./fastlane/metadata/android/nb ./fastlane_tmp
mv ./fastlane/metadata/android/gl ./fastlane_tmp
# Fastlane / PlayStore require longDescription and shortDescription file to be set, so copy the default
# one for languages where they are missing

View File

@ -427,6 +427,9 @@ dependencies {
implementation libs.airbnb.epoxyPaging
implementation libs.airbnb.mavericks
// Snap Helper https://github.com/rubensousa/GravitySnapHelper
implementation 'com.github.rubensousa:gravitysnaphelper:2.2.2'
// Nightly
// API-only library
gplayImplementation libs.google.appdistributionApi

View File

@ -31,7 +31,6 @@ import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import im.vector.app.TestBuildVersionSdkIntProvider
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguration
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguratorProvider
import im.vector.app.features.pin.lockscreen.configuration.LockScreenMode
import im.vector.app.features.pin.lockscreen.crypto.LockScreenCryptoConstants
import im.vector.app.features.pin.lockscreen.crypto.LockScreenKeyRepository
@ -40,6 +39,7 @@ import im.vector.app.features.pin.lockscreen.ui.fallbackprompt.FallbackBiometric
import im.vector.app.features.pin.lockscreen.utils.DevicePromptCheck
import io.mockk.clearAllMocks
import io.mockk.every
import io.mockk.justRun
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.mockkStatic
@ -54,8 +54,10 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.coInvoking
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.amshove.kluent.shouldThrow
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
@ -239,36 +241,35 @@ class BiometricHelperTests {
@Test
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R) // Due to some issues with mockk and CryptoObject initialization
fun authenticateCreatesSystemKeyIfNeededOnSuccessOnAndroidM() = runTest {
fun enableAuthenticationDeletesSystemKeyOnFailure() = runTest {
buildVersionSdkIntProvider.value = Build.VERSION_CODES.M
every { lockScreenKeyRepository.isSystemKeyValid() } returns true
val mockAuthChannel = Channel<Boolean>(capacity = 1)
val biometricUtils = spyk(createBiometricHelper(createDefaultConfiguration(isBiometricsEnabled = true))) {
every { createAuthChannel() } returns mockAuthChannel
every { authenticateWithPromptInternal(any(), any(), any()) } returns mockk()
}
justRun { lockScreenKeyRepository.deleteSystemKey() }
val latch = CountDownLatch(1)
val intent = Intent(InstrumentationRegistry.getInstrumentation().targetContext, LockScreenTestActivity::class.java)
ActivityScenario.launch<LockScreenTestActivity>(intent).onActivity { activity ->
activity.lifecycleScope.launch {
val exception = IllegalStateException("Some error")
launch {
mockAuthChannel.send(true)
mockAuthChannel.close()
mockAuthChannel.close(exception)
}
biometricUtils.authenticate(activity).collect()
coInvoking { biometricUtils.enableAuthentication(activity).collect() } shouldThrow exception
latch.countDown()
}
}
latch.await(1, TimeUnit.SECONDS)
verify { lockScreenKeyRepository.ensureSystemKey() }
verify { lockScreenKeyRepository.deleteSystemKey() }
}
private fun createBiometricHelper(configuration: LockScreenConfiguration): BiometricHelper {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val configProvider = LockScreenConfiguratorProvider(configuration)
return BiometricHelper(context, lockScreenKeyRepository, configProvider, biometricManager, buildVersionSdkIntProvider)
return BiometricHelper(configuration, context, lockScreenKeyRepository, biometricManager, buildVersionSdkIntProvider)
}
private fun createDefaultConfiguration(

View File

@ -17,8 +17,6 @@
package im.vector.app.features.pin.lockscreen.crypto
import androidx.test.platform.app.InstrumentationRegistry
import im.vector.app.features.pin.lockscreen.crypto.migrations.LegacyPinCodeMigrator
import im.vector.app.features.settings.VectorPreferences
import io.mockk.clearAllMocks
import io.mockk.every
import io.mockk.mockk
@ -44,8 +42,6 @@ class LockScreenKeyRepositoryTests {
}
private lateinit var lockScreenKeyRepository: LockScreenKeyRepository
private val legacyPinCodeMigrator: LegacyPinCodeMigrator = mockk(relaxed = true)
private val vectorPreferences: VectorPreferences = mockk(relaxed = true)
private val keyStore: KeyStore by lazy {
KeyStore.getInstance(LockScreenCryptoConstants.ANDROID_KEY_STORE).also { it.load(null) }

View File

@ -25,17 +25,21 @@ import android.content.res.Configuration
import android.os.Handler
import android.os.HandlerThread
import android.os.StrictMode
import android.view.Gravity
import androidx.core.provider.FontRequest
import androidx.core.provider.FontsContractCompat
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.multidex.MultiDex
import androidx.recyclerview.widget.SnapHelper
import com.airbnb.epoxy.Carousel
import com.airbnb.epoxy.EpoxyAsyncUtil
import com.airbnb.epoxy.EpoxyController
import com.airbnb.mvrx.Mavericks
import com.facebook.stetho.Stetho
import com.gabrielittner.threetenbp.LazyThreeTen
import com.github.rubensousa.gravitysnaphelper.GravitySnapHelper
import com.mapbox.mapboxsdk.Mapbox
import com.vanniktech.emoji.EmojiManager
import com.vanniktech.emoji.google.GoogleEmojiProvider
@ -141,8 +145,9 @@ class VectorApplication :
logInfo()
LazyThreeTen.init(this)
Mavericks.initialize(debugMode = false)
EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
configureEpoxy()
registerActivityLifecycleCallbacks(VectorActivityLifecycleCallbacks(popupAlertManager))
val fontRequest = FontRequest(
"com.google.android.gms.fonts",
@ -198,6 +203,16 @@ class VectorApplication :
Mapbox.getInstance(this)
}
private fun configureEpoxy() {
EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
Carousel.setDefaultGlobalSnapHelperFactory(object : Carousel.SnapHelperFactory() {
override fun buildSnapHelper(context: Context?): SnapHelper {
return GravitySnapHelper(Gravity.START)
}
})
}
private fun enableStrictModeIfNeeded() {
if (Config.ENABLE_STRICT_MODE_LOGS) {
StrictMode.setThreadPolicy(

View File

@ -31,6 +31,7 @@ import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import im.vector.app.R
import im.vector.app.core.epoxy.LayoutManagerStateRestorer
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.platform.StateView
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.UserPreferencesProvider
@ -47,6 +48,7 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA
import im.vector.app.features.home.room.list.actions.RoomListSharedAction
import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel
import im.vector.app.features.spaces.SpaceListBottomSheet
import im.vector.app.features.home.room.list.home.recent.RecentRoomCarouselController
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.session.room.model.RoomSummary
@ -57,7 +59,8 @@ import javax.inject.Inject
class HomeRoomListFragment @Inject constructor(
private val roomSummaryItemFactory: RoomSummaryItemFactory,
private val userPreferencesProvider: UserPreferencesProvider
private val userPreferencesProvider: UserPreferencesProvider,
private val recentRoomCarouselController: RecentRoomCarouselController
) : VectorBaseFragment<FragmentRoomListBinding>(),
RoomListListener {
@ -237,6 +240,12 @@ class HomeRoomListFragment @Inject constructor(
}
}.adapter
}
is HomeRoomSection.RecentRoomsData -> recentRoomCarouselController.also { controller ->
controller.listener = this
data.list.observe(viewLifecycleOwner) { list ->
controller.submitList(list)
}
}.adapter
}
}
@ -249,6 +258,12 @@ class HomeRoomListFragment @Inject constructor(
)
}
override fun onDestroyView() {
views.roomListView.cleanup()
recentRoomCarouselController.listener = null
super.onDestroyView()
}
// region RoomListListener
override fun onRoomClicked(room: RoomSummary) {

View File

@ -37,6 +37,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.SpaceFilter
import org.matrix.android.sdk.api.query.toActiveSpaceOrNoFilter
import org.matrix.android.sdk.api.query.toActiveSpaceOrOrphanRooms
@ -45,6 +46,7 @@ import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.state.isPublic
class HomeRoomListViewModel @AssistedInject constructor(
@ -78,6 +80,7 @@ class HomeRoomListViewModel @AssistedInject constructor(
private fun configureSections() {
val newSections = mutableSetOf<HomeRoomSection>()
newSections.add(getRecentRoomsSection())
newSections.add(getAllRoomsSection())
viewModelScope.launch {
@ -89,6 +92,18 @@ class HomeRoomListViewModel @AssistedInject constructor(
}
}
private fun getRecentRoomsSection(): HomeRoomSection {
val liveList = session.roomService()
.getBreadcrumbsLive(roomSummaryQueryParams {
displayName = QueryStringValue.NoCondition
memberships = listOf(Membership.JOIN)
})
return HomeRoomSection.RecentRoomsData(
list = liveList
)
}
private fun getAllRoomsSection(): HomeRoomSection.RoomSummaryData {
val builder = RoomSummaryQueryParams.Builder().also {
it.memberships = listOf(Membership.JOIN)

View File

@ -24,4 +24,8 @@ sealed class HomeRoomSection {
data class RoomSummaryData(
val list: LiveData<PagedList<RoomSummary>>
) : HomeRoomSection()
data class RecentRoomsData(
val list: LiveData<List<RoomSummary>>
) : HomeRoomSection()
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.home.room.list.home.recent
import android.content.res.Resources
import android.util.TypedValue
import com.airbnb.epoxy.Carousel
import com.airbnb.epoxy.CarouselModelBuilder
import com.airbnb.epoxy.EpoxyController
import com.airbnb.epoxy.EpoxyModel
import com.airbnb.epoxy.carousel
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.list.RoomListListener
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.util.toMatrixItem
import javax.inject.Inject
class RecentRoomCarouselController @Inject constructor(
private val avatarRenderer: AvatarRenderer,
private val resources: Resources,
) : EpoxyController() {
private var data: List<RoomSummary>? = null
var listener: RoomListListener? = null
private val hPadding = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
16f,
resources.displayMetrics
).toInt()
private val itemSpacing = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
24f,
resources.displayMetrics
).toInt()
fun submitList(recentList: List<RoomSummary>) {
this.data = recentList
requestModelBuild()
}
override fun buildModels() {
val host = this
data?.let { data ->
carousel {
id("recents_carousel")
padding(Carousel.Padding(host.hPadding, host.itemSpacing))
withModelsFrom(data) { roomSummary ->
val onClick = host.listener?.let { it::onRoomClicked }
val onLongClick = host.listener?.let { it::onRoomLongClicked }
RecentRoomItem_()
.id(roomSummary.roomId)
.avatarRenderer(host.avatarRenderer)
.matrixItem(roomSummary.toMatrixItem())
.unreadNotificationCount(roomSummary.notificationCount)
.showHighlighted(roomSummary.highlightCount > 0)
.itemLongClickListener { _ -> onLongClick?.invoke(roomSummary) ?: false }
.itemClickListener { onClick?.invoke(roomSummary) }
}
}
}
}
}
private inline fun <T> CarouselModelBuilder.withModelsFrom(
items: List<T>,
modelBuilder: (T) -> EpoxyModel<*>
) {
models(items.map { modelBuilder(it) })
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.home.room.list.home.recent
import android.view.HapticFeedbackConstants
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R
import im.vector.app.core.epoxy.ClickListener
import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.epoxy.onClick
import im.vector.app.features.displayname.getBestName
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
import org.matrix.android.sdk.api.util.MatrixItem
@EpoxyModelClass
abstract class RecentRoomItem : VectorEpoxyModel<RecentRoomItem.Holder>(R.layout.item_recent_room) {
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute lateinit var matrixItem: MatrixItem
@EpoxyAttribute var unreadNotificationCount: Int = 0
@EpoxyAttribute var showHighlighted: Boolean = false
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
var itemLongClickListener: View.OnLongClickListener? = null
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
var itemClickListener: ClickListener? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.rootView.onClick(itemClickListener)
holder.rootView.setOnLongClickListener {
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
itemLongClickListener?.onLongClick(it) ?: false
}
avatarRenderer.render(matrixItem, holder.avatarImageView)
holder.avatarImageView.contentDescription = matrixItem.getBestName()
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted))
holder.title.text = matrixItem.getBestName()
}
override fun unbind(holder: Holder) {
holder.rootView.setOnClickListener(null)
holder.rootView.setOnLongClickListener(null)
avatarRenderer.clear(holder.avatarImageView)
super.unbind(holder)
}
class Holder : VectorEpoxyHolder() {
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.recentUnreadCounterBadgeView)
val avatarImageView by bind<ImageView>(R.id.recentImageView)
val title by bind<TextView>(R.id.recentTitle)
val rootView by bind<ViewGroup>(R.id.recentRoot)
}
}

View File

@ -193,25 +193,32 @@ class OnboardingViewModel @AssistedInject constructor(
}
private suspend fun checkUserNameAvailability(userName: String) {
when (val result = registrationWizard.registrationAvailable(userName)) {
RegistrationAvailability.Available -> {
setState {
copy(
registrationState = RegistrationState(
isUserNameAvailable = true,
selectedMatrixId = when {
userName.isMatrixId() -> userName
else -> "@$userName:${selectedHomeserver.userFacingUrl.toReducedUrl()}"
},
)
)
}
}
runCatching { registrationWizard.registrationAvailable(userName) }.fold(
onSuccess = { result ->
when (result) {
RegistrationAvailability.Available -> {
setState {
copy(
registrationState = RegistrationState(
isUserNameAvailable = true,
selectedMatrixId = when {
userName.isMatrixId() -> userName
else -> "@$userName:${selectedHomeserver.userFacingUrl.toReducedUrl()}"
},
)
)
}
}
is RegistrationAvailability.NotAvailable -> {
_viewEvents.post(OnboardingViewEvents.Failure(result.failure))
}
}
is RegistrationAvailability.NotAvailable -> {
_viewEvents.post(OnboardingViewEvents.Failure(result.failure))
}
}
},
onFailure = {
_viewEvents.post(OnboardingViewEvents.Failure(it))
}
)
}
private fun withAction(action: OnboardingAction, block: (OnboardingAction) -> Unit) {

View File

@ -24,6 +24,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import com.airbnb.mvrx.args
import com.airbnb.mvrx.asMavericksArgs
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import im.vector.app.R
import im.vector.app.core.extensions.replaceFragment
@ -33,7 +34,7 @@ import im.vector.app.databinding.FragmentPinBinding
import im.vector.app.features.MainActivity
import im.vector.app.features.MainActivityArgs
import im.vector.app.features.pin.lockscreen.biometrics.BiometricAuthError
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguratorProvider
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguration
import im.vector.app.features.pin.lockscreen.configuration.LockScreenMode
import im.vector.app.features.pin.lockscreen.ui.AuthMethod
import im.vector.app.features.pin.lockscreen.ui.LockScreenFragment
@ -51,7 +52,7 @@ data class PinArgs(
class PinFragment @Inject constructor(
private val pinCodeStore: PinCodeStore,
private val vectorPreferences: VectorPreferences,
private val configuratorProvider: LockScreenConfiguratorProvider,
private val defaultConfiguration: LockScreenConfiguration,
) : VectorBaseFragment<FragmentPinBinding>() {
private val fragmentArgs: PinArgs by args()
@ -81,21 +82,17 @@ class PinFragment @Inject constructor(
vectorBaseActivity.finish()
}
}
configuratorProvider.updateDefaultConfiguration {
copy(
mode = LockScreenMode.CREATE,
title = getString(R.string.create_pin_title),
needsNewCodeValidation = true,
newCodeConfirmationTitle = getString(R.string.create_pin_confirm_title),
)
}
createFragment.arguments = defaultConfiguration.copy(
mode = LockScreenMode.CREATE,
title = getString(R.string.create_pin_title),
needsNewCodeValidation = true,
newCodeConfirmationTitle = getString(R.string.create_pin_confirm_title),
).asMavericksArgs()
replaceFragment(R.id.pinFragmentContainer, createFragment)
}
private fun showAuthFragment() {
val authFragment = LockScreenFragment()
val canUseBiometrics = vectorPreferences.useBiometricsToUnlock()
authFragment.onLeftButtonClickedListener = View.OnClickListener { displayForgotPinWarningDialog() }
authFragment.lockScreenListener = object : LockScreenListener {
override fun onAuthenticationFailure(authMethod: AuthMethod) {
@ -133,18 +130,12 @@ class PinFragment @Inject constructor(
.show()
}
}
configuratorProvider.updateDefaultConfiguration {
copy(
mode = LockScreenMode.VERIFY,
title = getString(R.string.auth_pin_title),
isStrongBiometricsEnabled = isStrongBiometricsEnabled && canUseBiometrics,
isWeakBiometricsEnabled = isWeakBiometricsEnabled && canUseBiometrics,
isDeviceCredentialUnlockEnabled = isDeviceCredentialUnlockEnabled && canUseBiometrics,
autoStartBiometric = canUseBiometrics,
leftButtonTitle = getString(R.string.auth_pin_forgot),
clearCodeOnError = true,
)
}
authFragment.arguments = defaultConfiguration.copy(
mode = LockScreenMode.VERIFY,
title = getString(R.string.auth_pin_title),
leftButtonTitle = getString(R.string.auth_pin_forgot),
clearCodeOnError = true,
).asMavericksArgs()
replaceFragment(R.id.pinFragmentContainer, authFragment)
}

View File

@ -31,10 +31,12 @@ import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.qualifiers.ApplicationContext
import im.vector.app.R
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguration
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguratorProvider
import im.vector.app.features.pin.lockscreen.crypto.LockScreenKeyRepository
import im.vector.app.features.pin.lockscreen.ui.fallbackprompt.FallbackBiometricDialogFragment
import im.vector.app.features.pin.lockscreen.utils.DevicePromptCheck
@ -54,22 +56,24 @@ import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.util.BuildVersionSdkIntProvider
import java.security.KeyStore
import javax.crypto.Cipher
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
/**
* This is a helper to manage system authentication (biometric and other types) and the system key.
*/
class BiometricHelper @Inject constructor(
class BiometricHelper @AssistedInject constructor(
@Assisted private val configuration: LockScreenConfiguration,
@ApplicationContext private val context: Context,
private val lockScreenKeyRepository: LockScreenKeyRepository,
private val configurationProvider: LockScreenConfiguratorProvider,
private val biometricManager: BiometricManager,
private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider,
) {
private var prompt: BiometricPrompt? = null
private val configuration: LockScreenConfiguration get() = configurationProvider.currentConfiguration
@AssistedFactory
interface BiometricHelperFactory {
fun create(configuration: LockScreenConfiguration): BiometricHelper
}
/**
* Returns true if a weak biometric method (i.e.: some face or iris unlock implementations) can be used.
@ -174,16 +178,18 @@ class BiometricHelper @Inject constructor(
when (val exception = result.exceptionOrNull()) {
null -> result.getOrNull()?.let { emit(it) }
else -> {
// Exception found, stop collecting, throw it and remove the prompt reference
// Exception found:
// 1. Stop collecting.
// 2. Remove the system key if we were creating it.
// 3. Throw the exception and remove the prompt reference
if (!checkSystemKeyExists) {
lockScreenKeyRepository.deleteSystemKey()
}
prompt = null
throw exception
}
}
}
// Generates the system key on successful authentication
if (buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M) {
lockScreenKeyRepository.ensureSystemKey()
}
// Channel is closed, remove prompt reference
prompt = null
}
@ -213,11 +219,11 @@ class BiometricHelper @Inject constructor(
.setAllowedAuthenticators(authenticators)
.build()
return BiometricPrompt(activity, executor, callback).also {
return BiometricPrompt(activity, executor, callback).also { prompt ->
showFallbackFragmentIfNeeded(activity, channel.receiveAsFlow(), executor.asCoroutineDispatcher()) {
// For some reason this seems to be needed unless we want to receive a fragment transaction exception
delay(1L)
it.authenticate(promptInfo, cryptoObject)
prompt.authenticate(promptInfo, cryptoObject)
}
}
}
@ -253,11 +259,9 @@ class BiometricHelper @Inject constructor(
): BiometricPrompt.AuthenticationCallback = object : BiometricPrompt.AuthenticationCallback() {
private val scope = CoroutineScope(coroutineContext)
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
scope.launch {
// Error is a terminal event, should close both the Channel and the CoroutineScope to free resources.
channel.close(BiometricAuthError(errorCode, errString.toString()))
scope.cancel()
}
// Error is a terminal event, should close both the Channel and the CoroutineScope to free resources.
channel.close(BiometricAuthError(errorCode, errString.toString()))
scope.cancel()
}
override fun onAuthenticationFailed() {
@ -274,10 +278,8 @@ class BiometricHelper @Inject constructor(
scope.cancel()
}
} else {
scope.launch {
channel.close(IllegalStateException("System key was not valid after authentication."))
scope.cancel()
}
channel.close(IllegalStateException("System key was not valid after authentication."))
scope.cancel()
}
}

View File

@ -16,9 +16,13 @@
package im.vector.app.features.pin.lockscreen.configuration
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
/**
* Configuration to be used by the lockscreen feature.
*/
@Parcelize
data class LockScreenConfiguration(
/** Which mode should the UI display, [LockScreenMode.VERIFY] or [LockScreenMode.CREATE]. */
val mode: LockScreenMode,
@ -56,4 +60,4 @@ data class LockScreenConfiguration(
val biometricSubtitle: String? = null,
/** Text for the cancel button of the Biometric prompt dialog. Optional. */
val biometricCancelButtonTitle: String? = null,
)
) : Parcelable

View File

@ -1,58 +0,0 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.pin.lockscreen.configuration
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject
import javax.inject.Singleton
/**
* Class used to hold both the [defaultConfiguration] and an updated version in [currentConfiguration].
*/
@Singleton
class LockScreenConfiguratorProvider @Inject constructor(
/** Default [LockScreenConfiguration], any derived configuration created using [updateDefaultConfiguration] will use this as a base. */
val defaultConfiguration: LockScreenConfiguration,
) {
private val mutableConfigurationFlow = MutableStateFlow(defaultConfiguration)
/**
* A [Flow] that emits any changes in configuration.
*/
val configurationFlow: Flow<LockScreenConfiguration> = mutableConfigurationFlow
/**
* The current configuration to be read and used.
*/
val currentConfiguration get() = mutableConfigurationFlow.value
/**
* Applies the changes in [block] to the [defaultConfiguration] to generate a new [currentConfiguration].
*/
fun updateDefaultConfiguration(block: LockScreenConfiguration.() -> LockScreenConfiguration) {
mutableConfigurationFlow.value = defaultConfiguration.block()
}
/**
* Resets the [currentConfiguration] to the [defaultConfiguration].
*/
fun reset() {
mutableConfigurationFlow.value = defaultConfiguration
}
}

View File

@ -20,13 +20,13 @@ import android.annotation.SuppressLint
import android.content.Context
import android.os.Build
import android.security.keystore.KeyPermanentlyInvalidatedException
import android.security.keystore.UserNotAuthenticatedException
import android.util.Base64
import androidx.annotation.VisibleForTesting
import androidx.biometric.BiometricPrompt
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.securestorage.SecretStoringUtils
import org.matrix.android.sdk.api.util.BuildVersionSdkIntProvider
import java.security.Key
@ -113,14 +113,8 @@ class KeyStoreCrypto @AssistedInject constructor(
fun hasValidKey(): Boolean {
val keyExists = hasKey()
return if (buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M && keyExists) {
try {
ensureKey()
true
} catch (e: KeyPermanentlyInvalidatedException) {
false
} catch (e: UserNotAuthenticatedException) {
false
}
val initializedKey = tryOrNull("Error validating lockscreen system key.") { ensureKey() }
initializedKey != null
} else {
keyExists
}

View File

@ -40,7 +40,7 @@ class LockScreenKeysMigrator @Inject constructor(
suspend fun migrateIfNeeded() {
if (legacyPinCodeMigrator.isMigrationNeeded()) {
legacyPinCodeMigrator.migrate()
missingSystemKeyMigrator.migrate()
missingSystemKeyMigrator.migrateIfNeeded()
}
if (systemKeyV1Migrator.isMigrationNeeded() && versionProvider.get() >= Build.VERSION_CODES.M) {

View File

@ -18,8 +18,6 @@ package im.vector.app.features.pin.lockscreen.crypto.migrations
import android.annotation.SuppressLint
import android.os.Build
import android.security.keystore.KeyPermanentlyInvalidatedException
import android.security.keystore.UserNotAuthenticatedException
import im.vector.app.features.pin.lockscreen.crypto.KeyStoreCrypto
import im.vector.app.features.pin.lockscreen.di.BiometricKeyAlias
import im.vector.app.features.settings.VectorPreferences
@ -41,14 +39,15 @@ class MissingSystemKeyMigrator @Inject constructor(
* If user had biometric auth enabled, ensure system key exists, creating one if needed.
*/
@SuppressLint("NewApi")
fun migrate() {
fun migrateIfNeeded() {
if (buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M && vectorPreferences.useBiometricsToUnlock()) {
try {
keystoreCryptoFactory.provide(systemKeyAlias, true).ensureKey()
} catch (e: KeyPermanentlyInvalidatedException) {
Timber.e("Could not automatically create biometric key because it was invalidated.", e)
} catch (e: UserNotAuthenticatedException) {
Timber.e("Could not automatically create biometric key because there are no enrolled biometric authenticators.", e)
val systemKeyStoreCrypto = keystoreCryptoFactory.provide(systemKeyAlias, true)
runCatching {
systemKeyStoreCrypto.ensureKey()
}.onFailure { e ->
Timber.e(e, "Could not automatically create biometric key. Biometric authentication will be disabled.")
systemKeyStoreCrypto.deleteKey()
vectorPreferences.setUseBiometricToUnlock(false)
}
}
}

View File

@ -17,10 +17,10 @@
package im.vector.app.features.pin.lockscreen.crypto.migrations
import android.os.Build
import android.security.keystore.UserNotAuthenticatedException
import androidx.annotation.RequiresApi
import im.vector.app.features.pin.lockscreen.crypto.KeyStoreCrypto
import im.vector.app.features.pin.lockscreen.di.BiometricKeyAlias
import im.vector.app.features.settings.VectorPreferences
import timber.log.Timber
import java.security.KeyStore
import javax.inject.Inject
@ -32,6 +32,7 @@ class SystemKeyV1Migrator @Inject constructor(
@BiometricKeyAlias private val systemKeyAlias: String,
private val keyStore: KeyStore,
private val keystoreCryptoFactory: KeyStoreCrypto.Factory,
private val vectorPreferences: VectorPreferences,
) {
/**
@ -41,10 +42,12 @@ class SystemKeyV1Migrator @Inject constructor(
fun migrate() {
keyStore.deleteEntry(SYSTEM_KEY_ALIAS_V1)
val systemKeyStoreCrypto = keystoreCryptoFactory.provide(systemKeyAlias, keyNeedsUserAuthentication = true)
try {
runCatching {
systemKeyStoreCrypto.ensureKey()
} catch (e: UserNotAuthenticatedException) {
Timber.e("Could not migrate v1 biometric key because there are no enrolled biometric authenticators.", e)
}.onFailure { e ->
Timber.e(e, "Could not migrate v1 biometric key. Biometric authentication will be disabled.")
systemKeyStoreCrypto.deleteKey()
vectorPreferences.setUseBiometricToUnlock(false)
}
}

View File

@ -16,8 +16,10 @@
package im.vector.app.features.pin.lockscreen.di
import android.app.KeyguardManager
import android.content.Context
import androidx.biometric.BiometricManager
import androidx.core.content.getSystemService
import dagger.Binds
import dagger.Module
import dagger.Provides
@ -83,6 +85,9 @@ object LockScreenModule {
SecretStoringUtils(context, keyStore, buildVersionSdkIntProvider),
buildVersionSdkIntProvider,
)
@Provides
fun provideKeyguardManager(context: Context): KeyguardManager = context.getSystemService()!!
}
@Module

View File

@ -22,4 +22,5 @@ import im.vector.app.core.platform.VectorViewModelAction
sealed class LockScreenAction : VectorViewModelAction {
data class PinCodeEntered(val value: String) : LockScreenAction()
data class ShowBiometricPrompt(val callingActivity: FragmentActivity) : LockScreenAction()
object OnUIReady : LockScreenAction()
}

View File

@ -23,7 +23,6 @@ import android.view.ViewGroup
import android.view.animation.AnimationUtils
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint
@ -55,22 +54,7 @@ class LockScreenFragment : VectorBaseFragment<FragmentLockScreenBinding>() {
handleEvent(it)
}
withState(viewModel) { state ->
if (state.lockScreenConfiguration.mode == LockScreenMode.CREATE) return@withState
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
if (state.canUseBiometricAuth && state.isBiometricKeyInvalidated) {
lockScreenListener?.onBiometricKeyInvalidated()
} else if (state.showBiometricPromptAutomatically) {
showBiometricPrompt()
}
}
}
}
override fun onDestroy() {
super.onDestroy()
viewModel.reset()
viewModel.handle(LockScreenAction.OnUIReady)
}
override fun invalidate() = withState(viewModel) { state ->
@ -83,6 +67,7 @@ class LockScreenFragment : VectorBaseFragment<FragmentLockScreenBinding>() {
setupTitleView(views.titleTextView, false, state.lockScreenConfiguration)
}
}
renderDeleteOrFingerprintButtons(views, views.codeView.enteredDigits)
}
@ -123,6 +108,8 @@ class LockScreenFragment : VectorBaseFragment<FragmentLockScreenBinding>() {
is LockScreenViewEvent.AuthSuccessful -> lockScreenListener?.onAuthenticationSuccess(viewEvent.method)
is LockScreenViewEvent.AuthFailure -> onAuthFailure(viewEvent.method)
is LockScreenViewEvent.AuthError -> onAuthError(viewEvent.method, viewEvent.throwable)
is LockScreenViewEvent.ShowBiometricKeyInvalidatedMessage -> lockScreenListener?.onBiometricKeyInvalidated()
is LockScreenViewEvent.ShowBiometricPromptAutomatically -> showBiometricPrompt()
}
}

View File

@ -24,4 +24,6 @@ sealed class LockScreenViewEvent : VectorViewEvents {
data class AuthSuccessful(val method: AuthMethod) : LockScreenViewEvent()
data class AuthFailure(val method: AuthMethod) : LockScreenViewEvent()
data class AuthError(val method: AuthMethod, val throwable: Throwable) : LockScreenViewEvent()
object ShowBiometricKeyInvalidatedMessage : LockScreenViewEvent()
object ShowBiometricPromptAutomatically : LockScreenViewEvent()
}

View File

@ -17,12 +17,11 @@
package im.vector.app.features.pin.lockscreen.ui
import android.annotation.SuppressLint
import android.app.KeyguardManager
import android.os.Build
import android.security.keystore.KeyPermanentlyInvalidatedException
import androidx.fragment.app.FragmentActivity
import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import com.airbnb.mvrx.withState
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -31,26 +30,29 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.pin.lockscreen.biometrics.BiometricAuthError
import im.vector.app.features.pin.lockscreen.biometrics.BiometricHelper
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguration
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguratorProvider
import im.vector.app.features.pin.lockscreen.configuration.LockScreenMode
import im.vector.app.features.pin.lockscreen.crypto.LockScreenKeysMigrator
import im.vector.app.features.pin.lockscreen.pincode.PinCodeHelper
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeoutOrNull
import org.matrix.android.sdk.api.util.BuildVersionSdkIntProvider
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
class LockScreenViewModel @AssistedInject constructor(
@Assisted val initialState: LockScreenViewState,
private val pinCodeHelper: PinCodeHelper,
private val biometricHelper: BiometricHelper,
biometricHelperFactory: BiometricHelper.BiometricHelperFactory,
private val lockScreenKeysMigrator: LockScreenKeysMigrator,
private val configuratorProvider: LockScreenConfiguratorProvider,
private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider,
private val versionProvider: BuildVersionSdkIntProvider,
private val keyguardManager: KeyguardManager,
) : VectorViewModel<LockScreenViewState, LockScreenAction, LockScreenViewEvent>(initialState) {
@AssistedFactory
@ -58,27 +60,9 @@ class LockScreenViewModel @AssistedInject constructor(
override fun create(initialState: LockScreenViewState): LockScreenViewModel
}
companion object : MavericksViewModelFactory<LockScreenViewModel, LockScreenViewState> by hiltMavericksViewModelFactory() {
companion object : MavericksViewModelFactory<LockScreenViewModel, LockScreenViewState> by hiltMavericksViewModelFactory()
override fun initialState(viewModelContext: ViewModelContext): LockScreenViewState {
return LockScreenViewState(
lockScreenConfiguration = DUMMY_CONFIGURATION,
canUseBiometricAuth = false,
showBiometricPromptAutomatically = false,
pinCodeState = PinCodeState.Idle,
isBiometricKeyInvalidated = false,
)
}
private val DUMMY_CONFIGURATION = LockScreenConfiguration(
mode = LockScreenMode.VERIFY,
pinCodeLength = 4,
isStrongBiometricsEnabled = false,
isDeviceCredentialUnlockEnabled = false,
isWeakBiometricsEnabled = false,
needsNewCodeValidation = false,
)
}
private val biometricHelper = biometricHelperFactory.create(initialState.lockScreenConfiguration)
private var firstEnteredCode: String? = null
@ -86,18 +70,37 @@ class LockScreenViewModel @AssistedInject constructor(
private var isSystemAuthTemporarilyDisabledByBiometricPrompt = false
init {
// We need this to run synchronously before we start reading the configurations
runBlocking { lockScreenKeysMigrator.migrateIfNeeded() }
viewModelScope.launch {
// Wait until the keyguard is unlocked before performing migrations, it might cause crashes otherwise on Android 12 and 12L
waitUntilKeyguardIsUnlocked()
// Migrate pin code / system keys if needed
lockScreenKeysMigrator.migrateIfNeeded()
// Update initial state with biometric info
updateStateWithBiometricInfo()
}
}
configuratorProvider.configurationFlow
.onEach { updateConfiguration(it) }
.launchIn(viewModelScope)
private fun observeStateChanges() {
// The first time the state allows it, show the biometric prompt
viewModelScope.launch {
if (stateFlow.firstOrNull { it.showBiometricPromptAutomatically } != null) {
_viewEvents.post(LockScreenViewEvent.ShowBiometricPromptAutomatically)
}
}
// The first time the state allows it, react to biometric key being invalidated
viewModelScope.launch {
if (stateFlow.firstOrNull { it.isBiometricKeyInvalidated } != null) {
onBiometricKeyInvalidated()
}
}
}
override fun handle(action: LockScreenAction) {
when (action) {
is LockScreenAction.PinCodeEntered -> onPinCodeEntered(action.value)
is LockScreenAction.ShowBiometricPrompt -> showBiometricPrompt(action.callingActivity)
is LockScreenAction.OnUIReady -> observeStateChanges()
}
}
@ -141,13 +144,18 @@ class LockScreenViewModel @AssistedInject constructor(
private fun showBiometricPrompt(activity: FragmentActivity) = flow {
emitAll(biometricHelper.authenticate(activity))
}.catch { error ->
if (buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M && error is KeyPermanentlyInvalidatedException) {
removeBiometricAuthentication()
} else if (error is BiometricAuthError && error.isAuthDisabledError) {
isSystemAuthTemporarilyDisabledByBiometricPrompt = true
updateStateWithBiometricInfo()
when {
versionProvider.get() >= Build.VERSION_CODES.M && error is KeyPermanentlyInvalidatedException -> {
onBiometricKeyInvalidated()
}
else -> {
if (error is BiometricAuthError && error.isAuthDisabledError) {
isSystemAuthTemporarilyDisabledByBiometricPrompt = true
updateStateWithBiometricInfo()
}
_viewEvents.post(LockScreenViewEvent.AuthError(AuthMethod.BIOMETRICS, error))
}
}
_viewEvents.post(LockScreenViewEvent.AuthError(AuthMethod.BIOMETRICS, error))
}.onEach { success ->
_viewEvents.post(
if (success) LockScreenViewEvent.AuthSuccessful(AuthMethod.BIOMETRICS)
@ -155,24 +163,22 @@ class LockScreenViewModel @AssistedInject constructor(
)
}.launchIn(viewModelScope)
fun reset() {
configuratorProvider.reset()
}
private fun removeBiometricAuthentication() {
private suspend fun onBiometricKeyInvalidated() {
biometricHelper.disableAuthentication()
updateStateWithBiometricInfo()
_viewEvents.post(LockScreenViewEvent.ShowBiometricKeyInvalidatedMessage)
}
private fun updateStateWithBiometricInfo() {
val configuration = withState(this) { it.lockScreenConfiguration }
val canUseBiometricAuth = configuration.mode == LockScreenMode.VERIFY &&
@SuppressLint("NewApi")
private suspend fun updateStateWithBiometricInfo() {
// This is a terrible hack, but I found no other way to ensure this would be called only after the device is considered unlocked on Android 12+
waitUntilKeyguardIsUnlocked()
setState {
val isBiometricKeyInvalidated = biometricHelper.hasSystemKey && !biometricHelper.isSystemKeyValid
val canUseBiometricAuth = lockScreenConfiguration.mode == LockScreenMode.VERIFY &&
!isSystemAuthTemporarilyDisabledByBiometricPrompt &&
biometricHelper.isSystemAuthEnabledAndValid
val isBiometricKeyInvalidated = biometricHelper.hasSystemKey && !biometricHelper.isSystemKeyValid
val showBiometricPromptAutomatically = canUseBiometricAuth &&
configuration.autoStartBiometric
setState {
val showBiometricPromptAutomatically = canUseBiometricAuth && lockScreenConfiguration.autoStartBiometric
copy(
canUseBiometricAuth = canUseBiometricAuth,
showBiometricPromptAutomatically = showBiometricPromptAutomatically,
@ -181,8 +187,18 @@ class LockScreenViewModel @AssistedInject constructor(
}
}
private fun updateConfiguration(configuration: LockScreenConfiguration) {
setState { copy(lockScreenConfiguration = configuration) }
updateStateWithBiometricInfo()
/**
* Wait until the device is unlocked. There seems to be a behavior change on Android 12 that makes [KeyguardManager.isDeviceLocked] return `false` even
* after an Activity's `onResume` method. If we mix that with the system keys needing the device to be unlocked before they're used, we get crashes.
* See issue [#6768](https://github.com/vector-im/element-android/issues/6768).
*/
@SuppressLint("NewApi")
private suspend fun waitUntilKeyguardIsUnlocked() {
if (versionProvider.get() < Build.VERSION_CODES.S) return
withTimeoutOrNull(5.seconds) {
while (keyguardManager.isDeviceLocked) {
delay(50.milliseconds)
}
}
}
}

View File

@ -25,7 +25,11 @@ data class LockScreenViewState(
val showBiometricPromptAutomatically: Boolean,
val pinCodeState: PinCodeState,
val isBiometricKeyInvalidated: Boolean,
) : MavericksState
) : MavericksState {
constructor(lockScreenConfiguration: LockScreenConfiguration) : this(
lockScreenConfiguration, false, false, PinCodeState.Idle, false
)
}
sealed class PinCodeState {
object Idle : PinCodeState()

View File

@ -28,6 +28,8 @@ import im.vector.app.features.notifications.NotificationDrawerManager
import im.vector.app.features.pin.PinCodeStore
import im.vector.app.features.pin.PinMode
import im.vector.app.features.pin.lockscreen.biometrics.BiometricHelper
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguration
import im.vector.app.features.pin.lockscreen.configuration.LockScreenMode
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.orFalse
@ -38,12 +40,15 @@ class VectorSettingsPinFragment @Inject constructor(
private val pinCodeStore: PinCodeStore,
private val navigator: Navigator,
private val notificationDrawerManager: NotificationDrawerManager,
private val biometricHelper: BiometricHelper,
biometricHelperFactory: BiometricHelper.BiometricHelperFactory,
defaultLockScreenConfiguration: LockScreenConfiguration,
) : VectorSettingsBaseFragment() {
override var titleRes = R.string.settings_security_application_protection_screen_title
override val preferenceXmlRes = R.xml.vector_settings_pin
private val biometricHelper = biometricHelperFactory.create(defaultLockScreenConfiguration.copy(mode = LockScreenMode.CREATE))
private val usePinCodePref by lazy {
findPreference<SwitchPreference>(VectorPreferences.SETTINGS_SECURITY_USE_PIN_CODE_FLAG)!!
}
@ -102,9 +107,10 @@ class VectorSettingsPinFragment @Inject constructor(
}.onFailure {
showEnableBiometricErrorMessage()
}
updateBiometricPrefState(isPinCodeChecked = usePinCodePref.isChecked)
}
false
true
} else {
disableBiometricAuthentication()
true

View File

@ -0,0 +1,61 @@
<?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/recentRoot"
android:layout_width="60dp"
android:layout_height="wrap_content"
android:background="?android:colorBackground"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
tools:viewBindingIgnore="true">
<ImageView
android:id="@+id/recentImageView"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginHorizontal="12dp"
android:layout_marginTop="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription"
tools:src="@sample/room_round_avatars" />
<im.vector.app.features.home.room.list.UnreadCounterBadgeView
android:id="@+id/recentUnreadCounterBadgeView"
style="@style/Widget.Vector.TextView.Micro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minWidth="18dp"
android:minHeight="18dp"
android:textColor="?colorOnError"
android:visibility="gone"
app:layout_constraintCircle="@id/recentImageView"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="28dp"
tools:background="@drawable/bg_unread_highlight"
tools:ignore="MissingConstraints"
tools:text="24"
tools:visibility="visible" />
<TextView
android:id="@+id/recentTitle"
style="@style/Widget.Vector.TextView.Body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="16dp"
android:ellipsize="end"
android:lines="1"
android:textColor="?vctr_content_primary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/recentImageView"
tools:text="Coffee" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -97,14 +97,14 @@
<string name="notice_room_server_acl_updated_was_banned">• الخوادِم المُطابقة لـ %s أُزيلت مِن قائمة الحظر.</string>
<string name="notice_room_server_acl_updated_banned">• الخوادِم المُطابقة لـ %s محظورة الآن.</string>
<string name="notice_room_server_acl_updated_ip_literals_allowed">• خوادِم مُطابقة IP الحرفية مسموحة الآن.</string>
<string name="notice_room_server_acl_updated_title_by_you">لقد قمت بتغيير قائمة الوصول لهذه الغُرفة.</string>
<string name="notice_room_server_acl_updated_title">قام %s بتغيير قائمة الوصول (ACL) لهذه الغُرفة.</string>
<string name="notice_room_server_acl_updated_title_by_you">لقد غَيَّرت قائمة الوصول لهذه الغُرفة.</string>
<string name="notice_room_server_acl_updated_title">غَيَّرَ %s قائمة التحكم بالوصول (ACL) لهذه الغُرفة.</string>
<string name="notice_room_server_acl_set_ip_literals_not_allowed">• الخوادِم المتطابقة من حيث بروتوكول الإنترنت (IP) المستخدم محظورة.</string>
<string name="notice_room_server_acl_set_allowed">• الخوادِم المُطابقة لـِ %s مسموحة.</string>
<string name="notice_room_server_acl_set_banned">• الخوادِم المُطابقة لـ %s محظورة.</string>
<string name="notice_room_server_acl_set_ip_literals_allowed">الخوادِم المتطابقة من حيث بروتوكول الإنترنت (IP) المستخدم مسموحة.</string>
<string name="notice_room_server_acl_set_title_by_you">لقد قمت بتعيين قائمة التحكم بالوصول لهذه الغُرفة.</string>
<string name="notice_room_server_acl_set_title">%s قام بتعيين قائمة التحكم بالوصول لهذه الغرفة.</string>
<string name="notice_room_server_acl_set_title_by_you">لقد عيَّنت قائمة التحكم بالوصول لهذه الغُرفة.</string>
<string name="notice_room_server_acl_set_title">عيَّنَ %s قائمة التحكم بالوصول لهذه الغرفة.</string>
<string name="notice_direct_room_update_by_you">رقيتَ هُنا.</string>
<string name="notice_direct_room_update">رقّى %s هُنا.</string>
<string name="notice_made_future_direct_room_visibility_by_you">جعلتَ الرسائل المُستقبلية مرئية لـ %1$s</string>
@ -895,11 +895,11 @@
<item quantity="other">%d ثانية</item>
</plurals>
<string name="login_server_url_form_other_hint">العنوان</string>
<string name="login_clear_homeserver_history">امسح التأريخ</string>
<string name="login_clear_homeserver_history">امسح التاريخ</string>
<string name="login_signin">لِج</string>
<string name="login_signup">سجّل</string>
<string name="login_signin_to">لج عبر %1$s</string>
<string name="login_connect_to_a_custom_server">اتص بخادم مخصص</string>
<string name="login_connect_to_a_custom_server">اتصل بخادم مخصص</string>
<string name="login_connect_to_modular">اتصل بخدمات مايتركس لـ Element</string>
<string name="login_connect_to">اتصل بـ %1$s</string>
<string name="login_continue">تابع</string>
@ -1168,4 +1168,9 @@
<string name="initial_sync_request_title">طَلَبُ مُزامَنة أوَّلِيّ</string>
<string name="a11y_public_room">غُرفة عامة</string>
<string name="a11y_video">تسجيل مرئيّ</string>
<string name="login_reset_password_error_not_found">هذا البريد الإلكتروني غير مربوط بأي حساب</string>
<string name="login_reset_password_warning_submit">تابع</string>
<string name="login_reset_password_email_hint">البريد الإلكتروني</string>
<string name="login_reset_password_password_hint">كلمة السر الجديدة</string>
<string name="login_reset_password_submit">التالي</string>
</resources>

View File

@ -1277,7 +1277,7 @@
<string name="open_terms_of">Consulta els termes de %s</string>
<string name="login_terms_title">Accepta els termes per a continuar</string>
<string name="settings_discovery_disconnect_with_bound_pid">Estàs compartint les adreces de correu electrònic o números de telèfon amb el servidor d\'identitat %1$s. Per parar de compartir-les t\'has de tornar a connectar a %2$s.</string>
<string name="message_view_edit_history">Visualitza Edita Històric</string>
<string name="message_view_edit_history">Visualitza l\'històric d\'edició</string>
<string name="settings_show_redacted_summary">Indica els missatges eliminats</string>
<string name="bootstrap_migration_backup_recovery_key">Clau de recuperació de la còpia de seguretat de claus</string>
<string name="bootstrap_migration_use_recovery_key">utilitzar la clau de recuperació de còpia de seguretat de claus</string>
@ -1777,7 +1777,7 @@
<string name="verify_this_session">Verifica el nou inici de sessió que està accedint al teu compte: %1$s</string>
<string name="verification_open_other_to_verify">Utilitza aquesta sessió per a verificar-ne una de nova i poder-li donar accés als missatges xifrats.</string>
<string name="verification_profile_device_untrust_info">Fins que aquest usuari no confiï en aquesta sessió, els missatges enviats i rebuts es marcaran amb una alerta. Com a alternativa, pots verificar-lo manualment.</string>
<string name="crosssigning_verify_this_session">Verifica aquest inici de sessió</string>
<string name="crosssigning_verify_this_session">Verifica aquest dispositiu</string>
<string name="settings_active_sessions_unverified_device_desc">Verifica aquesta sessió per fer-la de confiança i permetre que accedeixi als missatges xifrats. Si no has estat tu el que ha iniciat sessió aquí, pot ser que el teu compte estigui compromès:</string>
<string name="verification_verify_device">Verifica aquesta sessió</string>
<string name="verification_conclusion_compromised">Alguna de les següents pot haver estat compromesa:
@ -2228,7 +2228,7 @@
<string name="error_file_too_big_simple">El fitxer és massa gran per carregar-lo.</string>
<string name="attachment_type_location">Ubicació</string>
<string name="ftue_auth_carousel_encrypted_body">Xifrat d\'extrem a extrem i sense haver de donar cap número de telèfon. Sense anuncis ni extracció de dades.</string>
<string name="ftue_auth_carousel_control_body">Tria on es desen les teves converses, donant-te control i independència. Connectat a través de Matrix.</string>
<string name="ftue_auth_carousel_control_body">Tria on es desen les teves converses, et dona control i independència. Connectat a través de Matrix.</string>
<string name="ftue_auth_carousel_secure_body">Comunicació segura i independent que t\'ofereix el mateix nivell de privadesa que una conversa cara a cara a casa teva.</string>
<string name="ftue_auth_carousel_workplace_title">Missatgeria pel teu equip.</string>
<string name="ftue_auth_carousel_encrypted_title">Missatgeria segura.</string>
@ -2535,7 +2535,7 @@
<string name="send_your_first_msg_to_invite">Envia un primer missatge per convidar %s a parlar</string>
<string name="direct_room_encryption_enabled_tile_description_future">Els missatges d\'aquest xat seran xifrats d\'extrem a extrem.</string>
<string name="create_room_action_go">Crea</string>
<string name="ftue_auth_email_verification_subtitle">Confirma el teu correu electrònic, prem el botó del correu que t\'hem enviat a %s</string>
<string name="ftue_auth_email_verification_subtitle">Segueix les instruccions enviades a %s</string>
<string name="ftue_auth_terms_subtitle">Si us plau, llegeix les condicions i polítiques de %s</string>
<string name="ftue_auth_choose_server_ems_cta">Contacta</string>
<string name="ftue_auth_create_account_username_entry_footer">Et podran trobar com a %s</string>
@ -2547,7 +2547,7 @@
<string name="ftue_auth_login_username_entry">Usuari / Correu / Telèfon</string>
<string name="permalink_unsupported_groups">No es pot obrir l\'enllaç: les comunitats han estat substituïdes pels espais</string>
<string name="live_location_not_enough_permission_dialog_title">No tens permís per compartir la ubicació en directe</string>
<string name="ftue_auth_email_verification_title">Comprova el teu correu per verificar.</string>
<string name="ftue_auth_email_verification_title">Verifica el teu correu</string>
<string name="ftue_auth_phone_confirmation_resend_code">Torna a enviar el codi</string>
<string name="ftue_auth_phone_confirmation_subtitle">S\'ha enviat un codi al %s</string>
<string name="ftue_auth_phone_confirmation_title">Confirma el teu número de telèfon</string>
@ -2588,4 +2588,19 @@
<string name="ftue_auth_password_reset_confirmation">Restabliment de contrasenya</string>
<string name="ftue_auth_forgot_password">Contrasenya oblidada</string>
<string name="ftue_auth_choose_server_ems_subtitle">Element Matrix Services (EMS) és un servei robust i fiable d\'allotjament (servidors) per comunicacions ràpides, segures i en temps real. Descobreix-ho a &lt;a href=\"${ftue_ems_url}\"&gt;element.io/ems&lt;/a&gt;</string>
<string name="crosssigning_cannot_verify_this_session_desc">No podràs accedir a l\'històric de missatges xifrats. Restableix la còpia de seguretat de missatges i les claus de verificació per començar de nou.</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">Aprova automàticament els ginys d\'Element Call i permet l\'accés a la càmera i el micròfon</string>
<string name="labs_enable_element_call_permission_shortcuts">Activa els permisos d\'accés directe d\'Element Call</string>
<string name="live_location_description">Ubicació en directe</string>
<string name="verify_invalid_qr_notice">Aquest codi QR sembla incorrecte. Prova de fer la verificació amb un altre mètode.</string>
<string name="crosssigning_cannot_verify_this_session">No s\'ha pogut verificar aquest dispositiu</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Quina és l\'adreça del teu servidor\?</string>
<string name="ftue_auth_sign_in_choose_server_header">On viuen les teves converses</string>
<string name="updating_your_data">Actualitzant dades…</string>
<plurals name="search_space_multiple_parents">
<item quantity="one">%1$s i %2$d altre</item>
<item quantity="other">%1$s i %2$d altres</item>
</plurals>
<string name="search_space_two_parents">%1$s i %2$s</string>
<string name="auth_reset_password_error_unverified">Correu no verificat, mira la teva safata d\'entrada</string>
</resources>

View File

@ -1321,7 +1321,7 @@
<item quantity="few">%d aktivní relace</item>
<item quantity="other">%d aktivních relací</item>
</plurals>
<string name="crosssigning_verify_this_session">Ověřit tuto relaci</string>
<string name="crosssigning_verify_this_session">Ověřit toto zařízení</string>
<string name="verification_open_other_to_verify">Pro ověření této relace použijte existující relaci, a tím ji udělíte přístup k zašifrovaným zprávám.</string>
<string name="verification_profile_verify">Ověřit</string>
<string name="verification_profile_verified">Ověřeno</string>
@ -2599,8 +2599,8 @@
<string name="ftue_auth_forgot_password">Zapomenuté heslo</string>
<string name="ftue_auth_email_resend_email">Znovu poslat e-mail</string>
<string name="ftue_auth_email_verification_footer">Nepřišel vám e-mail\?</string>
<string name="ftue_auth_email_verification_subtitle">Pro potvrzení e-mailu klepněte na tlačítko ve zprávě, kterou jsme právě odeslali na adresu %s</string>
<string name="ftue_auth_email_verification_title">Pro ověření si zkontrolujte svůj e-mail.</string>
<string name="ftue_auth_email_verification_subtitle">Postupujte podle pokynů zaslaných na adresu %s</string>
<string name="ftue_auth_email_verification_title">Ověřte svůj e-mail</string>
<string name="ftue_auth_phone_confirmation_resend_code">Znovu odeslat kód</string>
<string name="ftue_auth_phone_confirmation_subtitle">Kód byl odeslán na %s</string>
<string name="ftue_auth_phone_confirmation_title">Potvrďte své telefonní číslo</string>
@ -2637,4 +2637,20 @@
<string name="font_size_section_manually">Zvolit ručně</string>
<string name="font_size_section_auto">Nastavit automaticky</string>
<string name="font_size_title">Volba velikosti písma</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">Automaticky schvalovat widgety Element hovorů a udělit přístup ke kameře/mikrofonu</string>
<string name="labs_enable_element_call_permission_shortcuts">Zapnout zkratky pro povolení Element hovorů</string>
<string name="live_location_description">Poloha živě</string>
<string name="verify_invalid_qr_notice">Tento kód QR vypadá chybně. Zkuste provést ověření jinou metodou.</string>
<string name="crosssigning_cannot_verify_this_session_desc">Nebudete mít přístup k historii zašifrovaných zpráv. Obnovte zálohování zabezpečených zpráv a ověřovací klíče a začněte znovu.</string>
<string name="crosssigning_cannot_verify_this_session">Nepodařilo se ověřit toto zařízení</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Jaká je adresa vašeho serveru\?</string>
<string name="ftue_auth_sign_in_choose_server_header">Kde žijí vaše konverzace</string>
<string name="updating_your_data">Aktualizace vašich dat…</string>
<plurals name="search_space_multiple_parents">
<item quantity="one">%1$s a %2$d další</item>
<item quantity="few">%1$s a %2$d další</item>
<item quantity="other">%1$s a %2$d dalších</item>
</plurals>
<string name="search_space_two_parents">%1$s a %2$s</string>
<string name="auth_reset_password_error_unverified">E-mail nebyl ověřen, zkontrolujte si schránku</string>
</resources>

View File

@ -1092,7 +1092,7 @@
<string name="login_reset_password_email_hint">E-Mail</string>
<string name="login_reset_password_password_hint">Neues Passwort</string>
<string name="login_reset_password_warning_title">Achtung!</string>
<string name="login_reset_password_warning_content">Eine Änderung deines Passworts wird alle Ende-zu-Ende-Schlüssek zurücksetzen. Dein verschlüsselter Chatverlauf wird dadurch unlesbar. Richte die Schlüsselsicherung ein oder exportiere deine Raumschlüssel aus einer anderen Sitzung, bevor du dein Passwort zurücksetzt.</string>
<string name="login_reset_password_warning_content">Eine Änderung deines Passworts wird alle Ende-zu-Ende-Schlüssel zurücksetzen. Dein verschlüsselter Chatverlauf wird dadurch unlesbar. Richte die Schlüsselsicherung ein oder exportiere deine Raumschlüssel aus einer anderen Sitzung, bevor du dein Passwort zurücksetzt.</string>
<string name="login_reset_password_warning_submit">Fortfahren</string>
<string name="login_reset_password_error_not_found">Diese E-Mail-Adresse ist mit keinem Benutzerkonto verknüpft</string>
<string name="login_reset_password_mail_confirmation_title">Prüfe deinen Posteingang</string>
@ -1297,7 +1297,7 @@
<item quantity="one">Eine aktive Sitzung</item>
<item quantity="other">%d aktive Sitzungen</item>
</plurals>
<string name="crosssigning_verify_this_session">Verifiziere diese Sitzung</string>
<string name="crosssigning_verify_this_session">Verifiziere dieses Gerät</string>
<string name="verification_open_other_to_verify">Nutze eine vorhandene Sitzung um diese Sitzung zu verifizieren und ihr Zugriff auf verschlüsselte Nachrichten zu gewähren.</string>
<string name="verification_profile_verify">Verifizieren</string>
<string name="verification_profile_verified">Verifiziert</string>
@ -1520,7 +1520,7 @@
<string name="secure_backup_banner_setup_line1">Backup</string>
<string name="secure_backup_banner_setup_line2">Absicherung gegen den Verlust verschlüsselter Nachrichten</string>
<string name="secure_backup_setup">Richte Backup ein</string>
<string name="event_redacted">Nachricht gelöscht</string>
<string name="event_redacted">Nachricht entfernt</string>
<string name="settings_show_redacted">Gelöschte Nachrichten zeigen</string>
<string name="settings_show_redacted_summary">Zeigt einen Platzhalter für gelöschte Nachrichten an</string>
<string name="labs_show_unread_notifications_as_tab">Dedizierten Tab für ungelesene Nachrichten zur Hauptansicht hinzufügen</string>
@ -2367,7 +2367,7 @@
<string name="ftue_auth_use_case_join_existing_server">Möchtest du einem existierenden Server beitreten\?</string>
<string name="ftue_auth_use_case_option_three">Communities</string>
<string name="ftue_auth_use_case_option_two">Teams</string>
<string name="ftue_auth_use_case_subtitle">Wir helfen dir, in Verbindung zu kommen.</string>
<string name="ftue_auth_use_case_subtitle">Wir helfen dir, in Verbindung zu kommen</string>
<string name="ftue_auth_use_case_title">Mit wem wirst du am meisten chatten\?</string>
<string name="action_thread_copy_link_to_thread">Link zu Thread kopieren</string>
<string name="action_view_threads">Threads anzeigen</string>
@ -2375,8 +2375,8 @@
<string name="location_timeline_failed_to_load_map">Laden der Karte fehlgeschlagen</string>
<string name="a11y_static_map_image">Karte</string>
<string name="labs_enable_thread_messages_desc">Hinweis: App wird neugestartet</string>
<string name="ftue_auth_use_case_skip_partial">diese Frage überspringen</string>
<string name="ftue_auth_use_case_skip">Noch nicht sicher\? Du kannst %s</string>
<string name="ftue_auth_use_case_skip_partial">Diese Frage überspringen</string>
<string name="ftue_auth_use_case_skip">Noch nicht sicher\? %s</string>
<string name="ftue_auth_use_case_option_one">Freunde und Familie</string>
<string name="reply_in_thread">In Thread antworten</string>
<string name="search_thread_from_a_thread">Aus einem Thread</string>
@ -2471,7 +2471,7 @@
<string name="a11y_audio_message_item">%1$s, %2$s, %3$s</string>
<string name="settings_show_latest_profile_description">Die neuesten Profilinformationen (Avatar und Anzeigename) für alle Nachrichten anzeigen.</string>
<string name="settings_show_latest_profile">Aktuelle Benutzerinformationen anzeigen</string>
<string name="ftue_personalize_complete_title">Du kannst loslegen!</string>
<string name="ftue_personalize_complete_title">Sieht gut aus!</string>
<string name="ftue_display_name_title">einen Anzeigenamen wählen</string>
<string name="ftue_account_created_take_me_home">Zurück zum Home-Screen</string>
<string name="send_feedback_threads_title">Threads Beta-Feedback</string>
@ -2516,17 +2516,67 @@
<string name="sent_live_location">teilten ihren Live-Standort</string>
<string name="ftue_personalize_skip_this_step">Schritt überspringen</string>
<string name="ftue_personalize_submit">Speichern und fortfahren</string>
<string name="ftue_personalize_complete_subtitle">Deine Einstellungen wurden gespeichert.</string>
<string name="ftue_personalize_complete_subtitle">Öffne die Einstellungen jederzeit um dein Profil zu aktualisieren</string>
<string name="ftue_personalize_lets_go">Los geht\'s</string>
<string name="ftue_profile_picture_subtitle">Du kannst das jederzeit ändern.</string>
<string name="ftue_profile_picture_subtitle">Zeit, dem Namen ein Gesicht zu geben</string>
<string name="ftue_profile_picture_title">Profilbild hinzufügen</string>
<string name="ftue_display_name_entry_footer">Du kannst dies später ändern</string>
<string name="ftue_display_name_entry_title">Anzeigename</string>
<string name="ftue_display_name_subtitle">Dies wird angezeigt, wenn Du Nachrichten sendest.</string>
<string name="ftue_account_created_subtitle">Dein Konto %s wurde erstellt.</string>
<string name="ftue_account_created_subtitle">Dein Konto %s wurde erstellt</string>
<string name="ftue_account_created_congratulations_title">Herzlichen Glückwunsch!</string>
<string name="ftue_account_created_personalize">Profil personalisieren</string>
<string name="ftue_auth_carousel_workplace_body">${app_name} ist auch für den Arbeitsplatz geeignet. Die sichersten Organisationen der Welt vertrauen darauf.</string>
<string name="send_feedback_threads_info">Threads sind noch in Arbeit, und es stehen neue, aufregende Funktionen an, wie z. B. verbesserte Benachrichtigungen. Wir würden uns sehr über Dein Feedback freuen!</string>
<string name="direct_room_encryption_enabled_tile_description_future">Nachrichten in diesem Chat werden End-zu-End-Verschlüsselt</string>
<string name="direct_room_encryption_enabled_tile_description_future">Nachrichten in diesem Chat werden Ende-zu-Ende-verschlüsselt.</string>
<string name="ftue_auth_captcha_title">Bist du ein Mensch\?</string>
<string name="ftue_auth_terms_subtitle">Bitte lies dir %ss Bedingungen und Richtlinien durch</string>
<string name="ftue_auth_terms_title">Server-Richtlinien</string>
<string name="ftue_auth_email_verification_subtitle">Folge den Anweisungen, die an %s gesendet wurden</string>
<string name="ftue_auth_email_verification_title">E-Mail bestätigen</string>
<string name="poll_undisclosed_not_ended">Ergebnisse sind nach Beenden der Abstimmung sichtbar</string>
<string name="ftue_auth_reset_password_breaker_title">Prüfe deine E-Mails.</string>
<string name="ftue_auth_reset_password">Passwort zurücksetzen</string>
<string name="ftue_auth_new_password_subtitle">Gib mindestens 8 Zeichen ein.</string>
<string name="ftue_auth_email_entry_title">E-Mail-Adresse</string>
<string name="ftue_auth_phone_entry_title">Telefonnummer</string>
<string name="ftue_auth_email_resend_email">Erneut senden</string>
<string name="ftue_auth_reset_password_email_subtitle">%s wird dir einen Bestätigungslink schicken</string>
<string name="ftue_auth_email_title">Deine E-Mail-Adresse</string>
<string name="ftue_auth_new_password_entry_title">Neues Passwort</string>
<string name="ftue_auth_new_password_title">Wähle ein neues Passwort</string>
<string name="ftue_auth_sign_out_all_devices">Alle Geräte abmelden</string>
<string name="ftue_auth_phone_confirmation_title">Bestätige deine Telefonnummer</string>
<string name="ftue_auth_email_verification_footer">Keine E-Mail erhalten\?</string>
<string name="ftue_auth_password_reset_email_confirmation_subtitle">Folge den Anweisungen, die an %s gesendet wurden</string>
<string name="permalink_unsupported_groups">Kann Link nicht öffnen: Communities wurden durch Spaces ersetzt</string>
<string name="labs_enable_msc3061_share_history">MSC3061: Raumschlüssel für vorherige Nachrichten teilen</string>
<string name="labs_enable_msc3061_share_history_desc">Beim Einladen in einen Raum mit sichtbarem Verlauf wird der verschlüsselte Verlauf sichtbar sein.</string>
<string name="live_location_description">Live-Standort</string>
<plurals name="room_removed_messages">
<item quantity="one">%d Nachricht gelöscht</item>
<item quantity="other">%d Nachrichten gelöscht</item>
</plurals>
<string name="labs_enable_element_call_permission_shortcuts">Keine Element Call-Berechtigungsabfragen</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">Bestätige automatisch Element Call-Widgets und erlaube Kamera- und Mikrofonzugriff</string>
<string name="create_room_action_go">Los</string>
<string name="ftue_auth_create_account_edit_server_selection">ändern</string>
<string name="ftue_auth_create_account_sso_section_header">oder</string>
<string name="ftue_auth_sign_in_choose_server_header">Das Zuhause deiner Gespräche</string>
<string name="ftue_auth_create_account_choose_server_header">Das zukünftige Zuhause für deine Gespräche</string>
<string name="font_size_use_system">Systemstandard nutzen</string>
<string name="font_size_section_auto">Automatisch festlegen</string>
<string name="font_size_title">Schriftgröße wählen</string>
<string name="font_size_section_manually">Manuell wählen</string>
<string name="search_space_two_parents">%1$s und %2$s</string>
<string name="auth_reset_password_error_unverified">E-Mail nicht bestätigt, prüfe deinen Posteingang</string>
<string name="ftue_auth_welcome_back_title">Willkommen zurück!</string>
<string name="ftue_auth_forgot_password">Passwort vergessen</string>
<string name="ftue_auth_login_username_entry">Benutzername / E-Mail / Telefon</string>
<string name="ftue_auth_create_account_title">Erstelle dein Konto</string>
<string name="ftue_auth_choose_server_entry_hint">Serveradresse</string>
<string name="ftue_auth_choose_server_subtitle">Wie lautet die Adresse deines Servers\? Das wird eine Art Zuhause für deine Daten</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Wie lautet die Adresse deines Servers\?</string>
<string name="ftue_auth_create_account_password_entry_footer">Muss 8 oder mehr Zeichen umfassen</string>
<string name="ftue_auth_choose_server_title">Wähle deinen Server</string>
</resources>

View File

@ -720,7 +720,7 @@
<item quantity="one">%d aktiivne sessioon</item>
<item quantity="other">%d aktiivset sessiooni</item>
</plurals>
<string name="crosssigning_verify_this_session">Verifitseeri see sisselogimissessioon</string>
<string name="crosssigning_verify_this_session">Verifitseeri see seade</string>
<string name="verification_open_other_to_verify">Kasuta olemasolevat sessiooni selle sessiooni verifitseerimiseks, andes sellega ligipääsu krüptitud sõnumitele.</string>
<string name="verification_profile_verify">Verifitseeri</string>
<string name="verification_profile_verified">Verifitseeritud</string>
@ -2541,8 +2541,8 @@
<string name="ftue_auth_forgot_password">Kas unustasid oma salasõna</string>
<string name="ftue_auth_email_resend_email">Saada e-kiri uuesti</string>
<string name="ftue_auth_email_verification_footer">Sa ei saanud e-kirja kätte\?</string>
<string name="ftue_auth_email_verification_subtitle">Oma e-posti aadressi kinnitamiseks klõpsi selles kirjas leiduvat nuppu, mille just saatsime %s aadressile</string>
<string name="ftue_auth_email_verification_title">Kinnitamiseks vaata oma e-kirju.</string>
<string name="ftue_auth_email_verification_subtitle">Palun järgi juhtnööre, mille just saatsime %s aadressile</string>
<string name="ftue_auth_email_verification_title">Verifitseeri oma e-posti aadress</string>
<string name="ftue_auth_phone_confirmation_resend_code">Saada kinnituskood uuesti</string>
<string name="ftue_auth_phone_confirmation_subtitle">Kinnituskoodi saatsime telefoninumbrile %s</string>
<string name="ftue_auth_phone_confirmation_title">Kinnita oma telefoninumber</string>
@ -2579,4 +2579,19 @@
<string name="font_size_section_manually">Vali ise</string>
<string name="font_size_section_auto">Määra automaatselt</string>
<string name="font_size_title">Vali kirjatüübi suurus</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">Automaatsel luba kasutada Element\'i põhiste kõnede vidinaid ning luba ligipääs kaamerale ja mikrofonile</string>
<string name="labs_enable_element_call_permission_shortcuts">Võta kasutsele Element\'i põhiste kõnede õiguste kiirnupud</string>
<string name="live_location_description">Asukoht reaalajas</string>
<string name="verify_invalid_qr_notice">See QR-kood tundub olema vigane. Palun proovi verifitseerimist mõne muu meetodiga.</string>
<string name="crosssigning_cannot_verify_this_session_desc">Sa ei saa lugeda varasemaid krüptitud sõnumeid. Uuesti alustamiseks seadista varundusvõtmed ja verifitseerimisvõtmed.</string>
<string name="crosssigning_cannot_verify_this_session">Selle seadme verifitseerimine ei õnnestunud</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Mis on sinu koduserveri aadress\?</string>
<string name="ftue_auth_sign_in_choose_server_header">Kuidas sinu vestlusi hallatakse</string>
<string name="updating_your_data">Sinu andmed on uuendamisel…</string>
<plurals name="search_space_multiple_parents">
<item quantity="one">%1$s ja veel %2$d</item>
<item quantity="other">%1$s ja veel %2$d muud</item>
</plurals>
<string name="search_space_two_parents">%1$s ja %2$s</string>
<string name="auth_reset_password_error_unverified">E-posti aadress on kinnitamata, palun vaata oma saabunud e-kirju</string>
</resources>

View File

@ -982,7 +982,7 @@
<string name="encryption_information_dg_xsigning_disabled">ورود چندگانه به کار نیفتاده</string>
<string name="settings_hs_admin_e2e_disabled">مدیر کارسازتان رمزنگاری سرتاسری پیش‌گزیده را در اتاق‌های خصوصی و پیام‌های مستقیم از کار انداخته است.</string>
<string name="settings_active_sessions_signout_device">خروج از این نشست</string>
<string name="crosssigning_verify_this_session">تأیید این ورود</string>
<string name="crosssigning_verify_this_session">تأیید این افزاره</string>
<string name="verification_open_other_to_verify">استفاده از نشستی موجود برای تأییدش که به پیام‌های رمزشده دسترسی می‌دهد.</string>
<string name="verification_profile_verify">تأیید</string>
<string name="verification_profile_verified">تأیید‌شده</string>
@ -2550,8 +2550,8 @@
<string name="ftue_auth_forgot_password">فراموشی گذرواژه</string>
<string name="ftue_auth_email_resend_email">فرستادن دوبارهٔ رایانامه</string>
<string name="ftue_auth_email_verification_footer">رایانامه‌ای نگرفتید؟</string>
<string name="ftue_auth_email_verification_subtitle">برای تأیید رایانامه‌تان، روی دکمه در رایانامه‌ای‌که اکنون برایتان به %s فرستادیم بزنید</string>
<string name="ftue_auth_email_verification_title">برای تأیید، رایانامه‌تان را بررسی کنید.</string>
<string name="ftue_auth_email_verification_subtitle">دستورالعمل‌های فرستاده شده به %s را دنبال کنید</string>
<string name="ftue_auth_email_verification_title">رایانامه‌تان را تأیید کنید</string>
<string name="ftue_auth_phone_confirmation_resend_code">فرستادن دوبارهٔ رمز</string>
<string name="ftue_auth_phone_confirmation_subtitle">رمزی به %s فرستاده خواهد شد</string>
<string name="ftue_auth_phone_confirmation_title">شمارهٔ تلفنتان را تأیید کنید</string>
@ -2588,4 +2588,19 @@
<string name="font_size_section_manually">گزینش دستی</string>
<string name="font_size_section_auto">تنظیم خودکار</string>
<string name="font_size_title">گزینش اندازهٔ قلم</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">تأیید خودکار ابزارک‌های تماس و اعطای دسترسی دوربین و میکروفون</string>
<string name="labs_enable_element_call_permission_shortcuts">به کار انداخت میان‌برهای اجازهٔ تماس المنت</string>
<string name="live_location_description">مکان زنده</string>
<string name="verify_invalid_qr_notice">این رمز QR بدریخت به نظر می‌رسد. لطفاً تأیید با روشی دیگر را بیازمایید.</string>
<string name="crosssigning_cannot_verify_this_session_desc">نخواهید توانست به تاریخچهٔ پیام رمزشده دست یابید. برای آغاز تازه، کلیدهای تأیید و پشتیبان پیام امنتان را بازنشانی کنید.</string>
<string name="crosssigning_cannot_verify_this_session">ناتوان در تأیید این افزاره</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">نشانی کارسازتان چیست؟</string>
<string name="ftue_auth_sign_in_choose_server_header">زیستگاه گفت‌وگوهایتان</string>
<string name="updating_your_data">به‌روز رساندن داده‌هایتان…</string>
<plurals name="search_space_multiple_parents">
<item quantity="one">%1$s و ۱ والد دیگر</item>
<item quantity="other">%1$s و %2$d والد دیگر</item>
</plurals>
<string name="search_space_two_parents">%1$s و %2$s</string>
<string name="auth_reset_password_error_unverified">رایانامه تأیید نشده. صندوق ورودیتان را بررسی کنید</string>
</resources>

View File

@ -1273,7 +1273,7 @@
<item quantity="one">%d session active</item>
<item quantity="other">%d sessions actives</item>
</plurals>
<string name="crosssigning_verify_this_session">Vérifier cette session</string>
<string name="crosssigning_verify_this_session">Vérifier cet appareil</string>
<string name="verification_open_other_to_verify">Utilisez une session existante pour vérifier celle-ci, ce qui lui permettra davoir accès aux messages chiffrés.</string>
<string name="verification_profile_verify">Vérifier</string>
<string name="verification_profile_verified">Vérifié</string>
@ -2550,8 +2550,8 @@
<string name="ftue_auth_forgot_password">Mot de passe oublié</string>
<string name="ftue_auth_email_resend_email">Renvoyer le courriel</string>
<string name="ftue_auth_email_verification_footer">Pas reçu de courriel \?</string>
<string name="ftue_auth_email_verification_subtitle">Pour confirmer votre courriel, appuyez sur le bouton dans le courriel que nous venons denvoyer à %s</string>
<string name="ftue_auth_email_verification_title">Relevez vos courriels pour la vérification.</string>
<string name="ftue_auth_email_verification_subtitle">Suivez les instructions envoyées à %s</string>
<string name="ftue_auth_email_verification_title">Vérifiez votre courriel</string>
<string name="ftue_auth_phone_confirmation_resend_code">Renvoyer le code</string>
<string name="ftue_auth_phone_confirmation_subtitle">Un code a été envoyé au %s</string>
<string name="ftue_auth_phone_confirmation_title">Confirmer votre numéro de téléphone</string>
@ -2588,4 +2588,19 @@
<string name="font_size_section_manually">Choisir manuellement</string>
<string name="font_size_section_auto">Automatique</string>
<string name="font_size_title">Choisir la taille de la police</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">Approuve automatiquement les widgets de Element Call et leur donner laccès au micro et à la caméra</string>
<string name="labs_enable_element_call_permission_shortcuts">Activer les raccourcis de permission de Element Call</string>
<string name="live_location_description">Position en direct</string>
<string name="verify_invalid_qr_notice">Ce QR code semble incorrect. Veuillez réessayer la vérification avec une autre méthode.</string>
<string name="crosssigning_cannot_verify_this_session_desc">Vous ne pourrez plus accéder à lhistorique des messages chiffrés. Réinitialiser votre sauvegarde sécurisée des messages et vos clés de récupération pour un nouveau départ.</string>
<string name="crosssigning_cannot_verify_this_session">Impossible de vérifier cet appareil</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Quelle est ladresse de votre serveur \?</string>
<string name="ftue_auth_sign_in_choose_server_header">Où seront vos conversations</string>
<string name="updating_your_data">Mise-à-jour de vos données…</string>
<plurals name="search_space_multiple_parents">
<item quantity="one">%1$s et %2$d autre</item>
<item quantity="other">%1$s et %2$d autres</item>
</plurals>
<string name="search_space_two_parents">%1$s et %2$s</string>
<string name="auth_reset_password_error_unverified">Courriel non vérifié, relevez votre boîte de réception</string>
</resources>

View File

@ -1064,9 +1064,9 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
<string name="login_mode_not_supported">Az alkalmazás nem tud bejelentkezni a Matrix szerverbe. A Matrix szerver ezeket a bejelentkezési módokat támogatja: %1$s.
\n
\nWeb klienssel szeretnél bejelentkezni\?</string>
<string name="login_registration_not_supported">Az alkalmazás nem tud fiókot készíteni ezen a Matrix szerveren.
<string name="login_registration_not_supported">Ez az alkalmazás nem tudott fiókot készíteni ezen a Matrix szerveren.
\n
\nWeb klienssel szeretnél bejelentkezni\?</string>
\nSzeretnél a webes kliens segítségével létrehozni egy fiókot\?</string>
<string name="login_reset_password_mail_confirmation_notice_2">Koppints a linkre az új jelszó megerősítéséhez. Miután követted a linket, kattints alább.</string>
<string name="login_set_email_notice">Állíts be egy e-mail címet a fiókod visszaállításához. Később esetleg engedélyezheted, hogy ismerősök e-mail címmel megtalálhassanak.</string>
<string name="login_msisdn_error_not_international">Nemzetközi telefonszámnak „+” jellel kell kezdődnie</string>
@ -1077,7 +1077,7 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
<string name="login_signup_submit">Következő</string>
<string name="login_signup_error_user_in_use">A felhasználónév már használatban van</string>
<string name="login_signup_cancel_confirmation_title">Figyelmeztetés</string>
<string name="login_signup_cancel_confirmation_content">A felhasználói fiókod még nincs kész. Megállítód a regisztrációt\?</string>
<string name="login_signup_cancel_confirmation_content">A felhasználói fiókod még nincs kész. Félbehagyod a regisztrációt\?</string>
<string name="login_a11y_choose_matrix_org">matrix.org kiválasztása</string>
<string name="login_a11y_choose_modular">Element Matrix Services kiválasztása</string>
<string name="login_a11y_choose_other">Egyedi matrix szerver kiválasztása</string>
@ -2318,7 +2318,7 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
<string name="restart_the_application_to_apply_changes">A változások életbelépéséhez indítsd újra az alkalmazást.</string>
<string name="labs_enable_latex_maths">LaTeX matematikai szintaxis engedélyezése</string>
<string name="room_error_access_unauthorized">Nem léphetsz be ebbe a szobába</string>
<string name="ftue_auth_carousel_secure_title">Birtokold a beszélgetéseid.</string>
<string name="ftue_auth_carousel_secure_title">Vedd birtokba a beszélgetéseid.</string>
<string name="labs_auto_report_uisi_desc">Titkosítás visszafejtési hiba esemény alkalmával a rendszer automatikusan elküldi a logokat</string>
<string name="labs_auto_report_uisi">Titkosítás visszafejtési hibák automatikus jelentése.</string>
<string name="tooltip_attachment_poll">Szavazás létrehozása</string>
@ -2330,7 +2330,7 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
<string name="room_member_override_nick_color">Megjelenítendő név színének megváltoztatása</string>
<string name="login_splash_already_have_account">Már van fiókom</string>
<string name="ftue_auth_carousel_encrypted_title">Biztonságos üzenetküldés.</string>
<string name="ftue_auth_carousel_control_title">Te irányítasz.</string>
<string name="ftue_auth_carousel_control_title">Tiéd az irányítás.</string>
<string name="tooltip_attachment_location">Tartózkodási hely megosztása</string>
<string name="location_share_external">Megnyitás ezzel</string>
<string name="location_not_available_dialog_content">Az ${app_name} nem fér hozzá a tartózkodási helyedhez. Próbáld újra később.</string>
@ -2351,9 +2351,9 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
<string name="sent_location">A földrajzi helyzetüket megosztották</string>
<string name="login_splash_create_account">Fiók létrehozása</string>
<string name="ftue_auth_carousel_workplace_title">Üzenetküldés a csoportodnak.</string>
<string name="ftue_auth_carousel_encrypted_body">Telefonszám nélkül végpontok között titkosított. Reklámok és adatbányászat nélkül.</string>
<string name="ftue_auth_carousel_control_body">Válaszd meg hol legyenek a beszélgetéseid tárolva, visszaadja az irányítást és függetlenné tesz. Csatlakozva a Matrixhoz.</string>
<string name="ftue_auth_carousel_secure_body">Biztonságos és független kommunikáció ami olyan biztonságos mintha valakivel négyszemközt beszélgetnél a házadban.</string>
<string name="ftue_auth_carousel_encrypted_body">Végponti tikosítással és telefonszám nélküli regisztrációval. Reklámok és adatbányászat nélkül.</string>
<string name="ftue_auth_carousel_control_body">Te választhatod ki, hogy hol legyenek a beszélgetéseid tárolva, ezáltal visszadva az irányítást és a függetlenséget neked. A Matrix hálózathoz csatlakozva.</string>
<string name="ftue_auth_carousel_secure_body">Biztonságos és független kommunikáció, ami olyan biztonságos mint ha valakivel négyszemközt beszélgetnél a házadban.</string>
<string name="attachment_type_location">Földrajzi helyzet</string>
<string name="room_unsupported_e2e_algorithm_as_admin">A titkosítás beállítása hibás így nem lehet üzenetet küldeni. Kattints a beállításokért.</string>
<string name="room_unsupported_e2e_algorithm">A titkosítás beállítása hibás így nem lehet üzenetet küldeni. Kérjük vedd fel a kapcsolatot az adminisztrátorral a titkosítás helyreállításához.</string>
@ -2367,9 +2367,9 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
<string name="ftue_auth_use_case_skip_partial">Kihagyhatod ezt a kérdést.</string>
<string name="ftue_auth_use_case_skip">Még nem tudod\? %s</string>
<string name="ftue_auth_use_case_option_three">Közösségek</string>
<string name="ftue_auth_use_case_option_two">Csoportok</string>
<string name="ftue_auth_use_case_option_two">Munkahelyi csoportok</string>
<string name="ftue_auth_use_case_option_one">Barátok és család</string>
<string name="ftue_auth_use_case_subtitle">Segítünk a kapcsolatteremtésben.</string>
<string name="ftue_auth_use_case_subtitle">Segítünk a kapcsolatteremtésben</string>
<string name="ftue_auth_use_case_title">Kikkel fogsz legtöbbet beszélgetni\?</string>
<string name="navigate_to_thread_when_already_in_the_thread">Jelenleg ezt az üzenetszálat olvasod!</string>
<string name="view_in_room">Megjelenítés szobában</string>
@ -2424,17 +2424,17 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
<string name="live_location_sharing_notification_title">${app_name} Folyamatos helymeghatározás</string>
<string name="error_forbidden_digits_only_username">A matrix szerver nem fogad el olyan felhasználói nevet ami csak számokból áll.</string>
<string name="ftue_personalize_skip_this_step">Lépés kihagyása</string>
<string name="ftue_personalize_submit">Mentés és tovább</string>
<string name="ftue_personalize_complete_subtitle">A beállítások elmentve.</string>
<string name="ftue_personalize_complete_title">Minden kész!</string>
<string name="ftue_personalize_submit">Mentés és folytatás</string>
<string name="ftue_personalize_complete_subtitle">A beállításokban bármikor megváltoztathatod a profilod adatait</string>
<string name="ftue_personalize_complete_title">Jónak tűnik!</string>
<string name="ftue_personalize_lets_go">Gyerünk</string>
<string name="ftue_profile_picture_subtitle">Bármikor megváltoztatható.</string>
<string name="ftue_profile_picture_subtitle">Itt az ideje egy profilképet adni a fiókhoz</string>
<string name="ftue_profile_picture_title">Profilkép hozzáadása</string>
<string name="ftue_display_name_entry_footer">Ezt később meg lehet változtatni</string>
<string name="ftue_display_name_entry_title">Megjelenítendő név</string>
<string name="ftue_display_name_subtitle">Ez fog megjelenni amikor üzenetet küldesz.</string>
<string name="ftue_display_name_title">Válassz egy megjelenítési nevet</string>
<string name="ftue_account_created_subtitle">A fiókod elkészült: %s.</string>
<string name="ftue_display_name_title">Válassz egy megjelenítendő nevet</string>
<string name="ftue_account_created_subtitle">A fiókod elkészült. A Matrix címed: %s</string>
<string name="ftue_account_created_congratulations_title">Gratulálunk!</string>
<string name="ftue_account_created_take_me_home">A kezdőlapra</string>
<string name="ftue_account_created_personalize">Profil személyre szabása</string>
@ -2499,35 +2499,35 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
<string name="time_unit_second_short">mperc</string>
<string name="time_unit_minute_short">perc</string>
<string name="time_unit_hour_short">ó</string>
<string name="live_location_labs_promotion_switch_title">Földrajzi hely megosztás engedélyezése</string>
<string name="live_location_labs_promotion_description">Figyelem: ez a labor lehetőség egy átmeneti megvalósítás. Ez azt jelenti, hogy a szobába már elküldött helyadatok az élő hely megosztás leállítása után is hozzáférhetők maradnak a szobában.</string>
<string name="live_location_labs_promotion_title">Élő földrajzi hely megosztása</string>
<string name="live_location_labs_promotion_switch_title">Földrajzi hely megosztásának engedélyezése</string>
<string name="live_location_labs_promotion_description">Figyelem: ez a labs lehetőség egy átmeneti megvalósítás. Ez azt jelenti, hogy nem lehet utólag törölni a megosztott helyadatokat. A technikailag hozzáértő szoba tagok a helyzetmegosztás leállítása után is meg tudják nézni az útvonalat.</string>
<string name="live_location_labs_promotion_title">Folyamatos helyzetmegosztás</string>
<string name="settings_troubleshoot_test_current_gateway">Jelenlegi átjáró: %s</string>
<string name="settings_troubleshoot_test_current_gateway_title">Átjáró (gateway)</string>
<string name="settings_troubleshoot_test_current_endpoint_failed">Nem található végpont.</string>
<string name="settings_troubleshoot_test_current_endpoint_success">Jelenlegi végpont: %s</string>
<string name="settings_troubleshoot_test_current_endpoint_title">Végpont</string>
<string name="settings_troubleshoot_test_current_distributor">Jelenleg használatban: %s.</string>
<string name="settings_troubleshoot_test_current_distributor_title">Metódus</string>
<string name="settings_troubleshoot_test_current_distributor_title">Mód</string>
<plurals name="settings_troubleshoot_test_distributors_many">
<item quantity="one">%d beállítás található.</item>
<item quantity="other">%d beállítás található.</item>
<item quantity="one">%d mód található.</item>
<item quantity="other">%d mód található.</item>
</plurals>
<string name="settings_troubleshoot_test_distributors_fdroid">A háttér szinkronizációs szolgáltatástól eltérő beállítási lehetőség nem érhető el.</string>
<string name="settings_troubleshoot_test_distributors_gplay">A Google Play szolgáltatástól eltérő beállítási lehetőség nem érhető el.</string>
<string name="settings_troubleshoot_test_distributors_title">Elérhető beállítások</string>
<string name="settings_notification_method">Értesítési beállítások</string>
<string name="settings_troubleshoot_test_distributors_fdroid">A háttér szinkronizációs szolgáltatáson kívül nem található más mód.</string>
<string name="settings_troubleshoot_test_distributors_gplay">A Google Play szolgáltatásokon kívül nem található más mód.</string>
<string name="settings_troubleshoot_test_distributors_title">Elérhető módok</string>
<string name="settings_notification_method">Értesítési módok</string>
<string name="unifiedpush_distributor_background_sync">Szinkronizálás a háttérben</string>
<string name="unifiedpush_distributor_fcm_fallback">Google szolgáltatások</string>
<string name="unifiedpush_getdistributors_dialog_title">Válaszd ki, hogyan szeretnél értesítéseket kapni</string>
<string name="poll_undisclosed_not_ended">Az eredmény a szavazás végeztével válik láthatóvá</string>
<string name="labs_enable_msc3061_share_history_desc">Ha olyan titkosított szobába hívsz meg valakit ahol a régi üzenetek megosztása engedélyezett a régi titkosított üzenetek is láthatóak lesznek a meghívott számára.</string>
<string name="poll_undisclosed_not_ended">Az eredmény a szavazás lezárása után válik láthatóvá</string>
<string name="labs_enable_msc3061_share_history_desc">Ha olyan titkosított szobába hívsz meg valakit ahol a régi üzenetek megosztása be van kapcsolva, akkor a meghívott felhasználó el fogja tudni olvasni a meghívása előtt küldött üzeneteket is.</string>
<string name="labs_enable_msc3061_share_history">MSC3061: Szoba kulcsok megosztása a régi üzenetekhez</string>
<string name="settings_security_pin_code_use_biometrics_error">A biometrikus azonosítást nem lehet engedélyezni.</string>
<string name="auth_biometric_key_invalidated_message">A biometrikus azonosítás kikapcsolásra került mivel egy új biometrikus azonosítási metódus került hozzáadásra. Újra engedélyezheted a Beállításokban.</string>
<string name="send_your_first_msg_to_invite">Az első üzeneteddel hívd meg ide őt: %s</string>
<string name="settings_security_pin_code_use_biometrics_error">Nem sikerült bekapcsolni a biometrikus azonosítást.</string>
<string name="auth_biometric_key_invalidated_message">A biometrikus azonosítás kikapcsolásra került mivel egy új biometrikus azonosítási mód került hozzáadásra. Újra engedélyezheted a Beállításokban.</string>
<string name="send_your_first_msg_to_invite">A meghívó elküldéséhez küldj %s felhasználónak egy üzenetet</string>
<string name="direct_room_encryption_enabled_tile_description_future">Az üzenetek ebben a beszélgetésben végpontok közötti titkosítással lesznek védve.</string>
<string name="settings_troubleshoot_test_endpoint_registration_quick_fix">Értesítési metódus visszaállítása</string>
<string name="settings_troubleshoot_test_endpoint_registration_quick_fix">Értesítési mód visszaállítása</string>
<string name="push_gateway_item_profile_tag">Profil címke:</string>
<string name="create_room_action_go">Menj</string>
<string name="settings_troubleshoot_test_endpoint_registration_failed">Végpont token regisztrációja sikertelen a Matrix-kiszolgálón:
@ -2535,4 +2535,44 @@ A Visszaállítási Kulcsot tartsd biztonságos helyen, mint pl. egy jelszókeze
<string name="settings_troubleshoot_test_endpoint_registration_success">Végpont sikeresen regisztrálva lett a matrix szerveren.</string>
<string name="settings_troubleshoot_test_endpoint_registration_title">Végpont regisztráció</string>
<string name="action_next">Következő</string>
<string name="ftue_auth_login_username_entry">Felhasználónév / e-mail / telefonszám</string>
<string name="ftue_auth_captcha_title">Valódi személy vagy\?</string>
<string name="ftue_auth_password_reset_email_confirmation_subtitle">Kövesd az útmutatást, amit ide küldtünk: %s</string>
<string name="ftue_auth_password_reset_confirmation">Jelszó visszaállítás</string>
<string name="ftue_auth_forgot_password">Elfelejtett jelszó</string>
<string name="ftue_auth_email_resend_email">E-mail újraküldése</string>
<string name="ftue_auth_email_verification_footer">Nem kaptad meg az e-mailt\?</string>
<string name="ftue_auth_email_verification_subtitle">Kövesd az útmutatást, amit ide küldtünk: %s</string>
<string name="ftue_auth_email_verification_title">E-mail ellenőrzése</string>
<string name="ftue_auth_phone_confirmation_resend_code">Kód újraküldése</string>
<string name="ftue_auth_phone_confirmation_subtitle">Egy kódot küldtünk ide: %s</string>
<string name="ftue_auth_phone_confirmation_title">Telefonszám megerősítése</string>
<string name="ftue_auth_sign_out_all_devices">Összes eszközöm kijelentkeztetése</string>
<string name="ftue_auth_reset_password">Jelszó visszaállítása</string>
<string name="ftue_auth_new_password_subtitle">Bizonyosodj meg róla, hogy minimum 8 karakter hosszú.</string>
<string name="ftue_auth_phone_confirmation_entry_title">Megerősítő kód</string>
<string name="ftue_auth_phone_entry_title">Telefonszám</string>
<string name="ftue_auth_phone_subtitle">A %s szervernek ellenőriznie kell a fiókod</string>
<string name="ftue_auth_phone_title">Add meg a telefonszámod</string>
<string name="ftue_auth_email_entry_title">E-mail</string>
<string name="ftue_auth_email_subtitle">A %s szervernek ellenőriznie kell a fiókod</string>
<string name="ftue_auth_email_title">Add meg az e-mail címed</string>
<string name="ftue_auth_terms_subtitle">Kérünk, olvasd el a %s szerver felhasználási feltételeit</string>
<string name="ftue_auth_terms_title">Szerver szabályok</string>
<string name="ftue_auth_choose_server_ems_cta">Kapcsolatfelvétel</string>
<string name="ftue_auth_choose_server_ems_subtitle">Az Element Matrix Services (EMS) egy robosztus és megbízható szerver üzemeltetési szolgáltatás a gyors és biztonságos kommunikáció céljaira. Tudj meg többet itt: <a href="${ftue_ems_url}">element.io/ems</a></string>
<string name="ftue_auth_choose_server_ems_title">Szeretnél egy saját szervert\?</string>
<string name="ftue_auth_choose_server_entry_hint">Szerver URL</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Mi a szervered címe\?</string>
<string name="ftue_auth_choose_server_title">Válassz szervert</string>
<string name="ftue_auth_welcome_back_title">Üdv újra!</string>
<string name="ftue_auth_create_account_edit_server_selection">Szerkesztés</string>
<string name="ftue_auth_sign_in_choose_server_header">Ahol a beszélgetéseid tárolva vannak</string>
<string name="ftue_auth_create_account_sso_section_header">vagy</string>
<string name="ftue_auth_create_account_password_entry_footer">Minimum 8 karakterből kell álljon</string>
<string name="ftue_auth_create_account_username_entry_footer">Mások ezen a címen tudnak írni neked: %s</string>
<string name="ftue_auth_create_account_title">Fiók létrehozása</string>
<string name="ftue_auth_create_account_choose_server_header">Itt lesznek tárolva a beszélgetéseid</string>
<string name="ftue_auth_choose_server_subtitle">Mi a szervered címe\? Itt lesz tárolva az összes üzeneted</string>
<string name="auth_reset_password_error_unverified">Az email cím nem lett ellenőrizve, kérlek nézd meg a beérkező email-jeidet</string>
</resources>

View File

@ -1289,7 +1289,7 @@
<item quantity="one">%d sessione attiva</item>
<item quantity="other">%d sessioni attive</item>
</plurals>
<string name="crosssigning_verify_this_session">Verifica questo accesso</string>
<string name="crosssigning_verify_this_session">Verifica questo dispositivo</string>
<string name="verification_open_other_to_verify">Usa una sessione esistente per verificare questa, dandole l\'accesso ai messaggi criptati.</string>
<string name="verification_profile_verify">Verifica</string>
<string name="verification_profile_verified">Verificato</string>
@ -2541,8 +2541,8 @@
<string name="ftue_auth_forgot_password">Password dimenticata</string>
<string name="ftue_auth_email_resend_email">Reinvia email</string>
<string name="ftue_auth_email_verification_footer">Non hai ricevuto un\'email\?</string>
<string name="ftue_auth_email_verification_subtitle">Per confermare l\'email, tocca il pulsante nell\'email che abbiamo appena inviato a %s</string>
<string name="ftue_auth_email_verification_title">Controlla l\'email per verificare.</string>
<string name="ftue_auth_email_verification_subtitle">Segui le istruzioni inviate a %s</string>
<string name="ftue_auth_email_verification_title">Verifica l\'email</string>
<string name="ftue_auth_phone_confirmation_resend_code">Reinvia codice</string>
<string name="ftue_auth_phone_confirmation_subtitle">È stato inviato un codice a %s</string>
<string name="ftue_auth_phone_confirmation_title">Conferma il tuo numero di telefono</string>
@ -2579,4 +2579,19 @@
<string name="font_size_section_manually">Scegli manualmente</string>
<string name="font_size_section_auto">Imposta automaticamente</string>
<string name="font_size_title">Scegli dimensione caratteri</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">Auto-approva i widget di Element Call e consenti accesso a fotocamera / microfono</string>
<string name="labs_enable_element_call_permission_shortcuts">Attiva scorciatoie di autorizzazione di Element Call</string>
<string name="live_location_description">Posizione in tempo reale</string>
<string name="verify_invalid_qr_notice">Questo codice QR sembra sbagliato. Prova la verifica con un altro metodo.</string>
<string name="crosssigning_cannot_verify_this_session_desc">Non potrai accedere alla cronologia dei messaggi cifrati. Reimposta il backup dei messaggi sicuri e le chiavi di verifica per ricominciare.</string>
<string name="crosssigning_cannot_verify_this_session">Impossibile verificare questo dispositivo</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Qual è l\'indirizzo del tuo server\?</string>
<string name="ftue_auth_sign_in_choose_server_header">Dove vivono le tue conversazioni</string>
<string name="updating_your_data">Aggiornamento dei tuoi dati…</string>
<plurals name="search_space_multiple_parents">
<item quantity="one">%1$s e %2$d altro</item>
<item quantity="other">%1$s e altri %2$d</item>
</plurals>
<string name="search_space_two_parents">%1$s e %2$s</string>
<string name="auth_reset_password_error_unverified">Email non verificata, controlla la posta in arrivo</string>
</resources>

View File

@ -2000,7 +2000,7 @@
<string name="verification_profile_device_verified_because">Deze sessie wordt vertrouwd voor veilig berichtenverkeer omdat %1$s (%2$s) deze heeft geverifieerd:</string>
<string name="room_member_profile_failed_to_get_devices">Kan geen sessies ophalen</string>
<string name="verification_open_other_to_verify">Gebruik een bestaande sessie om deze te verifiëren en deze toegang te verlenen tot versleutelde berichten.</string>
<string name="crosssigning_verify_this_session">Verifieer deze login</string>
<string name="crosssigning_verify_this_session">Verifieer dit apparaat</string>
<plurals name="settings_active_sessions_count">
<item quantity="one">%d actieve sessie</item>
<item quantity="other">%d actieve sessies</item>
@ -2550,8 +2550,8 @@
<string name="ftue_auth_forgot_password">Wachtwoord vergeten</string>
<string name="ftue_auth_email_resend_email">Email opnieuw verzenden</string>
<string name="ftue_auth_email_verification_footer">Geen e-mail ontvangen\?</string>
<string name="ftue_auth_email_verification_subtitle">Om uw e-mailadres te bevestigen, tikt u op de knop in de e-mail die we zojuist naar %s hebben gestuurd</string>
<string name="ftue_auth_email_verification_title">Controleer uw e-mail om te verifiëren.</string>
<string name="ftue_auth_email_verification_subtitle">Volg de instructies die naar %s zijn gestuurd</string>
<string name="ftue_auth_email_verification_title">Verifieer uw e-mailadres</string>
<string name="ftue_auth_phone_confirmation_resend_code">Code nogmaals versturen</string>
<string name="ftue_auth_phone_confirmation_subtitle">Er is een code verzonden naar %s</string>
<string name="ftue_auth_phone_confirmation_title">Bevestig uw telefoonnummer</string>
@ -2588,4 +2588,19 @@
<string name="font_size_section_manually">Handmatig kiezen</string>
<string name="font_size_section_auto">Automatisch instellen</string>
<string name="font_size_title">Kies lettergrootte</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">Keur automatisch Element Oproep widgets goed en verleen camera-/microfoontoegang</string>
<string name="labs_enable_element_call_permission_shortcuts">Snelkoppelingen voor Element Oproep machtigingen inschakelen</string>
<string name="live_location_description">Live locatie</string>
<string name="verify_invalid_qr_notice">Deze QR-code lijkt misvormd. Probeer te verifiëren met een andere methode.</string>
<string name="crosssigning_cannot_verify_this_session_desc">U hebt geen toegang tot de gecodeerde berichtgeschiedenis. Reset uw Veilige Berichten Back-up en verificatiesleutels om opnieuw te beginnen.</string>
<string name="crosssigning_cannot_verify_this_session">Kan dit apparaat niet verifiëren</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Wat is het adres van uw server\?</string>
<string name="ftue_auth_sign_in_choose_server_header">Waar uw conversaties leven</string>
<string name="updating_your_data">Uw gegevens bijwerken…</string>
<plurals name="search_space_multiple_parents">
<item quantity="one">%1$s en %2$d andere</item>
<item quantity="other">%1$s en %2$d andere</item>
</plurals>
<string name="search_space_two_parents">%1$s en %2$s</string>
<string name="auth_reset_password_error_unverified">E-mailadres niet geverifieerd, controleer je inbox</string>
</resources>

View File

@ -457,7 +457,7 @@
<string name="markdown_has_been_enabled">Markdown został włączony.</string>
<string name="markdown_has_been_disabled">Markdown został wyłączony.</string>
<string name="generic_label_and_value">%1$s: %2$s</string>
<string name="x_plus">%d+</string>
<string name="x_plus">+%d</string>
<string name="settings_call_ringtone_use_app_ringtone">Użyj domyślnego dzwonka ${app_name} dla przychodzących połączeń</string>
<string name="settings_call_category">Połączenia</string>
<string name="room_participants_action_remove">Wyrzuć</string>
@ -1132,7 +1132,7 @@
<item quantity="many">%d aktywnych sesji</item>
<item quantity="other">%d aktywnych sesji</item>
</plurals>
<string name="crosssigning_verify_this_session">Zweryfikuj tą sesję</string>
<string name="crosssigning_verify_this_session">Zweryfikuj te urządzenie</string>
<string name="verification_open_other_to_verify">Otwórz obecną sesję i użyj jej do zweryfikowania obecnej, przyznając jej dostęp do zaszyfrowanych wiadomości.</string>
<string name="verification_profile_verify">Zweryfkuj</string>
<string name="verification_profile_verified">Zweryfikowano</string>
@ -1303,7 +1303,7 @@
<string name="room_created_summary_item">%s stworzył(a) i skonfigurował(a) ten pokój.</string>
<string name="encryption_unknown_algorithm_tile_description">Szyfrowanie wykorzystywane przez ten pokój nie jest obsługiwane</string>
<string name="encryption_not_enabled">Szyfrowanie wyłączone</string>
<string name="direct_room_encryption_enabled_tile_description">Wiadomości w tym pokoju są szyfrowane w trybie punkt-punkt (e2e).</string>
<string name="direct_room_encryption_enabled_tile_description">Wiadomości w tym czacie są szyfrowane end-to-end.</string>
<string name="encryption_enabled_tile_description">Wiadomości w tym pokoju są szyfrowane punkt-punkt (e2e). Możesz dowiedzieć się więcej i zweryfikować użytkowników w ich profilach.</string>
<string name="encryption_enabled">Szyfrowanie włączone</string>
<string name="bootstrap_cancel_text">Jeżeli teraz przerwiesz, możesz utracić zaszyfrowane wiadomości oraz dane jeżeli utracisz dostęp do zalogowanych sesji.
@ -2377,28 +2377,28 @@
<string name="login_splash_create_account">Utwórz konto</string>
<string name="ftue_personalize_skip_this_step">Pomiń ten krok</string>
<string name="ftue_personalize_submit">Zapisz i kontynuuj</string>
<string name="ftue_personalize_complete_subtitle">Twoje ustawienia zostały zapisane.</string>
<string name="ftue_personalize_complete_title">Wszystko ustawiłeś!</string>
<string name="ftue_personalize_complete_subtitle">Zawsze możesz zmienić swój profil w ustawieniach</string>
<string name="ftue_personalize_complete_title">Dobrze wyglądasz!</string>
<string name="ftue_personalize_lets_go">Chodźmy</string>
<string name="ftue_profile_picture_subtitle">Możesz go zmienić w każdym momencie.</string>
<string name="ftue_profile_picture_subtitle">Pora nadać tej nazwie jakąś twarz</string>
<string name="ftue_profile_picture_title">Dodaj obraz profilu</string>
<string name="ftue_display_name_entry_footer">Możesz zmienić ją później</string>
<string name="room_message_autocomplete_notification">Powiadomienie pokoju</string>
<string name="ftue_display_name_entry_title">Wyświetlana nazwa</string>
<string name="ftue_display_name_subtitle">Będzie ona widoczna podczas wysyłania wiadomości.</string>
<string name="ftue_display_name_title">Wybierz wyświetlaną nazwę</string>
<string name="ftue_account_created_subtitle">Twoje konto %s zostało utworzone.</string>
<string name="ftue_account_created_subtitle">Twoje konto %s zostało utworzone</string>
<string name="ftue_account_created_congratulations_title">Gratulacje!</string>
<string name="ftue_account_created_take_me_home">Zabierz mnie do domu</string>
<string name="ftue_account_created_personalize">Spersonalizuj profil</string>
<string name="ftue_auth_use_case_connect_to_server">Połącz się z serwerem</string>
<string name="ftue_auth_use_case_join_existing_server">Chcesz dołączyć do istniejącego serwera\?</string>
<string name="ftue_auth_use_case_skip_partial">pominąć to pytanie</string>
<string name="ftue_auth_use_case_skip">Nie wiesz jeszcze\? Możesz %s</string>
<string name="ftue_auth_use_case_skip_partial">Pomiń to pytanie</string>
<string name="ftue_auth_use_case_skip">Nie wiesz jeszcze\? %s</string>
<string name="ftue_auth_use_case_option_three">Społeczności</string>
<string name="ftue_auth_use_case_option_two">Zespoły</string>
<string name="ftue_auth_use_case_option_one">Przyjaciele i rodzina</string>
<string name="ftue_auth_use_case_subtitle">Pomożemy Ci się połączyć.</string>
<string name="ftue_auth_use_case_subtitle">Pomożemy Ci się połączyć</string>
<string name="ftue_auth_use_case_title">Z kim będziesz najczęściej rozmawiać\?</string>
<string name="ftue_auth_carousel_encrypted_body">Szyfrowane od-końca-do-końca i nie wymaga numeru telefonu. Brak reklam i dataminingu.</string>
<string name="ftue_auth_carousel_control_body">Wybierz, gdzie prowadzone są Twoje rozmowy, dając Ci kontrolę i niezależność. Połączenie przez sieć Matrix.</string>
@ -2636,8 +2636,8 @@
<string name="ftue_auth_forgot_password">Zapomniane hasło</string>
<string name="ftue_auth_email_resend_email">Wyślij wiadomość ponownie</string>
<string name="ftue_auth_email_verification_footer">Email nie dotarł\?</string>
<string name="ftue_auth_email_verification_subtitle">Aby potwierdzić swój email, dotknij przycisk we wiadomości wysłanej na %s</string>
<string name="ftue_auth_email_verification_title">Sprawdź swoją skrzynkę email aby dokończyć weryfikację.</string>
<string name="ftue_auth_email_verification_subtitle">Wykonaj instrukcje podane w wiadomości wysłanej na %s</string>
<string name="ftue_auth_email_verification_title">Potwierdź swój email</string>
<string name="ftue_auth_phone_confirmation_resend_code">Wyślij kod ponownie</string>
<string name="ftue_auth_phone_confirmation_subtitle">Kod został wysłany do %s</string>
<string name="ftue_auth_phone_confirmation_title">Potwierdź swój numer telefonu</string>
@ -2672,4 +2672,25 @@
<string name="font_size_section_manually">Ustaw ręcznie</string>
<string name="font_size_section_auto">Ustaw automatycznie</string>
<string name="font_size_title">Wybierz rozmiar czcionki</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">Automatycznie akceptuj widżety Element Call i przyznaj dostęp do kamery i mikrofonu</string>
<string name="labs_enable_element_call_permission_shortcuts">Włącz skróty uprawnień dla Element Call</string>
<string name="live_location_labs_promotion_description">Uwaga: to eksperymentalna funkcja wykorzystująca tymczasową implementację. Oznacza to, że nie będzie możliwości usunięcia historii lokalizacji, a zaawansowani użytkownicy będą mogli ją zobaczyć nawet gdy przestaniesz dzielić się lokalizacją na żywo z tym pokojem.</string>
<string name="live_location_description">Lokalizacja na żywo</string>
<string name="labs_enable_msc3061_share_history_desc">Zapraszając kogoś do zaszyfrowanego pokoju który współdzieli historię, zaszyfrowana historia będzie dla tej osoby widoczna.</string>
<string name="labs_enable_msc3061_share_history">MSC3061: Współdzielenie kluczy pokoju dla wcześniejszych wiadomości</string>
<string name="verify_invalid_qr_notice">Ten kod QR wygląda na niepoprawny. Spróbuj zweryfikować przy użyciu innej metody.</string>
<string name="crosssigning_cannot_verify_this_session_desc">Dostęp do wcześniejszych zaszyfrowanych wiadomości nie będzie możliwy. Zresetuj bezpieczną kopię zapasową wiadomości oraz klucze weryfikacyjne by zacząć od nowa.</string>
<string name="crosssigning_cannot_verify_this_session">Nie udało się zweryfikować tego urządzenia</string>
<string name="ftue_auth_terms_subtitle">Zapoznaj się z warunkami i zasadami serwera %s</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Jaki jest adres twojego serwera\?</string>
<string name="ftue_auth_sign_in_choose_server_header">Miejsce na twoje konwersacje</string>
<string name="updating_your_data">Aktualizowanie twoich danych…</string>
<plurals name="search_space_multiple_parents">
<item quantity="one">%1$s i %2$d inny</item>
<item quantity="few">%1$s i %2$d inne</item>
<item quantity="many">%1$s i %2$d innych</item>
<item quantity="other">%1$s i %2$d innych</item>
</plurals>
<string name="search_space_two_parents">%1$s i %2$s</string>
<string name="auth_reset_password_error_unverified">Email nie został zweryfikowany, sprawdź swoją skrzynkę</string>
</resources>

View File

@ -1390,7 +1390,7 @@
<item quantity="one">%d sessão ativa</item>
<item quantity="other">%d sessões ativas</item>
</plurals>
<string name="crosssigning_verify_this_session">Verificar este login</string>
<string name="crosssigning_verify_this_session">Verificar este dispositivo</string>
<string name="verification_open_other_to_verify">Use uma sessão existente para verificar esta aqui, concedendo-lhe acesso a mensagens encriptadas.</string>
<string name="verification_profile_verify">Verificar</string>
<string name="verification_profile_verified">Verificada(o)</string>
@ -2549,8 +2549,8 @@
<string name="ftue_auth_forgot_password">Esqueceu senha</string>
<string name="ftue_auth_email_resend_email">Reenviar email</string>
<string name="ftue_auth_email_verification_footer">Não recebeu um email\?</string>
<string name="ftue_auth_email_verification_subtitle">Para confirmar seu email, toque no botão no email que nós acabamos de enviar para %s</string>
<string name="ftue_auth_email_verification_title">Checar seu email para verificar.</string>
<string name="ftue_auth_email_verification_subtitle">Siga as instruções enviadas para %s</string>
<string name="ftue_auth_email_verification_title">Verifique seu email</string>
<string name="ftue_auth_phone_confirmation_resend_code">Reenviar código</string>
<string name="ftue_auth_phone_confirmation_subtitle">Um código foi enviado para %s</string>
<string name="ftue_auth_phone_confirmation_title">Confirmar seu número de telefone</string>
@ -2588,4 +2588,19 @@
<string name="font_size_section_manually">Escolher manualmente</string>
<string name="font_size_section_auto">Definir automaticamente</string>
<string name="font_size_title">Encolher tamanho de fonte</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">Auto-aprovar widgets de Element Call e conceder acesso de câmera / mic</string>
<string name="labs_enable_element_call_permission_shortcuts">Habilitar atalhos de permissão de Element Call</string>
<string name="live_location_description">Localização ao vivo</string>
<string name="verify_invalid_qr_notice">Este QR code parece malformado. Por favor tente verificar com um outro método.</string>
<string name="crosssigning_cannot_verify_this_session_desc">Você não vai ser capaz de acessar histórico de mensagem encriptada. Resette seu Backup de Mensagem Seguro e chaves de verificação para começar do zero.</string>
<string name="crosssigning_cannot_verify_this_session">Incapaz de verificar este dispositivo</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Qual é o endereço de seu servidor\?</string>
<string name="ftue_auth_sign_in_choose_server_header">Onde suas conversas vivem</string>
<string name="updating_your_data">Atualizando seus dados…</string>
<plurals name="search_space_multiple_parents">
<item quantity="one">%1$s e %2$d outro</item>
<item quantity="other">%1$s e %2$d outros</item>
</plurals>
<string name="search_space_two_parents">%1$s e %2$s</string>
<string name="auth_reset_password_error_unverified">Email não verificado, cheque sua inbox</string>
</resources>

View File

@ -194,7 +194,7 @@
<string name="room_displayname_3_members">%1$s, %2$s и %3$s</string>
<string name="notice_room_server_acl_allow_is_empty">🎉 Всем серверам запрещено участвовать! Эта комната больше не может быть использована.</string>
<string name="notice_room_server_acl_updated_no_change">Без изменений.</string>
<string name="room_displayname_empty_room_was">Пустая комната (была %s)</string>
<string name="room_displayname_empty_room_was">Пустая комната (был(а) %s)</string>
<string name="notice_room_server_acl_set_banned">• Соответствующие серверы %s заблокированы.</string>
<string name="notice_room_server_acl_updated_ip_literals_not_allowed">• Серверы, соответствующие буквальным IP-адресам, теперь запрещены.</string>
<string name="notice_room_server_acl_updated_ip_literals_allowed">• Серверы, соответствующие буквальным IP-адресам, теперь разрешены.</string>
@ -302,7 +302,7 @@
<string name="option_take_photo_video">Камера</string>
<string name="auth_login">Вход</string>
<string name="auth_submit">Подать</string>
<string name="auth_invalid_login_param">Неправильный логин и/или пароль</string>
<string name="auth_invalid_login_param">Неправильное имя пользователя и/или пароль</string>
<string name="auth_invalid_email">Это не похоже на действительный адрес электронной почты</string>
<string name="auth_email_already_defined">Этот адрес электронной почты уже используется.</string>
<string name="auth_forgot_password">Забыли пароль?</string>
@ -962,7 +962,7 @@
<string name="room_filtering_filter_hint">Отфильтровать беседы…</string>
<string name="room_filtering_footer_title">Не можете найти то, что ищете\?</string>
<string name="room_filtering_footer_create_new_room">Создать новую комнату</string>
<string name="room_filtering_footer_create_new_direct_message">Отправить новое сообщение в диалог</string>
<string name="room_filtering_footer_create_new_direct_message">Отправить новое личное сообщение</string>
<string name="room_filtering_footer_open_room_directory">Просмотр каталога комнат</string>
<string name="room_directory_search_hint">Имя или ID (#example:matrix.org)</string>
<string name="labs_swipe_to_reply_in_timeline">Включить жест смахивания для ответа в ленте сообщений</string>
@ -1455,7 +1455,7 @@
<item quantity="few">%d сессии активны</item>
<item quantity="many">%d сессий активно</item>
</plurals>
<string name="crosssigning_verify_this_session">Подтвердите эту сессию</string>
<string name="crosssigning_verify_this_session">Подтвердите это устройство</string>
<string name="verification_open_other_to_verify">Используйте существующую сессию для подтверждения этой, предоставив ей доступ к зашифрованным сообщениям.</string>
<string name="settings_dev_tools">Инструменты для разработчиков</string>
<string name="settings_account_data">Данные учётной записи</string>
@ -1749,7 +1749,7 @@
<string name="bad_passphrase_key_reset_all_action">Забыли или потеряли все варианты восстановления\? Сбросить все</string>
<string name="direct_room_created_summary_item_by_you">Вы вошли.</string>
<string name="direct_room_created_summary_item">%s вошёл(ла).</string>
<string name="direct_room_encryption_enabled_tile_description">Сообщения в этой комнате зашифрованы сквозным шифрованием.</string>
<string name="direct_room_encryption_enabled_tile_description">Сообщения в этой переписке защищены сквозным шифрованием.</string>
<string name="direct_room_profile_section_more_leave">Покинуть</string>
<string name="direct_room_profile_section_more_settings">Настройки</string>
<string name="direct_room_profile_encrypted_subtitle">Сообщения здесь защищены сквозным шифрованием.
@ -1840,7 +1840,7 @@
<string name="send_bug_report_include_key_share_history">Отправить историю запросов на обмен ключами</string>
<string name="start_chatting">Начать беседу</string>
<string name="room_created_summary_no_topic_creation_text">%s чтобы люди знали, о чём эта комната.</string>
<string name="this_is_the_beginning_of_dm">Это начало вашей истории диалога с %s.</string>
<string name="this_is_the_beginning_of_dm">Это начало вашей переписки с %s.</string>
<string name="settings_export_trail">Экспорт аудита</string>
<string name="room_member_open_or_create_dm">Личное сообщение</string>
<string name="settings_discovery_consent_title">Отправить электронную почту и номера телефонов</string>
@ -2035,7 +2035,7 @@
<string name="looking_for_someone_not_in_space">Ищете кого-то не в %s\?</string>
<string name="user_invites_you">%s приглашает вас</string>
<string name="you_are_invited">Вы приглашены</string>
<string name="spaces_beta_welcome_to_spaces_desc">Пространства - это новый способ группировки комнат и людей.</string>
<string name="spaces_beta_welcome_to_spaces_desc">Пространства — это новый способ организации комнат и людей.</string>
<string name="space_add_existing_rooms">Добавить существующие комнаты и пространство</string>
<string name="space_leave_prompt_msg_as_admin">Вы единственный администратор этого пространства. Если вы его покинете, то никто не сможет управлять им.</string>
<string name="space_leave_prompt_msg_private">Вы сможете присоединиться только после повторного приглашения.</string>
@ -2387,7 +2387,7 @@
<string name="room_profile_section_restore_security">Восстановить шифрование</string>
<string name="contact_admin_to_restore_encryption">Обратитесь к администратору, чтобы восстановить шифрование до рабочего состояния.</string>
<string name="encryption_has_been_misconfigured">Шифрование настроено неправильно.</string>
<string name="sent_location">Поделились своим местоположением</string>
<string name="sent_location">Поделился(лась) местоположением</string>
<string name="login_splash_already_have_account">У меня уже есть учётная запись</string>
<string name="login_splash_create_account">Создать учётную запись</string>
<string name="ftue_auth_carousel_workplace_title">Обмен сообщениями для вашей команды.</string>
@ -2443,12 +2443,12 @@
<string name="labs_enable_thread_messages">Включить обсуждения сообщений</string>
<string name="ftue_auth_use_case_connect_to_server">Подключиться к серверу</string>
<string name="ftue_auth_use_case_join_existing_server">Хотите присоединиться к существующему серверу\?</string>
<string name="ftue_auth_use_case_skip_partial">пропустить вопрос</string>
<string name="ftue_auth_use_case_skip">Пока не уверенны\? Вы можете %s</string>
<string name="ftue_auth_use_case_skip_partial">Пропустить вопрос</string>
<string name="ftue_auth_use_case_skip">Пока не уверены\? %s</string>
<string name="ftue_auth_use_case_option_three">Сообщества</string>
<string name="ftue_auth_use_case_option_two">Команды</string>
<string name="ftue_auth_use_case_option_one">Друзья и семья</string>
<string name="ftue_auth_use_case_subtitle">Мы поможем вам подключится.</string>
<string name="ftue_auth_use_case_subtitle">Мы поможем вам подключиться</string>
<string name="ftue_auth_use_case_title">С кем вы будете общаться больше всего\?</string>
<string name="navigate_to_thread_when_already_in_the_thread">Вы уже просматриваете это обсуждение!</string>
<string name="view_in_room">Просмотр в Комнате</string>
@ -2489,7 +2489,7 @@
<string name="ftue_display_name_entry_title">Отображаемое имя</string>
<string name="ftue_display_name_subtitle">Показывается, когда вы отправляете сообщения.</string>
<string name="ftue_display_name_title">Выберите отображаемое имя</string>
<string name="ftue_account_created_subtitle">Ваш аккаунт «%s» создан.</string>
<string name="ftue_account_created_subtitle">Ваша учётная запись %s создана</string>
<string name="ftue_account_created_congratulations_title">Поздравляем!</string>
<string name="ftue_account_created_take_me_home">Домой</string>
<string name="ftue_account_created_personalize">Персонализировать</string>
@ -2523,7 +2523,7 @@
<string name="location_share_live_started">Загрузка трансляции местоположения…</string>
<string name="location_share_live_select_duration_title">Поделиться трансляцией местоположения на</string>
<string name="a11y_location_share_option_user_live_icon">Трансляцией местоположения</string>
<string name="sent_live_location">Поделились трансляцией местоположения</string>
<string name="sent_live_location">Поделился(лась) трансляцией местоположения</string>
<string name="location_share_option_user_live">Трансляцией местоположения</string>
<string name="space_explore_filter_no_result_description">Некоторые результаты могут быть скрыты, поскольку они являются приватными и для их просмотра необходимо приглашение.</string>
<string name="time_unit_minute_short">мин</string>
@ -2550,7 +2550,7 @@
<string name="ftue_personalize_skip_this_step">Пропустить этот шаг</string>
<string name="ftue_personalize_submit">Сохранить и продолжить</string>
<string name="ftue_personalize_complete_subtitle">Ваши предпочтения были сохранены.</string>
<string name="ftue_personalize_complete_title">Всё готово!</string>
<string name="ftue_personalize_complete_title">Выглядит хорошо!</string>
<string name="ftue_auth_carousel_workplace_body">${app_name} также отлично подходит для работы. Ему доверяют самые надёжные организации в мире.</string>
<string name="keys_backup_settings_signature_from_this_user">Резервная копия имеет действительную подпись для данного пользователя.</string>
<string name="settings_autoplay_animated_images_summary">Воспроизводить анимированные изображения, как только они попадают в поле зрения</string>
@ -2609,4 +2609,58 @@
<string name="settings_troubleshoot_test_current_endpoint_success">Текущая конечная точка: %s</string>
<string name="settings_troubleshoot_test_current_endpoint_title">Конечная точка</string>
<string name="space_leave_radio_buttons_title">Вещи в этом пространстве</string>
</resources>
<string name="live_location_share_location_item_share">Поделиться местоположением</string>
<string name="labs_enable_msc3061_share_history">MSC3061: Предоставление ключей от прошлых сообщений</string>
<string name="create_room_action_go">Вперёд</string>
<string name="ftue_auth_new_password_subtitle">Убедитесь, что он состоит из 8 или более символов.</string>
<string name="font_size_section_manually">Выбрать вручную</string>
<string name="font_size_title">Выбор размера шрифта</string>
<plurals name="room_removed_messages">
<item quantity="one">Удалено %d сообщение</item>
<item quantity="few">Удалено %d сообщения</item>
<item quantity="many">Удалено %d сообщений</item>
<item quantity="other">Удалено %d сообщений</item>
</plurals>
<string name="ftue_auth_sign_out_all_devices">Выйти из учётной записи на всех устройствах</string>
<string name="live_location_description">Трансляция местоположения</string>
<string name="direct_room_encryption_enabled_tile_description_future">Сообщения в этой переписке будут защищены сквозным шифрованием.</string>
<string name="updating_your_data">Обновление данных…</string>
<string name="ftue_auth_email_resend_email">Повторно отправить письмо</string>
<string name="ftue_auth_email_verification_subtitle">Следуйте инструкциям, отправленным на %s</string>
<string name="ftue_auth_email_verification_title">Подтвердите свою электронную почту</string>
<string name="ftue_auth_reset_password_breaker_title">Проверьте электронную почту.</string>
<string name="ftue_auth_terms_subtitle">Пожалуйста, ознакомьтесь с условиями и правилами %s</string>
<string name="ftue_auth_choose_server_ems_title">Хотите разместить собственный сервер\?</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Какой адрес у вашего сервера\?</string>
<string name="ftue_auth_choose_server_subtitle">Какой адрес у вашего сервера\? Это что-то вроде дома для всех ваших данных</string>
<string name="ftue_auth_choose_server_title">Выберите свой сервер</string>
<string name="font_size_section_auto">Установить автоматически</string>
<string name="auth_reset_password_error_unverified">Почта не подтверждена, проверьте почтовый ящик</string>
<string name="ftue_auth_create_account_edit_server_selection">Изменить</string>
<string name="ftue_auth_sign_in_choose_server_header">Где хранятся ваши переписки</string>
<string name="ftue_auth_create_account_choose_server_header">Где будут храниться ваши переписки</string>
<string name="ftue_auth_create_account_password_entry_footer">Должно быть 8 или более символов</string>
<string name="crosssigning_cannot_verify_this_session">Не удалось подтвердить это устройство</string>
<string name="permalink_unsupported_groups">Невозможно открыть эту ссылку: сообщества были заменены пространствами</string>
<string name="ftue_auth_login_username_entry">Имя пользователя / Почта / Телефон</string>
<string name="ftue_auth_password_reset_email_confirmation_subtitle">Следуйте инструкциям, отправленным на %s</string>
<string name="ftue_auth_forgot_password">Забыли пароль</string>
<string name="ftue_auth_email_verification_footer">Не получили письмо\?</string>
<string name="ftue_auth_captcha_title">Вы человек\?</string>
<string name="ftue_auth_phone_confirmation_resend_code">Повторно отправить код</string>
<string name="ftue_auth_phone_confirmation_subtitle">Код отправлен на %s</string>
<string name="ftue_auth_phone_confirmation_title">Подтвердите номер телефона</string>
<string name="ftue_auth_reset_password">Сбросить пароль</string>
<string name="ftue_auth_new_password_entry_title">Новый пароль</string>
<string name="ftue_auth_phone_confirmation_entry_title">Код подтверждения</string>
<string name="ftue_auth_phone_entry_title">Номер телефона</string>
<string name="ftue_auth_phone_title">Введите номер телефона</string>
<string name="ftue_auth_email_entry_title">Электронная почта</string>
<string name="ftue_auth_email_title">Введите адрес электронной почты</string>
<string name="ftue_auth_terms_title">Правила сервера</string>
<string name="ftue_auth_choose_server_entry_hint">URL-адрес сервера</string>
<string name="ftue_auth_welcome_back_title">С возвращением!</string>
<string name="ftue_auth_create_account_sso_section_header">Или</string>
<string name="ftue_auth_create_account_title">Создать учётную запись</string>
<string name="search_space_two_parents">%1$s и %2$s</string>
</resources>

View File

@ -1239,7 +1239,7 @@
<string name="encryption_not_enabled">Šifrovanie nie je zapnuté</string>
<string name="keep_it_safe">Udržujte ho v bezpečí</string>
<string name="verify_new_session_was_not_me">Toto som nebol ja</string>
<string name="crosssigning_verify_this_session">Overte toto prihlásenie</string>
<string name="crosssigning_verify_this_session">Overiť toto zariadenie</string>
<plurals name="settings_active_sessions_count">
<item quantity="one">%d aktívna relácia</item>
<item quantity="few">%d aktívne relácie</item>
@ -2600,8 +2600,8 @@
<string name="ftue_auth_forgot_password">Zabudnuté heslo</string>
<string name="ftue_auth_email_resend_email">Opätovne odoslať e-mail</string>
<string name="ftue_auth_email_verification_footer">Nedostali ste e-mail\?</string>
<string name="ftue_auth_email_verification_subtitle">Ak chcete potvrdiť svoj e-mail, ťuknite na tlačidlo v e-maile, ktorý sme práve poslali na adresu %s</string>
<string name="ftue_auth_email_verification_title">Pre overenie skontrolujte svoj e-mail.</string>
<string name="ftue_auth_email_verification_subtitle">Postupujte podľa pokynov zaslaných na adresu %s</string>
<string name="ftue_auth_email_verification_title">Overte svoj e-mail</string>
<string name="ftue_auth_phone_confirmation_resend_code">Znovu odoslať kód</string>
<string name="ftue_auth_phone_confirmation_subtitle">Kód bol odoslaný na %s</string>
<string name="ftue_auth_phone_confirmation_title">Potvrďte svoje telefónne číslo</string>
@ -2637,4 +2637,20 @@
<string name="font_size_section_manually">Vybrať manuálne</string>
<string name="font_size_section_auto">Nastaviť automaticky</string>
<string name="font_size_title">Vyberte veľkosť písma</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">Automaticky schvaľovať miniaplikácie Element Call a udeliť prístup ku kamere/mikrofónu</string>
<string name="labs_enable_element_call_permission_shortcuts">Zapnúť skratky na povolenie Element hovorov</string>
<string name="live_location_description">Poloha v reálnom čase</string>
<string name="verify_invalid_qr_notice">Tento QR kód vyzerá chybne. Skúste vykonať overenie inou metódou.</string>
<string name="crosssigning_cannot_verify_this_session_desc">K zašifrovanej histórii správ nebudete mať prístup. Obnovte zálohu zabezpečených správ a overovacie kľúče a začnite odznova.</string>
<string name="crosssigning_cannot_verify_this_session">Nie je možné overiť toto zariadenie</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Aká je adresa vášho servera\?</string>
<string name="ftue_auth_sign_in_choose_server_header">Kde vaše rozhovory žijú</string>
<string name="updating_your_data">Aktualizácia vašich údajov…</string>
<plurals name="search_space_multiple_parents">
<item quantity="one">%1$s a %2$d ďalší</item>
<item quantity="few">%1$s a %2$d ďalší</item>
<item quantity="other">%1$s a %2$d ďalších</item>
</plurals>
<string name="search_space_two_parents">%1$s a %2$s</string>
<string name="auth_reset_password_error_unverified">E-mail nie je overený, skontrolujte si schránku</string>
</resources>

View File

@ -1207,7 +1207,7 @@
<string name="verification_open_other_to_verify">Використайте чинний сеанс, щоб звірити цей сеанс, таким чином надавши йому доступ до зашифрованих повідомлень.</string>
<string name="confirm_your_identity_quad_s">Підтвердьте вашу тотожність, звіривши цей вхід та надавши йому доступ до зашифрованих повідомлень.</string>
<string name="verify_this_session">Звірте новий вхід, що доступається до вашого облікового запису: %1$s</string>
<string name="crosssigning_verify_this_session">Звірте цей вхід</string>
<string name="crosssigning_verify_this_session">Звірте цей пристрій</string>
<string name="verification_request_waiting">Очікування…</string>
<string name="new_session">Новий вхід. Це були ви\?</string>
<string name="refresh">Оновити</string>
@ -1227,7 +1227,7 @@
<string name="notice_room_third_party_registered_invite_with_reason_by_you">Ви прийняли запрошення для %1$s. Причина: %2$s</string>
<string name="notice_room_third_party_registered_invite_with_reason">%1$s приймає запрошення для %2$s. Причина: %3$s</string>
<string name="notice_room_ban_with_reason_by_you">Ви заблокували %1$s. Причина: %2$s</string>
<string name="notice_room_ban_with_reason">%1$s заблоковано %2$s. Причина: %3$s</string>
<string name="notice_room_ban_with_reason">%1$s блокує %2$s. Причина: %3$s</string>
<string name="notice_room_unban_with_reason_by_you">Ви розблокували %1$s. Причина: %2$s</string>
<string name="notice_room_unban_with_reason">%1$s розблоковує %2$s. Причина: %3$s</string>
<string name="notice_room_remove_with_reason_by_you">Ви вилучили %1$s. Причина: %2$s</string>
@ -1436,11 +1436,11 @@
</plurals>
<string name="keys_backup_restore_success_title">Резервну копію відновлено %s!</string>
<string name="keys_backup_recovery_code_error_decrypt">Не вдалося розшифрувати резервну копію за допомогою цього ключа відновлення: переконайтеся, що ви ввели правильний ключ відновлення.</string>
<string name="notice_room_server_acl_updated_ip_literals_not_allowed">• Сервери з відповідними літералам IP тепер заблоковано.</string>
<string name="notice_room_server_acl_updated_ip_literals_not_allowed">• Сервери з відповідними літералам IP тепер заблоковані.</string>
<string name="notice_room_server_acl_updated_was_banned">• Відповідні сервери %s було вилучено зі списку блокування.</string>
<string name="notice_room_server_acl_updated_banned">• Відповідні сервери %s тепер заблоковано.</string>
<string name="notice_room_server_acl_set_ip_literals_not_allowed">• Сервери, що з відповідними літералам IP заблоковано.</string>
<string name="notice_room_server_acl_set_banned">• Відповідні сервери %s заблоковано.</string>
<string name="notice_room_server_acl_updated_banned">• Відповідні сервери %s відтепер заблоковані.</string>
<string name="notice_room_server_acl_set_ip_literals_not_allowed">• Сервери з відповідними літералам IP заблоковані.</string>
<string name="notice_room_server_acl_set_banned">• Відповідні сервери %s заблоковані.</string>
<string name="error_opening_banned_room">Неможливо відкрити кімнату, у якій вас заблоковано.</string>
<string name="room_filtering_footer_open_room_directory">Переглянути каталог кімнат</string>
<string name="create_room_in_progress">Створення кімнати…</string>
@ -2648,8 +2648,8 @@
<string name="ftue_auth_forgot_password">Забули пароль</string>
<string name="ftue_auth_email_verification_footer">Не отримали лист\?</string>
<string name="ftue_auth_email_resend_email">Повторно надіслати електронний лист</string>
<string name="ftue_auth_email_verification_subtitle">Щоб підтвердити свою електронну адресу, торкніться кнопки в електронному листі, який ми щойно надіслали на адресу %s</string>
<string name="ftue_auth_email_verification_title">Перейдіть до своєї електронної пошти для підтвердження.</string>
<string name="ftue_auth_email_verification_subtitle">Виконайте вказівки надіслані на %s</string>
<string name="ftue_auth_email_verification_title">Підтвердьте свою електронну адресу</string>
<string name="ftue_auth_phone_confirmation_resend_code">Повторно надіслати код</string>
<string name="ftue_auth_phone_confirmation_subtitle">Код було надіслано на %s</string>
<string name="ftue_auth_phone_confirmation_title">Підтвердьте свій номер телефону</string>
@ -2686,4 +2686,21 @@
<string name="font_size_section_manually">Вибрати вручну</string>
<string name="font_size_section_auto">Установити автоматично</string>
<string name="font_size_title">Виберіть розмір шрифту</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">Віджети автосхвалення викликів Element і надання доступу до камери/мікрофона</string>
<string name="labs_enable_element_call_permission_shortcuts">Увімкнути ярлики дозволів на виклик елемента</string>
<string name="live_location_description">Місце перебування наживо</string>
<string name="verify_invalid_qr_notice">Цей QR-код має неправильний вигляд. Спробуйте звірити іншим методом.</string>
<string name="crosssigning_cannot_verify_this_session_desc">Ви не зможете отримати доступ до історії зашифрованих повідомлень. Скиньте захищену резервну копію повідомлень і ключі підтвердження, щоб почати заново.</string>
<string name="crosssigning_cannot_verify_this_session">Не вдалося звірити цей пристрій</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">Яка адреса вашого сервера\?</string>
<string name="ftue_auth_sign_in_choose_server_header">Де відбуватимуться ваші розмови</string>
<string name="updating_your_data">Оновлення ваших даних…</string>
<plurals name="search_space_multiple_parents">
<item quantity="one">%1$s і %2$d інший</item>
<item quantity="few">%1$s і %2$d інші</item>
<item quantity="many">%1$s і %2$d інших</item>
<item quantity="other">%1$s і %2$d інших</item>
</plurals>
<string name="search_space_two_parents">%1$s і %2$s</string>
<string name="auth_reset_password_error_unverified">Електронна пошта не підтверджена, перевірте свою поштову скриньку</string>
</resources>

View File

@ -975,7 +975,7 @@
\nVui lòng kiểm tra thiết lập.</string>
<string name="settings_troubleshoot_test_system_settings_success">Thông báo được bật trong thiết lập hệ thống.</string>
<string name="settings_troubleshoot_test_system_settings_title">Thiết lập hệ thống.</string>
<string name="settings_notification_troubleshoot">Xử lý lỗi thông báo</string>
<string name="settings_notification_troubleshoot">Thông báo khắc phục lỗi</string>
<string name="settings_notification_keyword_contains_invalid_character">Từ khóa không được chứa \'%s\'</string>
<string name="settings_notification_keyword_contains_dot">Từ khóa không được bắt đầu với \'.\'</string>
<string name="settings_notification_new_keyword">Thêm mới từ khóa</string>
@ -2274,4 +2274,7 @@
<string name="settings_presence_user_always_appears_offline">Chế độ ngoại tuyến</string>
<string name="settings_presence">Sự hiện diện</string>
<string name="message_bubbles">Hiển thị bong bóng tin nhắn</string>
<string name="unifiedpush_getdistributors_dialog_title">Chọn cách nhận thông báo</string>
<string name="settings_notification_method">Phương thức thông báo</string>
<string name="settings_troubleshoot_test_endpoint_registration_quick_fix">Đặt lại phương thức thông báo</string>
</resources>

View File

@ -90,7 +90,7 @@
<string name="notice_room_join_by_you">你加入了房间</string>
<string name="notice_room_leave_by_you">你离开了房间</string>
<string name="notice_room_reject_by_you">你拒绝了邀请</string>
<string name="notice_room_remove_by_you">移除了 %1$s</string>
<string name="notice_room_remove_by_you">了 %1$s</string>
<string name="notice_room_unban_by_you">你解封了 %1$s</string>
<string name="notice_room_ban_by_you">你封禁了 %1$s</string>
<string name="notice_room_withdraw_by_you">你撤回了对 %1$s 的邀请</string>
@ -108,7 +108,7 @@
<string name="notice_call_candidates_by_you">你发送了数据以建立通话。</string>
<string name="notice_answered_call_by_you">你接听了通话。</string>
<string name="notice_ended_call_by_you">你结束了通话。</string>
<string name="notice_made_future_room_visibility_by_you">你已让未来的房间记录对%1$s可见</string>
<string name="notice_made_future_room_visibility_by_you">你已让未来的房间历史对%1$s可见</string>
<string name="notice_room_update_by_you">你升级了此房间。</string>
<string name="notice_room_name_removed_by_you">你移除了房间名称</string>
<string name="notice_room_topic_removed_by_you">你移除了房间主题</string>
@ -163,7 +163,7 @@
<string name="notice_direct_room_third_party_invite_by_you">你邀请了 %1$s</string>
<string name="notice_direct_room_third_party_invite">%1$s 邀请了 %2$s</string>
<string name="notice_direct_room_update_by_you">你在此处升级。</string>
<string name="notice_direct_room_update">%s 在此处升级</string>
<string name="notice_direct_room_update">%s 是升级后的房间</string>
<string name="notice_made_future_direct_room_visibility_by_you">你使未来的消息对 %1$s 可见</string>
<string name="notice_made_future_direct_room_visibility">%1$s 使未来的消息对 %2$s 可见</string>
<string name="notice_direct_room_leave_by_you">你离开了房间</string>
@ -193,7 +193,7 @@
<string name="logout">登出</string>
<string name="search">搜索</string>
<string name="option_send_files">发送文件</string>
<string name="call_ended">通话结束</string>
<string name="call_ended">通话结束</string>
<string name="_continue">继续</string>
<string name="action_join">加入</string>
<string name="action_reject">拒绝</string>
@ -420,12 +420,12 @@
<string name="black_theme">黑色主题</string>
<string name="settings_notification_ringtone">通知声音</string>
<string name="settings_12_24_timestamps">使用12小时制显示时间戳</string>
<string name="widget_delete_message_confirmation">你确定要删除这个挂件吗?</string>
<string name="widget_delete_message_confirmation">确定要从此房间删除此挂件吗?</string>
<string name="widget_integration_unable_to_create">无法创建挂件。</string>
<string name="widget_integration_failed_to_send_request">发送请求失败。</string>
<string name="widget_integration_positive_power_level">权力级别必须是正整数。</string>
<string name="widget_integration_must_be_in_room">你不在这个房间。</string>
<string name="widget_integration_no_permission_in_room">你没有在当前房间中执行此操作的权限</string>
<string name="widget_integration_no_permission_in_room">你没权限在当前房间执行此操作</string>
<string name="widget_integration_missing_room_id">请求中缺失 room_id。</string>
<string name="widget_integration_missing_user_id">请求中缺失 user_id。</string>
<string name="widget_integration_room_not_visible">房间 %s 不可见。</string>
@ -470,14 +470,14 @@
<item quantity="other">%d个成员</item>
</plurals>
<plurals name="notification_unread_notified_messages">
<item quantity="other">%d 条未读消息</item>
<item quantity="other">%d条未读的已通知消息</item>
</plurals>
<string name="list_members">成员</string>
<plurals name="notification_unread_notified_messages_in_room_rooms">
<item quantity="other">%d 个房间</item>
</plurals>
<plurals name="active_widgets">
<item quantity="other">已启用 %d 个挂件</item>
<item quantity="other">%d个启用的挂件</item>
</plurals>
<string name="group_details_home">主页</string>
<string name="rooms">房间</string>
@ -504,7 +504,7 @@
<string name="no_sticker_application_dialog_content">你目前没有启用任何贴纸包。
\n
\n要添加一些吗</string>
<string name="widget_integration_missing_parameter">缺少所需的参数。</string>
<string name="widget_integration_missing_parameter">缺少一个必需参数。</string>
<string name="dialog_user_consent_content">要想继续使用主服务器 %1$s 你必须阅读并同意其服务条款。</string>
<string name="dialog_user_consent_submit">现在阅读</string>
<string name="action_download">下载</string>
@ -587,7 +587,7 @@
<string name="settings_troubleshoot_test_token_registration_success">FCM令牌已成功注册至主服务器。</string>
<string name="settings_troubleshoot_test_token_registration_failed">未能将FCM令牌注册到主服务器
\n %1$s</string>
<string name="settings_labs_native_camera_summary">调用系统相机应用而非使用 ${app_name} 内置的相机界面</string>
<string name="settings_labs_native_camera_summary">启动系统相机而非自定义的相机屏幕</string>
<string name="settings_troubleshoot_test_service_boot_title">开机时启动</string>
<string name="settings_troubleshoot_test_service_boot_quickfix">启用开机时启动</string>
<string name="settings_troubleshoot_test_bg_restricted_title">检查后台限制</string>
@ -760,12 +760,12 @@
<string name="settings_play_shutter_sound">播放快门声</string>
<string name="action_mark_room_read">标记为已读</string>
<plurals name="notification_compat_summary_line_for_room">
<item quantity="other">%1$s: %2$d 条消息</item>
<item quantity="other">%1$s%2$d条消息</item>
</plurals>
<plurals name="notification_compat_summary_title">
<item quantity="other">%d 条通知</item>
</plurals>
<string name="notification_unknown_new_event">活动</string>
<string name="notification_unknown_new_event">事件</string>
<string name="notification_unknown_room_name">房间</string>
<string name="notification_new_messages">新消息</string>
<string name="notification_new_invitation">新邀请</string>
@ -812,11 +812,11 @@
<string name="room_preview_no_preview">无法预览此房间</string>
<string name="fab_menu_create_room">房间</string>
<string name="create_room_action_create">创建</string>
<string name="create_room_name_hint">房间名称</string>
<string name="create_room_name_hint">名称</string>
<string name="settings_sdk_version">Matrix SDK 版本</string>
<string name="settings_general_title">通用</string>
<string name="settings_preferences">选项</string>
<string name="settings_security_and_privacy">隐私安全</string>
<string name="settings_preferences">偏好</string>
<string name="settings_security_and_privacy">安全与隐私</string>
<string name="settings_push_rules">推送规则</string>
<string name="settings_push_rules_no_rules">尚未定义任何推送规则</string>
<string name="settings_push_gateway_no_pushers">没有已注册的推送通道</string>
@ -893,7 +893,7 @@
<string name="settings_secure_backup_reset">重置安全备份</string>
<string name="settings_secure_backup_enter_to_setup">在此设备上设置</string>
<string name="settings_secure_backup_section_info">通过在你的服务器上备份加密密钥,防止失去对加密信息和数据的访问。</string>
<string name="reset_secure_backup_title">为你已有的备份生成新的安全密钥或设置新的安全口令</string>
<string name="reset_secure_backup_title">为你已有的备份生成新的安全密钥或设置新的安全短语</string>
<string name="reset_secure_backup_warning">这将替换你的当前密钥或短语。</string>
<string name="settings_discovery_category">发现</string>
<string name="settings_discovery_manage">管理你的发现设置。</string>
@ -905,16 +905,16 @@
<item quantity="other">%d 个封禁用户</item>
</plurals>
<string name="encryption_exported_successfully">成功导出密钥</string>
<string name="notification_ticker_text_dm">%1$s: %2$s</string>
<string name="notification_ticker_text_group">%1$s: %2$s %3$s</string>
<string name="notification_ticker_text_dm">%1$s%2$s</string>
<string name="notification_ticker_text_group">%1$s%2$s %3$s</string>
<string name="active_widget_view_action">查看</string>
<string name="active_widgets_title">活动挂件</string>
<string name="room_widget_activity_title">挂件</string>
<string name="room_widget_permission_title">载入挂件</string>
<string name="room_widget_permission_added_by">此挂件添加者:</string>
<string name="room_widget_permission_webview_shared_info_title">使用它会设置 cookie 并与 %s 分享数据:</string>
<string name="room_widget_permission_shared_info_title">使用它会与 %s 分享数据:</string>
<string name="room_widget_failed_to_load">无法载入挂件。
<string name="room_widget_permission_webview_shared_info_title">使用它可能会设置cookie并与%s分享数据</string>
<string name="room_widget_permission_shared_info_title">使用它可能会与%s分享数据</string>
<string name="room_widget_failed_to_load">载入挂件失败
\n%s</string>
<string name="room_widget_reload">重载挂件</string>
<string name="room_widget_open_in_browser">在浏览器中打开</string>
@ -956,7 +956,7 @@
<string name="create_room_public_description">任何人都可以加入此房间</string>
<string name="keys_backup_unable_to_get_trust_info">获取信任信息时发生错误</string>
<string name="keys_backup_unable_to_get_keys_backup_data">获取密钥备份数据时发生错误</string>
<string name="import_e2e_keys_from_file">从文件 \"%1$s\" 导入端对端密钥。</string>
<string name="import_e2e_keys_from_file">从文件“%1$s”导入端到端密钥。</string>
<string name="settings_other_third_party_notices">其他第三方通知</string>
<string name="navigate_to_room_when_already_in_the_room">你已经在查看此房间!</string>
<string name="settings_troubleshoot_test_token_registration_quick_fix">注册令牌</string>
@ -1319,7 +1319,7 @@
<plurals name="settings_active_sessions_count">
<item quantity="other">%d 个活动会话</item>
</plurals>
<string name="crosssigning_verify_this_session">验证此登录</string>
<string name="crosssigning_verify_this_session">验证此设备</string>
<string name="verification_open_other_to_verify">使用现有会话来验证此会话,并授予其访问加密消息的权限。</string>
<string name="verification_profile_verify">验证</string>
<string name="verification_profile_verified">已验证</string>
@ -1335,7 +1335,7 @@
<string name="reset_cross_signing">重置密钥</string>
<string name="a11y_qr_code_for_verification">二维码</string>
<string name="qr_code_scanned_by_other_notice">快要完成了!%s 显示对勾了吗?</string>
<string name="qr_code_scanned_by_other_yes">使</string>
<string name="qr_code_scanned_by_other_yes"></string>
<string name="qr_code_scanned_by_other_no"></string>
<string name="no_connectivity_to_the_server_indicator">到服务器的连接已丢失</string>
<string name="no_connectivity_to_the_server_indicator_airplane">飞行模式已打开</string>
@ -1350,7 +1350,7 @@
<item quantity="other">发送原始尺寸图片</item>
</plurals>
<string name="delete_event_dialog_title">确认移除</string>
<string name="delete_event_dialog_content">你确实想要移除(删除)此事件吗?注意如果你删除房间名或话题更改,可以撤销更改</string>
<string name="delete_event_dialog_content">你确定要移除(删除)此事件吗?注意,如果删除房间名称或话题的更改,更改会被撤销</string>
<string name="delete_event_dialog_reason_checkbox">附加理由</string>
<string name="delete_event_dialog_reason_hint">编辑理由</string>
<string name="event_redacted_by_user_reason_with_reason">事件被用户删除,理由:%1$s</string>
@ -1379,7 +1379,7 @@
<string name="message_key">消息密钥</string>
<string name="enter_account_password">输入你的 %s 以继续。</string>
<string name="bootstrap_dont_reuse_pwd">不要使用你的账户密码。</string>
<string name="bootstrap_info_text_2">输入只有你知道的安全口令,用于保护服务器上的秘密。</string>
<string name="bootstrap_info_text_2">输入只有你知道的安全短语,用于保护服务器上的秘密。</string>
<string name="bootstrap_loading_text">这可能会花费数秒,请耐心等待。</string>
<string name="bootstrap_loading_title">设置恢复。</string>
<string name="bootstrap_finish_title">完成了!</string>
@ -1517,20 +1517,20 @@
<string name="bottom_sheet_setup_secure_backup_submit">设置</string>
<string name="bottom_sheet_setup_secure_backup_security_key_title">使用安全密钥</string>
<string name="bottom_sheet_setup_secure_backup_security_key_subtitle">生成安全密钥存储在安全的地方如密码管理器或保险箱。</string>
<string name="bottom_sheet_setup_secure_backup_security_phrase_title">使用安全口令</string>
<string name="bottom_sheet_setup_secure_backup_security_phrase_subtitle">输入仅有你知道的安全口令,生成备份用的密钥。</string>
<string name="bottom_sheet_setup_secure_backup_security_phrase_title">使用安全短语</string>
<string name="bottom_sheet_setup_secure_backup_security_phrase_subtitle">输入仅有你知道的秘密短语,生成备份用的密钥。</string>
<string name="bottom_sheet_save_your_recovery_key_title">保存你的安全密钥</string>
<string name="bottom_sheet_save_your_recovery_key_content">将你的安全密钥存储在安全的地方,例如密码管理器或保险箱。</string>
<string name="set_a_security_phrase_title">设置安全口令</string>
<string name="set_a_security_phrase_notice">输入只有你知道的安全口令,用于保护你的服务器上的秘密。</string>
<string name="set_a_security_phrase_hint">安全口令</string>
<string name="set_a_security_phrase_again_notice">再次输入你的安全口令以确认。</string>
<string name="set_a_security_phrase_title">设置安全短语</string>
<string name="set_a_security_phrase_notice">输入只有你知道的安全短语,用于保护你的服务器上的秘密。</string>
<string name="set_a_security_phrase_hint">安全短语</string>
<string name="set_a_security_phrase_again_notice">再次输入你的安全短语以确认。</string>
<string name="room_settings_name_hint">房间名称</string>
<string name="room_settings_topic_hint">主题</string>
<string name="room_settings_save_success">你已成功更改房间设置</string>
<string name="notice_crypto_unable_to_decrypt_final">你无法访问此消息</string>
<string name="notice_crypto_unable_to_decrypt_friendly">正在等待此消息,可能会花费一些时间</string>
<string name="notice_crypto_unable_to_decrypt_friendly_desc">由于端端加密,你可能需要等待某人的消息到达因为加密密钥未正确发送给你。</string>
<string name="notice_crypto_unable_to_decrypt_friendly_desc">由于端端加密,你可能需要等待某人的消息到达因为加密密钥未正确发送给你。</string>
<string name="crypto_error_withheld_blacklisted">你无法访问此消息因为你已屏蔽此发送者</string>
<string name="crypto_error_withheld_unverified">你无法访问此消息,因为你的会话不被发送者信任</string>
<string name="crypto_error_withheld_generic">你无法访问此消息因为发送者有意不发送密钥</string>
@ -1540,7 +1540,7 @@
<string name="disclaimer_negative_button">明白了</string>
<string name="disclaimer_positive_button">了解更多</string>
<string name="save_recovery_key_chooser_hint">将恢复密钥保存到</string>
<string name="loading_contact_book">正在获取你的联系人…</string>
<string name="loading_contact_book">正在获取你的联系人…</string>
<string name="empty_contact_book">你的通讯录是空的</string>
<string name="contacts_book_title">通讯录</string>
<string name="three_pid_revoke_invite_dialog_title">撤销邀请</string>
@ -1548,7 +1548,7 @@
<string name="member_banned_by">被 %1$s 封禁</string>
<string name="failed_to_unban">解封用户失败</string>
<string name="alert_push_are_disabled_title">推送通知已禁用</string>
<string name="alert_push_are_disabled_description">你的设置以启用推送通知</string>
<string name="alert_push_are_disabled_description">查你的设置以启用推送通知</string>
<string name="create_pin_title">选择 PIN 以确保安全</string>
<string name="create_pin_confirm_title">确认 PIN</string>
<string name="create_pin_confirm_failure">验证 PIN 失败,请输入新的。</string>
@ -1583,7 +1583,7 @@
<plurals name="wrong_pin_message_remaining_attempts">
<item quantity="other">错误代码,剩余 %d 次尝试</item>
</plurals>
<string name="wrong_pin_message_last_remaining_attempt">注意!登出前最后一次尝试!</string>
<string name="wrong_pin_message_last_remaining_attempt">警告!登出前最后一次尝试!</string>
<string name="too_many_pin_failures">错误次数过多,你已被登出</string>
<string name="auth_msisdn_already_defined">此电话号码已定义。</string>
<string name="settings_phone_number_empty">你的账户尚未添加电话号码</string>
@ -1613,8 +1613,8 @@
<string name="settings_security_pin_code_grace_period_summary_off">每次打开 ${app_name} 都要求 PIN 码。</string>
<string name="settings_security_pin_code_grace_period_summary_on">在 2 分钟未使用 ${app_name} 后要求 PIN 码。</string>
<string name="settings_security_pin_code_grace_period_title">2 分钟后要求 PIN</string>
<string name="settings_security_pin_code_notifications_summary_off">仅在一个简单通知中显示未读消息内容数量。</string>
<string name="settings_security_pin_code_notifications_summary_on">显示细节如房间名称和消息内容。</string>
<string name="settings_security_pin_code_notifications_summary_off">仅在一个简单的通知中显示未读消息的数量。</string>
<string name="settings_security_pin_code_notifications_summary_on">显示详情,如房间名称和消息内容。</string>
<string name="settings_security_pin_code_notifications_title">在通知中显示内容</string>
<string name="settings_security_pin_code_use_biometrics_summary_off">PIN 码是解锁 ${app_name} 的唯一方式。</string>
<string name="settings_security_pin_code_use_biometrics_summary_on">启用设备特定的生物特征识别,如指纹和面部识别。</string>
@ -1775,7 +1775,7 @@
<string name="notice_room_server_acl_updated_banned">• 匹配 %s 的服务器现已被屏蔽。</string>
<string name="notice_room_server_acl_set_ip_literals_not_allowed">• 已封禁匹配 IP 地址的服务器。</string>
<string name="notice_room_server_acl_set_ip_literals_allowed">• 已允许匹配 IP 地址的服务器。</string>
<string name="notice_room_server_acl_set_banned">• 匹配 %s 的服务器被屏蔽。</string>
<string name="notice_room_server_acl_set_banned">• 匹配 %s 的服务器被屏蔽。</string>
<string name="notice_room_server_acl_set_allowed">• 已允许匹配 %s 的服务器。</string>
<string name="a11y_checked">已勾选</string>
<string name="a11y_selected">已选中</string>
@ -1901,7 +1901,7 @@
<string name="invite_to_space_with_name">邀请至 %s</string>
<string name="invite_by_link">分享链接</string>
<string name="invite_by_email">通过电子邮件进行邀请</string>
<string name="invite_people_to_your_space_desc">此刻仅有你自己。%s 与他人一道会更好。</string>
<string name="invite_people_to_your_space_desc">此刻只有你。%s与他人一道会更好。</string>
<string name="invite_to_space">邀请至 %s</string>
<string name="invite_people_menu">邀请人们</string>
<string name="invite_people_to_your_space">邀请人们加入你的空间</string>
@ -1925,7 +1925,7 @@
<string name="create_spaces_me_and_teammates">我和伙伴</string>
<string name="create_spaces_organise_rooms">用于整理你房间的私有空间</string>
<string name="create_spaces_just_me">仅我</string>
<string name="create_spaces_make_sure_access">确保对的人可以访问 %s。</string>
<string name="create_spaces_make_sure_access">确保正确的人可以访问%s。</string>
<string name="create_spaces_who_are_you_working_with">你与谁一同工作?</string>
<string name="create_spaces_join_info_help">要加入现有空间,你需要获得邀请。</string>
<string name="create_spaces_you_can_change_later">你可以稍后更改</string>
@ -1974,7 +1974,7 @@
<string name="send_feedback_space_info">你正在使用空间的测试版。你的反馈将有助于改善下一版本。我们将会记录你的平台和用户名以帮助我们尽我们所能多发挥你的反馈的作用。</string>
<string name="feedback">反馈</string>
<string name="send_feedback_space_title">空间反馈</string>
<string name="jitsi_leave_conf_to_join_another_one_content">离开当前的回忆并切换至其他会议</string>
<string name="jitsi_leave_conf_to_join_another_one_content">离开当前会议并切换至另一个</string>
<string name="error_jitsi_join_conf">抱歉,在尝试加入会议时发生了错误</string>
<string name="room_settings_room_access_restricted_description">所有在此空间中的人都可以找到并加入它。仅有此房间的管理员可以将其添加到空间中。</string>
<string name="room_settings_room_access_restricted_title">仅空间成员</string>
@ -2127,7 +2127,7 @@
<string name="call_tile_video_declined">视频通话被拒绝</string>
<string name="call_tile_voice_declined">语音通话被拒绝</string>
<string name="call_tile_video_call_has_ended">视频通话已结束 • %1$s</string>
<string name="call_tile_voice_call_has_ended">语音通话结束 • %1$s</string>
<string name="call_tile_voice_call_has_ended">语音通话结束 • %1$s</string>
<string name="call_tile_video_incoming">视频来电</string>
<string name="call_tile_voice_incoming">语音来电</string>
<string name="call_tile_you_declined_this_call">你拒绝了此通话</string>
@ -2143,7 +2143,7 @@
<string name="settings_notification_new_keyword">添加新关键词</string>
<string name="settings_notification_your_keywords">你的关键词</string>
<string name="room_settings_none"></string>
<string name="room_settings_mention_and_keyword_only">仅提及 &amp; 关键词</string>
<string name="room_settings_mention_and_keyword_only">仅提及关键词</string>
<string name="call_remove_jitsi_widget_progress">正结束通话…</string>
<string name="call_ended_invite_timeout_title">无应答</string>
<string name="call_ended_user_busy_description">你呼叫的用户正忙。</string>
@ -2224,7 +2224,7 @@
<string name="attachment_type_poll">投票</string>
<string name="identity_server_consent_dialog_title_2">向 %s 发送电子邮件和电话号码</string>
<string name="settings_discovery_consent_notice_off_2">您的联系人是私密的。 要从您的联系人中发现用户,我们需要您的许可才能将联系信息发送到您的身份服务器。</string>
<string name="shortcut_disabled_reason_sign_out">退出此会话!</string>
<string name="shortcut_disabled_reason_sign_out">出此会话!</string>
<string name="shortcut_disabled_reason_room_left">已离开此房间!</string>
<string name="identity_server_consent_dialog_content_question">你同意发送此信息吗?</string>
<string name="identity_server_consent_dialog_content_3">要发现现有的联系人,您需要将联系人信息(电子邮件和电话号码)发送到您的身份服务器。出乎隐私考量,我们会在发送前对您的数据进行散列处理。</string>
@ -2232,7 +2232,7 @@
<string name="delete_poll_dialog_content">您确定要删除此投票吗?一旦移除,就无法恢复。</string>
<string name="delete_poll_dialog_title">删除投票</string>
<string name="poll_end_room_list_preview">投票已结束</string>
<string name="poll_response_room_list_preview">投票</string>
<string name="poll_response_room_list_preview">投票</string>
<string name="end_poll_confirmation_approve_button">结束投票</string>
<string name="end_poll_confirmation_description">这将使人们无法再投票,并将显示投票的最终结果。</string>
<string name="end_poll_confirmation_title">结束此投票?</string>
@ -2274,7 +2274,7 @@
<plurals name="notice_room_server_acl_changes">
<item quantity="other">修改服务器 %d 的 ACLs</item>
</plurals>
<string name="thread_list_empty_subtitle">Thread帮助你的对话不离题且易于跟踪。</string>
<string name="thread_list_empty_subtitle">消息列帮助你的对话不离题且易于跟踪。</string>
<string name="thread_list_modal_all_threads_subtitle">显示当前房间的所有子区</string>
<string name="thread_list_modal_all_threads_title">所有子区</string>
<string name="thread_list_modal_title">筛选器</string>
@ -2310,7 +2310,7 @@
<string name="a11y_location_share_locate_button">缩放到当前位置</string>
<string name="a11y_location_share_pin_on_map">地图上选定位置的图钉</string>
<string name="poll_no_votes_cast">无投票</string>
<string name="ftue_auth_email_verification_title">检查你的电子邮件以验证。</string>
<string name="ftue_auth_email_verification_title">验证你的电子邮件</string>
<plurals name="room_removed_messages">
<item quantity="other">%d条消息已移除</item>
</plurals>
@ -2374,9 +2374,9 @@
<string name="location_activity_title_preview">位置</string>
<string name="location_activity_title_static_sharing">分享位置</string>
<string name="closed_poll_option_description">结果仅在你结束投票后展示</string>
<string name="closed_poll_option_title">已关闭的投票</string>
<string name="closed_poll_option_title">封闭式投票</string>
<string name="open_poll_option_description">投票者一投票就能看到结果</string>
<string name="open_poll_option_title">投票</string>
<string name="open_poll_option_title">放式投票</string>
<string name="poll_type_title">投票类型</string>
<string name="edit_poll_title">编辑投票</string>
<string name="poll_undisclosed_not_ended">结果将在投票结束时可见</string>
@ -2386,7 +2386,7 @@
<string name="ftue_profile_picture_title">添加用户资料图片</string>
<string name="ftue_auth_email_resend_email">重发电子邮件</string>
<string name="ftue_auth_email_verification_footer">没有收到电子邮件?</string>
<string name="ftue_auth_email_verification_subtitle">要确认你的电子邮件地址,点击我们刚刚寄到%s的电子邮件里的按钮</string>
<string name="ftue_auth_email_verification_subtitle">跟随发送到%s的说明</string>
<string name="ftue_auth_phone_confirmation_resend_code">重新发送验证码</string>
<string name="ftue_auth_phone_confirmation_subtitle">代码已发送到%s</string>
<string name="ftue_auth_phone_confirmation_title">确认你的电话号码</string>
@ -2430,7 +2430,7 @@
<string name="ftue_auth_carousel_encrypted_title">安全传送消息。</string>
<string name="settings_troubleshoot_test_endpoint_registration_failed">向主服务器注册端点token失败
\n%1$s</string>
<string name="threads_beta_enable_notice_message">Threads帮助保持你的对话不离题且易于跟踪。%s启用thread会刷新应用。这对一些账户可能需要更长时间。</string>
<string name="threads_beta_enable_notice_message">Threads帮助保持你的对话不离题且易于跟踪。%s启用消息列会刷新应用。这对一些账户可能需要更长时间。</string>
<string name="restart_the_application_to_apply_changes">重启应用以使更改生效。</string>
<string name="labs_enable_latex_maths">启用LaTeX数学</string>
<string name="audio_message_file_size">%1$s</string>
@ -2442,7 +2442,7 @@
<string name="a11y_audio_message_item">%1$s、%2$s、%3$s</string>
<string name="settings_show_latest_profile">显示最新用户信息</string>
<string name="labs_enable_thread_messages_desc">注意:应用将重启</string>
<string name="labs_enable_thread_messages">启用thread消息</string>
<string name="labs_enable_thread_messages">启用消息列消息</string>
<string name="labs_auto_report_uisi_desc">当无法解密的错误出现时,你的系统会自动发送日志</string>
<string name="labs_auto_report_uisi">自动报告解密错误。</string>
<string name="space_explore_filter_no_result_description">一些结果可能被隐藏,因为它们是私有的,你需要它们的邀请。</string>
@ -2495,11 +2495,11 @@
<string name="beta_title_bottom_sheet_action">BETA</string>
<string name="settings_troubleshoot_test_endpoint_registration_quick_fix">重设通知方式</string>
<string name="push_gateway_item_profile_tag">资料标签:</string>
<string name="navigate_to_thread_when_already_in_the_thread">你已经在查看这个thread了!</string>
<string name="navigate_to_thread_when_already_in_the_thread">你已经在查看这个消息列了!</string>
<string name="create_room_action_go">出发</string>
<string name="reply_in_thread">thread中回复</string>
<string name="reply_in_thread">消息列中回复</string>
<string name="keys_backup_settings_signature_from_this_user">备份具有来自该用户的有效签名。</string>
<string name="command_not_supported_in_threads">命令“%s”可被识别但在threads中不被支持。</string>
<string name="command_not_supported_in_threads">命令“%s”可被识别但在消息列中不被支持。</string>
<string name="font_size_use_system">使用系统默认值</string>
<string name="font_size_section_manually">手动选择</string>
<string name="font_size_section_auto">自动设置</string>
@ -2516,13 +2516,13 @@
<string name="settings_autoplay_animated_images_title">自动播放动画图片</string>
<string name="settings_troubleshoot_test_endpoint_registration_success">端点成功注册到主服务器。</string>
<string name="settings_troubleshoot_test_endpoint_registration_title">端点注册</string>
<string name="threads_labs_enable_notice_message">你的主服务器当前不支持threads所以此功能可能不可靠。Some threaded messages may not be reliably available. %s你仍要启用threads吗?</string>
<string name="threads_labs_enable_notice_message">你的主服务器当前不支持消息列所以此功能可能不可靠。Some threaded messages may not be reliably available. %s你仍要启用消息列吗?</string>
<string name="threads_notice_migration_title">Threads接近Beta了 🎉</string>
<string name="search_thread_from_a_thread">来自thread</string>
<string name="search_thread_from_a_thread">来自消息列</string>
<string name="thread_list_empty_notice">实用提示:长按消息并使用“%s”。</string>
<string name="thread_list_empty_title">使用threads来保持讨论的条理性</string>
<string name="thread_list_modal_my_threads_subtitle">显示你参与的所有threads</string>
<string name="thread_list_modal_my_threads_title">我的threads</string>
<string name="thread_list_empty_title">使用消息列来保持讨论的条理性</string>
<string name="thread_list_modal_my_threads_subtitle">显示你参与的所有消息列</string>
<string name="thread_list_modal_my_threads_title">我的消息列s</string>
<string name="room_unsupported_e2e_algorithm_as_admin">加密被错误地配置了,所以你无法发送消息。点击以打开设置。</string>
<string name="room_unsupported_e2e_algorithm">加密被错误地配置了,所以你无法发送消息。请联系管理员将加密还原到有效的状态。</string>
<string name="room_notification_more_than_two_users_are_typing">%1$s、%2$s与其他人</string>
@ -2539,4 +2539,18 @@
<string name="time_unit_hour_short">小时</string>
<string name="initial_sync_request_reason_unignored_users">- 一些用户已被取消忽略</string>
<string name="initial_sync_request_title">初始同步请求</string>
<plurals name="search_space_multiple_parents">
<item quantity="other">%1$s与其他%2$d人</item>
</plurals>
<string name="updating_your_data">正在更新你的数据……</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">自动批准Element通话组件授予相机/麦克风权限</string>
<string name="labs_enable_element_call_permission_shortcuts">启用Element通话权限捷径</string>
<string name="live_location_description">实时位置</string>
<string name="verify_invalid_qr_notice">这个QR码看起来不正常。请尝试用另一个方法验证。</string>
<string name="crosssigning_cannot_verify_this_session_desc">你无法访问加密消息历史。重置你的安全消息备份和验证密钥以重新开始。</string>
<string name="crosssigning_cannot_verify_this_session">无法验证此设备</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">你的服务器地址是什么?</string>
<string name="ftue_auth_sign_in_choose_server_header">你的对话发生的地方</string>
<string name="search_space_two_parents">%1$s和%2$s</string>
<string name="auth_reset_password_error_unverified">电子邮件未确认,检查你的收件箱</string>
</resources>

View File

@ -1273,7 +1273,7 @@
<plurals name="settings_active_sessions_count">
<item quantity="other">%d 活躍的工作階段</item>
</plurals>
<string name="crosssigning_verify_this_session">驗證此登入</string>
<string name="crosssigning_verify_this_session">驗證此裝置</string>
<string name="verification_open_other_to_verify">使用既有的工作階段來驗證這個,讓它可以存取已加密的訊息。</string>
<string name="verification_profile_verify">驗證</string>
<string name="verification_profile_verified">已驗證</string>
@ -1304,7 +1304,7 @@
<item quantity="other">使用原始大小傳送圖片</item>
</plurals>
<string name="delete_event_dialog_title">確認移除</string>
<string name="delete_event_dialog_content">您確定您想要移除(刪除)此活動嗎?注意,如果您刪除聊天室名稱或變更主題,則可能會撤銷變更</string>
<string name="delete_event_dialog_content">您確定您想要移除(刪除)此活動嗎?注意,如果您刪除聊天室名稱或主題的變更,變更會被撤銷</string>
<string name="delete_event_dialog_reason_checkbox">包含理由</string>
<string name="delete_event_dialog_reason_hint">修改原因</string>
<string name="event_redacted_by_user_reason_with_reason">被使用者刪除的活動,理由:%1$s</string>
@ -2293,9 +2293,9 @@
<string name="location_activity_title_preview">位置</string>
<string name="location_activity_title_static_sharing">分享位置</string>
<string name="closed_poll_option_description">結果僅在您結束投票後顯示</string>
<string name="closed_poll_option_title">已關閉投票</string>
<string name="closed_poll_option_title">封闭式投票</string>
<string name="open_poll_option_description">投票者在投票後可以立刻看到投票結果</string>
<string name="open_poll_option_title">投票</string>
<string name="open_poll_option_title">放式投票</string>
<string name="poll_type_title">投票類型</string>
<string name="edit_poll_title">編輯投票</string>
<string name="poll_no_votes_cast">沒有投票</string>
@ -2486,7 +2486,7 @@
<string name="labs_enable_msc3061_share_history">MSC3061為過去的訊息分享聊天室金鑰</string>
<string name="send_your_first_msg_to_invite">傳送您的第一則訊息以邀請 %s 來聊天</string>
<string name="direct_room_encryption_enabled_tile_description_future">此聊天中的訊息將會是端到端加密。</string>
<string name="create_room_action_go"></string>
<string name="create_room_action_go">出發</string>
<plurals name="room_removed_messages">
<item quantity="other">已移除 %d 則訊息</item>
</plurals>
@ -2501,8 +2501,8 @@
<string name="ftue_auth_forgot_password">忘記密碼</string>
<string name="ftue_auth_email_resend_email">重新傳送電子郵件</string>
<string name="ftue_auth_email_verification_footer">沒有收到電子郵件?</string>
<string name="ftue_auth_email_verification_subtitle">要確認您的電子郵件,請點擊我們剛剛寄給 %s 的電子郵件中的按鈕</string>
<string name="ftue_auth_email_verification_title">檢查您的電子郵件以驗證。</string>
<string name="ftue_auth_email_verification_subtitle">請遵循傳送至 %s 中的步驟</string>
<string name="ftue_auth_email_verification_title">驗證您的電子郵件</string>
<string name="ftue_auth_phone_confirmation_resend_code">重新傳送驗證碼</string>
<string name="ftue_auth_phone_confirmation_subtitle">驗證碼已傳送至 %s</string>
<string name="ftue_auth_phone_confirmation_title">確認您的電話號碼</string>
@ -2539,4 +2539,18 @@
<string name="font_size_section_manually">手動選擇</string>
<string name="font_size_section_auto">自動設定</string>
<string name="font_size_title">選擇字型大小</string>
<string name="labs_enable_element_call_permission_shortcuts_summary">自動批准 Element Call 小工具並授予相機/麥克風存取權限</string>
<string name="labs_enable_element_call_permission_shortcuts">啟用 Element Call 權限捷徑</string>
<string name="live_location_description">即時位置</string>
<string name="verify_invalid_qr_notice">這個 QR code 的格式似乎不正確。請嘗試使用其他方法進行驗證。</string>
<string name="crosssigning_cannot_verify_this_session_desc">您將無法存取已加密的訊息歷史紀錄。重設您的安全訊息備份與驗證金鑰以重新開始。</string>
<string name="crosssigning_cannot_verify_this_session">無法驗證此裝置</string>
<string name="ftue_auth_choose_server_sign_in_subtitle">您的伺服器地址是?</string>
<string name="ftue_auth_sign_in_choose_server_header">您的對話所在位置</string>
<string name="updating_your_data">正在更新您的資料……</string>
<plurals name="search_space_multiple_parents">
<item quantity="other">%1$s 與 %2$d 個其他人</item>
</plurals>
<string name="search_space_two_parents">%1$s 與 %2$s</string>
<string name="auth_reset_password_error_unverified">電子郵件未驗證,請檢查您的收件匣</string>
</resources>

View File

@ -478,6 +478,20 @@ class OnboardingViewModelTest {
.finish()
}
@Test
fun `given available username throws, when a register username is entered, then emits error`() = runTest {
viewModelWith(initialRegistrationState(A_HOMESERVER_URL))
fakeAuthenticationService.givenRegistrationWizard(FakeRegistrationWizard().also { it.givenUserNameIsAvailableThrows(A_USERNAME, AN_ERROR) })
val test = viewModel.test()
viewModel.handle(OnboardingAction.UserNameEnteredAction.Registration(A_USERNAME))
test
.assertStates(initialState)
.assertEvents(OnboardingViewEvents.Failure(AN_ERROR))
.finish()
}
@Test
fun `given available username, when a register username is entered, then emits available registration state`() = runTest {
viewModelWith(initialRegistrationState(A_HOMESERVER_URL))

View File

@ -26,7 +26,7 @@ import io.mockk.verify
import kotlinx.coroutines.runBlocking
import org.junit.Test
class LockScreenTestMigratorTests {
class LockScreenKeysMigratorTests {
private val legacyPinCodeMigrator = mockk<LegacyPinCodeMigrator>(relaxed = true)
private val missingSystemKeyMigrator = mockk<MissingSystemKeyMigrator>(relaxed = true)
@ -42,7 +42,7 @@ class LockScreenTestMigratorTests {
runBlocking { migrator.migrateIfNeeded() }
coVerify(exactly = 0) { legacyPinCodeMigrator.migrate() }
verify(exactly = 0) { missingSystemKeyMigrator.migrate() }
verify(exactly = 0) { missingSystemKeyMigrator.migrateIfNeeded() }
// When migration is needed
every { legacyPinCodeMigrator.isMigrationNeeded() } returns true
@ -50,7 +50,7 @@ class LockScreenTestMigratorTests {
runBlocking { migrator.migrateIfNeeded() }
coVerify { legacyPinCodeMigrator.migrate() }
verify { missingSystemKeyMigrator.migrate() }
verify { missingSystemKeyMigrator.migrateIfNeeded() }
}
@Test

View File

@ -44,7 +44,7 @@ class MissingSystemKeyMigratorTests {
every { keyStoreCryptoFactory.provide(any(), any()) } returns keyStoreCryptoMock
every { vectorPreferences.useBiometricsToUnlock() } returns true
missingSystemKeyMigrator.migrate()
missingSystemKeyMigrator.migrateIfNeeded()
verify { keyStoreCryptoMock.ensureKey() }
}
@ -57,7 +57,7 @@ class MissingSystemKeyMigratorTests {
every { keyStoreCryptoFactory.provide(any(), any()) } returns keyStoreCryptoMock
every { vectorPreferences.useBiometricsToUnlock() } returns true
invoking { missingSystemKeyMigrator.migrate() } shouldNotThrow KeyPermanentlyInvalidatedException::class
invoking { missingSystemKeyMigrator.migrateIfNeeded() } shouldNotThrow KeyPermanentlyInvalidatedException::class
}
@Test
@ -68,7 +68,7 @@ class MissingSystemKeyMigratorTests {
every { keyStoreCryptoFactory.provide(any(), any()) } returns keyStoreCryptoMock
every { vectorPreferences.useBiometricsToUnlock() } returns true
invoking { missingSystemKeyMigrator.migrate() } shouldNotThrow UserNotAuthenticatedException::class
invoking { missingSystemKeyMigrator.migrateIfNeeded() } shouldNotThrow UserNotAuthenticatedException::class
}
@Test
@ -79,7 +79,7 @@ class MissingSystemKeyMigratorTests {
every { keyStoreCryptoFactory.provide(any(), any()) } returns keyStoreCryptoMock
every { vectorPreferences.useBiometricsToUnlock() } returns false
missingSystemKeyMigrator.migrate()
missingSystemKeyMigrator.migrateIfNeeded()
verify(exactly = 0) { keyStoreCryptoMock.ensureKey() }
}
@ -93,7 +93,7 @@ class MissingSystemKeyMigratorTests {
every { keyStoreCryptoFactory.provide(any(), any()) } returns keyStoreCryptoMock
every { vectorPreferences.useBiometricsToUnlock() } returns false
missingSystemKeyMigrator.migrate()
missingSystemKeyMigrator.migrateIfNeeded()
verify(exactly = 0) { keyStoreCryptoMock.ensureKey() }
}

View File

@ -18,6 +18,7 @@ package im.vector.app.features.pin.lockscreen.crypto.migrations
import android.security.keystore.UserNotAuthenticatedException
import im.vector.app.features.pin.lockscreen.crypto.KeyStoreCrypto
import im.vector.app.features.settings.VectorPreferences
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
@ -31,7 +32,8 @@ class SystemKeyV1MigratorTests {
private val keyStoreCryptoFactory = mockk<KeyStoreCrypto.Factory>()
private val keyStore = mockk<KeyStore>(relaxed = true)
private val systemKeyV1Migrator = SystemKeyV1Migrator("vector.system_new", keyStore, keyStoreCryptoFactory)
private val vectorPreferences = mockk<VectorPreferences>(relaxed = true)
private val systemKeyV1Migrator = SystemKeyV1Migrator("vector.system_new", keyStore, keyStoreCryptoFactory, vectorPreferences)
@Test
fun isMigrationNeededReturnsTrueIfV1KeyExists() {

View File

@ -16,6 +16,7 @@
package im.vector.app.features.pin.lockscreen.fragment
import android.app.KeyguardManager
import android.os.Build
import android.security.keystore.KeyPermanentlyInvalidatedException
import androidx.fragment.app.FragmentActivity
@ -23,7 +24,6 @@ import com.airbnb.mvrx.test.MvRxTestRule
import com.airbnb.mvrx.withState
import im.vector.app.features.pin.lockscreen.biometrics.BiometricHelper
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguration
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguratorProvider
import im.vector.app.features.pin.lockscreen.configuration.LockScreenMode
import im.vector.app.features.pin.lockscreen.crypto.LockScreenKeysMigrator
import im.vector.app.features.pin.lockscreen.pincode.PinCodeHelper
@ -42,6 +42,7 @@ import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBeEqualTo
import org.amshove.kluent.shouldBeFalse
@ -57,7 +58,15 @@ class LockScreenViewModelTests {
private val pinCodeHelper = mockk<PinCodeHelper>(relaxed = true)
private val biometricHelper = mockk<BiometricHelper>(relaxed = true)
private val biometricHelperFactory = object : BiometricHelper.BiometricHelperFactory {
override fun create(configuration: LockScreenConfiguration): BiometricHelper {
return biometricHelper
}
}
private val keysMigrator = mockk<LockScreenKeysMigrator>(relaxed = true)
private val keyguardManager = mockk<KeyguardManager>(relaxed = true) {
every { isDeviceLocked } returns false
}
private val versionProvider = TestBuildVersionSdkIntProvider()
@Before
@ -68,19 +77,36 @@ class LockScreenViewModelTests {
@Test
fun `init migrates old keys to new ones if needed`() {
val initialState = createViewState()
val configProvider = LockScreenConfiguratorProvider(createDefaultConfiguration())
LockScreenViewModel(initialState, pinCodeHelper, biometricHelper, keysMigrator, configProvider, versionProvider)
LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
coVerify { keysMigrator.migrateIfNeeded() }
}
@Test
fun `init updates the initial state with biometric info`() = runTest {
every { biometricHelper.isSystemAuthEnabledAndValid } returns true
val initialState = createViewState()
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
advanceUntilIdle()
val newState = viewModel.awaitState()
newState shouldNotBeEqualTo initialState
}
@Test
fun `Updating the initial state with biometric info waits until device is unlocked on Android 12+`() = runTest {
val initialState = createViewState()
versionProvider.value = Build.VERSION_CODES.S
LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
advanceUntilIdle()
verify { keyguardManager.isDeviceLocked }
}
@Test
fun `when ViewModel is instantiated initialState is updated with biometric info`() {
val initialState = createViewState()
val configProvider = LockScreenConfiguratorProvider(createDefaultConfiguration())
// This should set canUseBiometricAuth to true
every { biometricHelper.isSystemAuthEnabledAndValid } returns true
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelper, keysMigrator, configProvider, versionProvider)
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
val newState = withState(viewModel) { it }
initialState shouldNotBeEqualTo newState
}
@ -88,8 +114,7 @@ class LockScreenViewModelTests {
@Test
fun `when onPinCodeEntered is called in VERIFY mode, the code is verified and the result is emitted as a ViewEvent`() = runTest {
val initialState = createViewState()
val configProvider = LockScreenConfiguratorProvider(createDefaultConfiguration())
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelper, keysMigrator, configProvider, versionProvider)
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
coEvery { pinCodeHelper.verifyPinCode(any()) } returns true
val events = viewModel.test().viewEvents
@ -113,8 +138,7 @@ class LockScreenViewModelTests {
fun `when onPinCodeEntered is called in CREATE mode with no confirmation needed it creates the pin code`() = runTest {
val configuration = createDefaultConfiguration(mode = LockScreenMode.CREATE, needsNewCodeValidation = false)
val initialState = createViewState(lockScreenConfiguration = configuration)
val configProvider = LockScreenConfiguratorProvider(configuration)
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelper, keysMigrator, configProvider, versionProvider)
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
val events = viewModel.test().viewEvents
events.assertNoValues()
@ -128,9 +152,8 @@ class LockScreenViewModelTests {
@Test
fun `when onPinCodeEntered is called twice in CREATE mode with confirmation needed it verifies and creates the pin code`() = runTest {
val configuration = createDefaultConfiguration(mode = LockScreenMode.CREATE, needsNewCodeValidation = true)
val configProvider = LockScreenConfiguratorProvider(configuration)
val initialState = createViewState(lockScreenConfiguration = configuration)
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelper, keysMigrator, configProvider, versionProvider)
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
val events = viewModel.test().viewEvents
events.assertNoValues()
@ -149,8 +172,7 @@ class LockScreenViewModelTests {
fun `when onPinCodeEntered is called in CREATE mode with incorrect confirmation it clears the pin code`() = runTest {
val configuration = createDefaultConfiguration(mode = LockScreenMode.CREATE, needsNewCodeValidation = true)
val initialState = createViewState(lockScreenConfiguration = configuration)
val configProvider = LockScreenConfiguratorProvider(configuration)
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelper, keysMigrator, configProvider, versionProvider)
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
val events = viewModel.test().viewEvents
events.assertNoValues()
@ -170,8 +192,7 @@ class LockScreenViewModelTests {
@Test
fun `onPinCodeEntered handles exceptions`() = runTest {
val initialState = createViewState()
val configProvider = LockScreenConfiguratorProvider(createDefaultConfiguration())
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelper, keysMigrator, configProvider, versionProvider)
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
val exception = IllegalStateException("Something went wrong")
coEvery { pinCodeHelper.verifyPinCode(any()) } throws exception
@ -187,39 +208,34 @@ class LockScreenViewModelTests {
fun `when showBiometricPrompt catches a KeyPermanentlyInvalidatedException it disables biometric authentication`() = runTest {
versionProvider.value = Build.VERSION_CODES.M
every { biometricHelper.isSystemAuthEnabledAndValid } returns true
every { biometricHelper.isSystemKeyValid } returns true
every { biometricHelper.isSystemKeyValid } returns false
val exception = KeyPermanentlyInvalidatedException()
coEvery { biometricHelper.authenticate(any<FragmentActivity>()) } throws exception
coEvery { biometricHelper.disableAuthentication() } coAnswers {
every { biometricHelper.isSystemAuthEnabledAndValid } returns false
}
val configuration = createDefaultConfiguration(mode = LockScreenMode.VERIFY, needsNewCodeValidation = true, isBiometricsEnabled = true)
val configProvider = LockScreenConfiguratorProvider(configuration)
val initialState = createViewState(
canUseBiometricAuth = true,
isBiometricKeyInvalidated = false,
lockScreenConfiguration = configuration
)
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelper, keysMigrator, configProvider, versionProvider)
val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
val events = viewModel.test().viewEvents
events.assertNoValues()
viewModel.handle(LockScreenAction.ShowBiometricPrompt(mockk()))
events.assertValues(LockScreenViewEvent.AuthError(AuthMethod.BIOMETRICS, exception))
events.assertValues(LockScreenViewEvent.ShowBiometricKeyInvalidatedMessage)
verify { biometricHelper.disableAuthentication() }
// System key was deleted, biometric auth should be disabled
every { biometricHelper.isSystemAuthEnabledAndValid } returns false
val newState = viewModel.awaitState()
newState.canUseBiometricAuth.shouldBeFalse()
}
@Test
fun `when showBiometricPrompt receives an event it propagates it as a ViewEvent`() = runTest {
val configProvider = LockScreenConfiguratorProvider(createDefaultConfiguration())
val viewModel = LockScreenViewModel(createViewState(), pinCodeHelper, biometricHelper, keysMigrator, configProvider, versionProvider)
val viewModel = LockScreenViewModel(createViewState(), pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
coEvery { biometricHelper.authenticate(any<FragmentActivity>()) } returns flowOf(false, true)
val events = viewModel.test().viewEvents
@ -232,8 +248,7 @@ class LockScreenViewModelTests {
@Test
fun `showBiometricPrompt handles exceptions`() = runTest {
val configProvider = LockScreenConfiguratorProvider(createDefaultConfiguration())
val viewModel = LockScreenViewModel(createViewState(), pinCodeHelper, biometricHelper, keysMigrator, configProvider, versionProvider)
val viewModel = LockScreenViewModel(createViewState(), pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager)
val exception = IllegalStateException("Something went wrong")
coEvery { biometricHelper.authenticate(any<FragmentActivity>()) } throws exception

View File

@ -57,6 +57,10 @@ class FakeRegistrationWizard : RegistrationWizard by mockk(relaxed = false) {
coEvery { registrationAvailable(userName) } returns RegistrationAvailability.Available
}
fun givenUserNameIsAvailableThrows(userName: String, cause: Throwable) {
coEvery { registrationAvailable(userName) } throws cause
}
fun givenUserNameIsUnavailable(userName: String, failure: Failure.ServerError) {
coEvery { registrationAvailable(userName) } returns RegistrationAvailability.NotAvailable(failure)
}