Skip to content

Commit 12f8907

Browse files
Merge pull request #17070 from nextcloud/backport/17024/stable-33.1.x
[stable-33.1.x] simplify passcode delay translation
2 parents 69e034a + e14cebd commit 12f8907

4 files changed

Lines changed: 154 additions & 57 deletions

File tree

app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.kt

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class PassCodeActivity :
4646
companion object {
4747
private val TAG = PassCodeActivity::class.java.simpleName
4848

49+
private const val ONE_SECOND_MS = 1000L
4950
private const val KEY_PASSCODE_DIGITS = "PASSCODE_DIGITS"
5051
private const val KEY_CONFIRMING_PASSCODE = "CONFIRMING_PASSCODE"
5152
const val ACTION_REQUEST_WITH_RESULT = "ACTION_REQUEST_WITH_RESULT"
@@ -79,6 +80,8 @@ class PassCodeActivity :
7980
private var changed = true // to control that only one blocks jump
8081
private var delayInSeconds = 0
8182

83+
private val delayFormatter by lazy { PassCodeDelayFormatter(resources) }
84+
8285
override fun onCreate(savedInstanceState: Bundle?) {
8386
super.onCreate(savedInstanceState)
8487
delayInSeconds = preferences.passCodeDelay
@@ -369,45 +372,6 @@ class PassCodeActivity :
369372
}
370373
}
371374

372-
@Suppress("MagicNumber")
373-
private fun getExplanationText(timeInSecond: Int): String = when {
374-
timeInSecond < 60 -> resources.getQuantityString(
375-
R.plurals.delay_message,
376-
timeInSecond,
377-
timeInSecond
378-
)
379-
380-
else -> {
381-
val minutes = timeInSecond / 60
382-
val remainingSeconds = timeInSecond % 60
383-
384-
when {
385-
remainingSeconds == 0 -> resources.getQuantityString(
386-
R.plurals.delay_message_minutes,
387-
minutes,
388-
minutes
389-
)
390-
391-
else -> {
392-
val minuteText = resources.getQuantityString(
393-
R.plurals.delay_message_minutes_part,
394-
minutes,
395-
minutes
396-
)
397-
val secondText = resources.getQuantityString(
398-
R.plurals.delay_message_seconds_part,
399-
remainingSeconds,
400-
remainingSeconds
401-
)
402-
403-
val prefixText = "$minuteText $secondText"
404-
getString(R.string.due_to_too_many_wrong_attempts, prefixText)
405-
}
406-
}
407-
}
408-
}
409-
410-
@Suppress("MagicNumber")
411375
private fun showDelay() {
412376
val pinBruteForceCount = preferences.pinBruteForceDelay()
413377
if (pinBruteForceCount <= 0) {
@@ -419,8 +383,8 @@ class PassCodeActivity :
419383
var counter = delayInSeconds
420384
lifecycleScope.launch(Dispatchers.Main) {
421385
while (counter != 0) {
422-
binding.explanation.text = getExplanationText(counter)
423-
delay(1000)
386+
binding.explanation.text = delayFormatter.getExplanationText(counter)
387+
delay(ONE_SECOND_MS)
424388
counter -= 1
425389
}
426390

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Nextcloud - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
package com.owncloud.android.ui.activity
8+
9+
import android.content.res.Resources
10+
import com.owncloud.android.R
11+
12+
class PassCodeDelayFormatter(private val resources: Resources) {
13+
14+
fun getExplanationText(timeInSeconds: Int): String {
15+
val minutes = timeInSeconds / SECONDS_PER_MINUTE
16+
val remainingSeconds = timeInSeconds % SECONDS_PER_MINUTE
17+
18+
return when {
19+
timeInSeconds < SECONDS_PER_MINUTE -> resources.getQuantityString(
20+
R.plurals.passcode_delay_seconds,
21+
timeInSeconds,
22+
timeInSeconds
23+
)
24+
25+
remainingSeconds == 0 -> resources.getQuantityString(
26+
R.plurals.passcode_delay_minutes,
27+
minutes,
28+
minutes
29+
)
30+
31+
else -> resources.getQuantityString(
32+
R.plurals.passcode_delay_minutes_seconds,
33+
minutes,
34+
minutes,
35+
remainingSeconds
36+
)
37+
}
38+
}
39+
40+
companion object {
41+
const val SECONDS_PER_MINUTE = 60
42+
}
43+
}

app/src/main/res/values/strings.xml

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,28 +1275,21 @@
12751275

12761276
<string name="login_url_helper_text">The link to your %1$s web interface when you open it in the browser.</string>
12771277

1278-
<plurals name="delay_message">
1279-
<item quantity="one">Delayed %d second due to too many wrong attempts</item>
1280-
<item quantity="other">Delayed %d seconds due to too many wrong attempts</item>
1278+
<plurals name="passcode_delay_seconds">
1279+
<item quantity="one">Try again in %d second due to too many wrong attempts</item>
1280+
<item quantity="other">Try again in %d seconds due to too many wrong attempts</item>
12811281
</plurals>
12821282

1283-
<plurals name="delay_message_minutes">
1284-
<item quantity="one">Delayed %d minute due to too many wrong attempts</item>
1285-
<item quantity="other">Delayed %d minutes due to too many wrong attempts</item>
1283+
<plurals name="passcode_delay_minutes">
1284+
<item quantity="one">Try again in %d minute due to too many wrong attempts</item>
1285+
<item quantity="other">Try again in %d minutes due to too many wrong attempts</item>
12861286
</plurals>
12871287

1288-
<plurals name="delay_message_minutes_part">
1289-
<item quantity="one">Delayed %d minute</item>
1290-
<item quantity="other">Delayed %d minutes</item>
1288+
<plurals name="passcode_delay_minutes_seconds">
1289+
<item quantity="one">Try again in %1$d minute and %2$d seconds due to too many wrong attempts</item>
1290+
<item quantity="other">Try again in %1$d minutes and %2$d seconds due to too many wrong attempts</item>
12911291
</plurals>
12921292

1293-
<plurals name="delay_message_seconds_part">
1294-
<item quantity="one">%d second</item>
1295-
<item quantity="other">%d seconds</item>
1296-
</plurals>
1297-
1298-
<string name="due_to_too_many_wrong_attempts">%s due to too many wrong attempts</string>
1299-
13001293

13011294
<string name="create">Create</string>
13021295
<string name="select_one_template">Please select one template</string>
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Nextcloud - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
package com.owncloud.android.ui.activity
8+
9+
import android.content.res.Resources
10+
import com.owncloud.android.R
11+
import io.mockk.every
12+
import io.mockk.mockk
13+
import org.junit.Assert.assertEquals
14+
import org.junit.Before
15+
import org.junit.Test
16+
17+
class PassCodeDelayFormatterTest {
18+
19+
private lateinit var resources: Resources
20+
private lateinit var sut: PassCodeDelayFormatter
21+
22+
@Before
23+
fun setUp() {
24+
resources = mockk()
25+
sut = PassCodeDelayFormatter(resources)
26+
}
27+
28+
@Test
29+
fun testGetExplanationTextWhenGivenOneSecondShouldReturnSingularSecondsString() {
30+
val expected = "Try again in 1 second due to too many wrong attempts"
31+
every { resources.getQuantityString(R.plurals.passcode_delay_seconds, 1, 1) } returns expected
32+
33+
val result = sut.getExplanationText(1)
34+
35+
assertEquals(expected, result)
36+
}
37+
38+
@Test
39+
fun testGetExplanationTextWhenGivenFiftyNineSecondsShouldReturnPluralSecondsString() {
40+
val expected = "Try again in 59 seconds due to too many wrong attempts"
41+
every { resources.getQuantityString(R.plurals.passcode_delay_seconds, 59, 59) } returns expected
42+
43+
val result = sut.getExplanationText(59)
44+
45+
assertEquals(expected, result)
46+
}
47+
48+
@Test
49+
fun testGetExplanationTextWhenGivenSixtySecondsShouldReturnSingularMinutesString() {
50+
val expected = "Try again in 1 minute due to too many wrong attempts"
51+
every { resources.getQuantityString(R.plurals.passcode_delay_minutes, 1, 1) } returns expected
52+
53+
val result = sut.getExplanationText(60)
54+
55+
assertEquals(expected, result)
56+
}
57+
58+
@Test
59+
fun testGetExplanationTextWhenGivenOneHundredTwentySecondsShouldReturnPluralMinutesString() {
60+
val expected = "Try again in 2 minutes due to too many wrong attempts"
61+
every { resources.getQuantityString(R.plurals.passcode_delay_minutes, 2, 2) } returns expected
62+
63+
val result = sut.getExplanationText(120)
64+
65+
assertEquals(expected, result)
66+
}
67+
68+
@Test
69+
fun testGetExplanationTextWhenGivenNinetySecondsShouldReturnMinutesAndSecondsString() {
70+
val expected = "Try again in 1 minute and 30 seconds due to too many wrong attempts"
71+
every { resources.getQuantityString(R.plurals.passcode_delay_minutes_seconds, 1, 1, 30) } returns expected
72+
73+
val result = sut.getExplanationText(90)
74+
75+
assertEquals(expected, result)
76+
}
77+
78+
@Test
79+
fun testGetExplanationTextWhenGivenOneHundredFortyFiveSecondsShouldReturnMinutesAndSecondsString() {
80+
val expected = "Try again in 2 minutes and 25 seconds due to too many wrong attempts"
81+
every { resources.getQuantityString(R.plurals.passcode_delay_minutes_seconds, 2, 2, 25) } returns expected
82+
83+
val result = sut.getExplanationText(145)
84+
85+
assertEquals(expected, result)
86+
}
87+
88+
@Test
89+
fun testGetExplanationTextWhenGivenThreeHundredSecondsShouldReturnFiveMinutesString() {
90+
val expected = "Try again in 5 minutes due to too many wrong attempts"
91+
every { resources.getQuantityString(R.plurals.passcode_delay_minutes, 5, 5) } returns expected
92+
93+
val result = sut.getExplanationText(300)
94+
95+
assertEquals(expected, result)
96+
}
97+
}

0 commit comments

Comments
 (0)