feat: adding friends

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2025-06-13 03:27:42 +02:00
parent a11864ba0d
commit 0d2b037a6f
33 changed files with 1421 additions and 43 deletions

View File

@ -277,8 +277,9 @@ dependencies {
implementation("dev.chrisbanes.haze:haze:1.6.4")
implementation("dev.chrisbanes.haze:haze-materials:1.6.4")
// ZXing - QR Code generation
// QR code related
implementation("com.google.zxing:core:3.5.3")
implementation("io.github.g00fy2.quickie:quickie-bundled:1.11.0")
// Persistence
implementation("app.cash.sqldelight:android-driver:2.0.1")

View File

@ -1,5 +1,6 @@
package chat.revolt.api.internals
import androidx.core.net.toUri
import chat.revolt.api.RevoltCbor
import chat.revolt.api.schemas.User
import kotlinx.serialization.ExperimentalSerializationApi
@ -37,4 +38,16 @@ object UserQR {
)
)
}
@OptIn(ExperimentalEncodingApi::class, ExperimentalSerializationApi::class)
fun fromUri(uriString: String): UserQRContents? {
return try {
val uri = uriString.toUri()
val base64 = uri.query ?: return null
val decodedBytes = Base64.decode(base64)
RevoltCbor.decodeFromByteArray(UserQRContents.serializer(), decodedBytes)
} catch (e: Exception) {
null
}
}
}

View File

@ -0,0 +1,849 @@
package chat.revolt.components.vectorassets
import androidx.compose.foundation.Image
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
const val HL_USERNAME = 0xFF4799F0
const val HL_TAG = 0xFF3ABF7E
val RevoltTagIntro: ImageVector
@Composable
get() {
if (_RevoltTagIntro != null) {
return _RevoltTagIntro!!
}
_RevoltTagIntro = ImageVector.Builder(
name = "RevoltTagIntro",
defaultWidth = 700.dp,
defaultHeight = 412.dp,
viewportWidth = 700f,
viewportHeight = 412f
).apply {
path(fill = SolidColor(MaterialTheme.colorScheme.primaryContainer)) {
moveTo(39.67f, 33.24f)
lineTo(641.51f, 2.03f)
arcTo(
39f,
39f,
54.42f,
isMoreThanHalf = false,
isPositiveArc = true,
682.48f,
38.95f
)
lineTo(697.94f, 336.99f)
arcTo(
39f,
39f,
132.66f,
isMoreThanHalf = false,
isPositiveArc = true,
661.01f,
377.96f
)
lineTo(59.17f, 409.18f)
arcTo(39f, 39f, 0f, isMoreThanHalf = false, isPositiveArc = true, 18.2f, 372.25f)
lineTo(2.74f, 74.21f)
arcTo(39f, 39f, 0f, isMoreThanHalf = false, isPositiveArc = true, 39.67f, 33.24f)
close()
}
path(fill = SolidColor(MaterialTheme.colorScheme.onPrimaryContainer)) {
moveTo(72.56f, 104.52f)
lineTo(70.96f, 71.52f)
lineTo(78.93f, 71.13f)
lineTo(79.55f, 83.95f)
lineTo(92.11f, 83.34f)
lineTo(91.48f, 70.52f)
lineTo(99.46f, 70.14f)
lineTo(101.06f, 103.13f)
lineTo(93.09f, 103.52f)
lineTo(92.44f, 90.12f)
lineTo(79.88f, 90.73f)
lineTo(80.53f, 104.13f)
lineTo(72.56f, 104.52f)
close()
moveTo(112.14f, 102.59f)
lineTo(110.53f, 69.6f)
lineTo(135.11f, 68.4f)
lineTo(135.44f, 75.18f)
lineTo(118.83f, 75.98f)
lineTo(119.14f, 82.34f)
lineTo(134.49f, 81.59f)
lineTo(134.81f, 88.17f)
lineTo(119.46f, 88.92f)
lineTo(119.78f, 95.43f)
lineTo(136.39f, 94.62f)
lineTo(136.72f, 101.4f)
lineTo(112.14f, 102.59f)
close()
moveTo(147.02f, 100.89f)
lineTo(145.41f, 67.9f)
lineTo(153.38f, 67.51f)
lineTo(154.66f, 93.73f)
lineTo(169.27f, 93.02f)
lineTo(169.6f, 99.8f)
lineTo(147.02f, 100.89f)
close()
moveTo(179.46f, 99.32f)
lineTo(177.86f, 66.32f)
lineTo(185.83f, 65.93f)
lineTo(187.11f, 92.15f)
lineTo(201.72f, 91.44f)
lineTo(202.05f, 98.22f)
lineTo(179.46f, 99.32f)
close()
moveTo(225.46f, 97.61f)
curveTo(222.48f, 97.76f, 219.76f, 97.22f, 217.31f, 95.99f)
curveTo(214.86f, 94.75f, 212.89f, 92.89f, 211.38f, 90.42f)
curveTo(209.86f, 87.95f, 209.02f, 84.93f, 208.85f, 81.37f)
curveTo(208.68f, 77.79f, 209.22f, 74.69f, 210.48f, 72.08f)
curveTo(211.75f, 69.46f, 213.54f, 67.42f, 215.85f, 65.96f)
curveTo(218.17f, 64.5f, 220.83f, 63.7f, 223.81f, 63.56f)
curveTo(226.79f, 63.41f, 229.5f, 63.95f, 231.95f, 65.18f)
curveTo(234.39f, 66.41f, 236.36f, 68.26f, 237.88f, 70.75f)
curveTo(239.39f, 73.22f, 240.23f, 76.25f, 240.4f, 79.84f)
curveTo(240.58f, 83.41f, 240.03f, 86.5f, 238.77f, 89.11f)
curveTo(237.5f, 91.72f, 235.72f, 93.75f, 233.4f, 95.21f)
curveTo(231.09f, 96.67f, 228.45f, 97.47f, 225.46f, 97.61f)
close()
moveTo(225.13f, 90.66f)
curveTo(226.71f, 90.58f, 228.05f, 90.13f, 229.17f, 89.29f)
curveTo(230.29f, 88.43f, 231.14f, 87.25f, 231.7f, 85.72f)
curveTo(232.26f, 84.19f, 232.49f, 82.36f, 232.39f, 80.23f)
curveTo(232.28f, 78.09f, 231.88f, 76.28f, 231.17f, 74.81f)
curveTo(230.46f, 73.33f, 229.51f, 72.23f, 228.3f, 71.51f)
curveTo(227.11f, 70.76f, 225.73f, 70.43f, 224.15f, 70.51f)
curveTo(222.58f, 70.58f, 221.24f, 71.05f, 220.11f, 71.9f)
curveTo(218.98f, 72.74f, 218.13f, 73.93f, 217.55f, 75.47f)
curveTo(216.99f, 77.01f, 216.76f, 78.84f, 216.87f, 80.98f)
curveTo(216.97f, 83.11f, 217.37f, 84.91f, 218.08f, 86.39f)
curveTo(218.8f, 87.84f, 219.77f, 88.94f, 220.97f, 89.69f)
curveTo(222.18f, 90.41f, 223.56f, 90.74f, 225.13f, 90.66f)
close()
moveTo(248.51f, 103.15f)
lineTo(249.37f, 90.21f)
lineTo(256.57f, 89.86f)
lineTo(253.8f, 102.89f)
lineTo(248.51f, 103.15f)
close()
moveTo(281.61f, 94.35f)
lineTo(280.01f, 61.36f)
lineTo(291.79f, 60.78f)
lineTo(296.67f, 73.53f)
curveTo(296.94f, 74.3f, 297.27f, 75.25f, 297.65f, 76.37f)
curveTo(298.03f, 77.49f, 298.42f, 78.67f, 298.82f, 79.91f)
curveTo(299.22f, 81.13f, 299.6f, 82.3f, 299.95f, 83.43f)
curveTo(300.3f, 84.55f, 300.58f, 85.49f, 300.79f, 86.25f)
lineTo(298.78f, 86.35f)
curveTo(298.92f, 85.57f, 299.1f, 84.61f, 299.33f, 83.46f)
curveTo(299.57f, 82.3f, 299.83f, 81.1f, 300.1f, 79.84f)
curveTo(300.38f, 78.57f, 300.65f, 77.36f, 300.9f, 76.21f)
curveTo(301.17f, 75.06f, 301.4f, 74.08f, 301.58f, 73.29f)
lineTo(305.16f, 60.13f)
lineTo(316.96f, 59.56f)
lineTo(318.57f, 92.55f)
lineTo(310.75f, 92.93f)
lineTo(310.06f, 78.65f)
curveTo(310.02f, 77.91f, 309.99f, 76.99f, 309.97f, 75.88f)
curveTo(309.94f, 74.77f, 309.91f, 73.57f, 309.88f, 72.29f)
curveTo(309.86f, 71f, 309.84f, 69.7f, 309.8f, 68.39f)
curveTo(309.78f, 67.07f, 309.74f, 65.83f, 309.69f, 64.66f)
lineTo(310.62f, 64.62f)
curveTo(310.35f, 65.86f, 310.07f, 67.15f, 309.76f, 68.5f)
curveTo(309.46f, 69.85f, 309.16f, 71.17f, 308.87f, 72.47f)
curveTo(308.59f, 73.76f, 308.32f, 74.95f, 308.07f, 76.04f)
curveTo(307.81f, 77.12f, 307.58f, 78.03f, 307.38f, 78.78f)
lineTo(303.33f, 93.29f)
lineTo(296.89f, 93.61f)
lineTo(291.37f, 79.56f)
curveTo(291.11f, 78.83f, 290.79f, 77.94f, 290.42f, 76.9f)
curveTo(290.04f, 75.84f, 289.64f, 74.68f, 289.23f, 73.43f)
curveTo(288.81f, 72.16f, 288.38f, 70.87f, 287.93f, 69.56f)
curveTo(287.49f, 68.25f, 287.08f, 66.99f, 286.68f, 65.78f)
lineTo(287.74f, 65.73f)
curveTo(287.81f, 66.89f, 287.9f, 68.13f, 287.99f, 69.45f)
curveTo(288.08f, 70.76f, 288.18f, 72.06f, 288.27f, 73.34f)
curveTo(288.38f, 74.62f, 288.47f, 75.82f, 288.55f, 76.92f)
curveTo(288.64f, 78.03f, 288.7f, 78.95f, 288.73f, 79.69f)
lineTo(289.43f, 93.97f)
lineTo(281.61f, 94.35f)
close()
moveTo(339.88f, 91.52f)
lineTo(339.3f, 79.71f)
lineTo(326.02f, 59.12f)
lineTo(335.13f, 58.68f)
lineTo(340.8f, 68.01f)
curveTo(341.28f, 68.83f, 341.76f, 69.65f, 342.23f, 70.47f)
curveTo(342.7f, 71.29f, 343.16f, 72.11f, 343.61f, 72.93f)
lineTo(342.21f, 73f)
curveTo(342.56f, 72.14f, 342.91f, 71.28f, 343.27f, 70.42f)
curveTo(343.64f, 69.56f, 344.03f, 68.7f, 344.43f, 67.83f)
lineTo(348.92f, 58f)
lineTo(357.98f, 57.56f)
lineTo(347.03f, 79.34f)
lineTo(347.6f, 91.14f)
lineTo(339.88f, 91.52f)
close()
moveTo(384.53f, 89.35f)
lineTo(382.92f, 56.35f)
lineTo(391.16f, 55.95f)
lineTo(401.26f, 70.49f)
curveTo(401.64f, 71.02f, 402.11f, 71.72f, 402.67f, 72.62f)
curveTo(403.23f, 73.51f, 403.82f, 74.46f, 404.45f, 75.48f)
curveTo(405.08f, 76.5f, 405.66f, 77.47f, 406.21f, 78.39f)
lineTo(405.39f, 80.58f)
curveTo(405.27f, 79.5f, 405.16f, 78.25f, 405.05f, 76.85f)
curveTo(404.94f, 75.43f, 404.83f, 74.07f, 404.74f, 72.76f)
curveTo(404.66f, 71.45f, 404.6f, 70.4f, 404.57f, 69.64f)
lineTo(403.87f, 55.33f)
lineTo(411.84f, 54.94f)
lineTo(413.45f, 87.94f)
lineTo(405.19f, 88.34f)
lineTo(395.93f, 75.03f)
curveTo(395.48f, 74.37f, 394.91f, 73.52f, 394.23f, 72.47f)
curveTo(393.54f, 71.42f, 392.79f, 70.25f, 391.97f, 68.94f)
curveTo(391.17f, 67.63f, 390.34f, 66.27f, 389.48f, 64.87f)
lineTo(390.96f, 64.13f)
curveTo(391.14f, 65.7f, 391.29f, 67.22f, 391.4f, 68.68f)
curveTo(391.52f, 70.14f, 391.61f, 71.44f, 391.68f, 72.57f)
curveTo(391.75f, 73.69f, 391.8f, 74.57f, 391.83f, 75.21f)
lineTo(392.5f, 88.96f)
lineTo(384.53f, 89.35f)
close()
moveTo(422.49f, 87.5f)
lineTo(432.22f, 53.95f)
lineTo(442.71f, 53.44f)
lineTo(455.72f, 85.88f)
lineTo(446.82f, 86.32f)
lineTo(441.64f, 72.03f)
curveTo(440.8f, 69.64f, 439.97f, 67.24f, 439.14f, 64.8f)
curveTo(438.31f, 62.37f, 437.46f, 59.74f, 436.58f, 56.89f)
lineTo(438.73f, 56.79f)
curveTo(438.1f, 59.71f, 437.48f, 62.41f, 436.88f, 64.91f)
curveTo(436.29f, 67.41f, 435.68f, 69.89f, 435.05f, 72.35f)
lineTo(431.14f, 87.08f)
lineTo(422.49f, 87.5f)
close()
moveTo(429.95f, 80.77f)
lineTo(429.65f, 74.54f)
lineTo(447.34f, 73.68f)
lineTo(447.64f, 79.91f)
lineTo(429.95f, 80.77f)
close()
moveTo(464.79f, 85.44f)
lineTo(463.18f, 52.45f)
lineTo(474.96f, 51.88f)
lineTo(479.84f, 64.62f)
curveTo(480.12f, 65.39f, 480.45f, 66.34f, 480.83f, 67.46f)
curveTo(481.2f, 68.58f, 481.6f, 69.76f, 482f, 71f)
curveTo(482.39f, 72.22f, 482.77f, 73.4f, 483.12f, 74.52f)
curveTo(483.47f, 75.64f, 483.75f, 76.58f, 483.97f, 77.34f)
lineTo(481.95f, 77.44f)
curveTo(482.09f, 76.66f, 482.28f, 75.7f, 482.5f, 74.55f)
curveTo(482.74f, 73.4f, 483f, 72.19f, 483.28f, 70.94f)
curveTo(483.56f, 69.67f, 483.83f, 68.45f, 484.08f, 67.3f)
curveTo(484.35f, 66.15f, 484.58f, 65.18f, 484.76f, 64.38f)
lineTo(488.34f, 51.22f)
lineTo(500.14f, 50.65f)
lineTo(501.74f, 83.65f)
lineTo(493.93f, 84.03f)
lineTo(493.23f, 69.74f)
curveTo(493.2f, 69f, 493.17f, 68.08f, 493.14f, 66.97f)
curveTo(493.12f, 65.86f, 493.09f, 64.67f, 493.06f, 63.38f)
curveTo(493.04f, 62.09f, 493.01f, 60.79f, 492.98f, 59.48f)
curveTo(492.96f, 58.16f, 492.92f, 56.92f, 492.86f, 55.75f)
lineTo(493.79f, 55.71f)
curveTo(493.53f, 56.95f, 493.24f, 58.24f, 492.94f, 59.59f)
curveTo(492.63f, 60.94f, 492.34f, 62.26f, 492.04f, 63.56f)
curveTo(491.77f, 64.85f, 491.5f, 66.04f, 491.24f, 67.13f)
curveTo(490.98f, 68.21f, 490.75f, 69.12f, 490.55f, 69.87f)
lineTo(486.51f, 84.39f)
lineTo(480.07f, 84.7f)
lineTo(474.54f, 70.65f)
curveTo(474.29f, 69.92f, 473.97f, 69.04f, 473.59f, 67.99f)
curveTo(473.21f, 66.93f, 472.82f, 65.77f, 472.4f, 64.52f)
curveTo(471.99f, 63.25f, 471.55f, 61.96f, 471.11f, 60.65f)
curveTo(470.67f, 59.34f, 470.25f, 58.08f, 469.86f, 56.87f)
lineTo(470.92f, 56.82f)
curveTo(470.99f, 57.99f, 471.07f, 59.23f, 471.17f, 60.54f)
curveTo(471.26f, 61.85f, 471.35f, 63.15f, 471.44f, 64.43f)
curveTo(471.55f, 65.71f, 471.64f, 66.91f, 471.73f, 68.01f)
curveTo(471.81f, 69.12f, 471.87f, 70.04f, 471.91f, 70.78f)
lineTo(472.6f, 85.06f)
lineTo(464.79f, 85.44f)
close()
moveTo(512.82f, 83.11f)
lineTo(511.22f, 50.11f)
lineTo(535.8f, 48.92f)
lineTo(536.13f, 55.69f)
lineTo(519.52f, 56.5f)
lineTo(519.83f, 62.86f)
lineTo(535.17f, 62.11f)
lineTo(535.49f, 68.69f)
lineTo(520.15f, 69.43f)
lineTo(520.46f, 75.94f)
lineTo(537.07f, 75.14f)
lineTo(537.4f, 81.91f)
lineTo(512.82f, 83.11f)
close()
moveTo(562.72f, 80.68f)
lineTo(562.41f, 74.35f)
lineTo(566.53f, 74.15f)
lineTo(565.54f, 53.82f)
lineTo(561.42f, 54.02f)
lineTo(561.11f, 47.69f)
lineTo(577.33f, 46.9f)
lineTo(577.63f, 53.23f)
lineTo(573.51f, 53.43f)
lineTo(574.5f, 73.76f)
lineTo(578.62f, 73.56f)
lineTo(578.93f, 79.89f)
lineTo(562.72f, 80.68f)
close()
moveTo(602.28f, 79.29f)
curveTo(599.35f, 79.43f, 596.84f, 79.11f, 594.75f, 78.32f)
curveTo(592.65f, 77.52f, 591.03f, 76.3f, 589.87f, 74.65f)
curveTo(588.71f, 72.99f, 588.07f, 70.95f, 587.95f, 68.53f)
lineTo(595.54f, 68.16f)
curveTo(595.62f, 69.21f, 595.94f, 70.1f, 596.49f, 70.83f)
curveTo(597.05f, 71.55f, 597.79f, 72.09f, 598.73f, 72.45f)
curveTo(599.67f, 72.8f, 600.78f, 72.95f, 602.03f, 72.89f)
curveTo(603.17f, 72.83f, 604.14f, 72.64f, 604.96f, 72.3f)
curveTo(605.78f, 71.96f, 606.41f, 71.52f, 606.84f, 70.97f)
curveTo(607.29f, 70.4f, 607.5f, 69.75f, 607.46f, 69.03f)
curveTo(607.43f, 68.41f, 607.21f, 67.88f, 606.78f, 67.44f)
curveTo(606.38f, 66.99f, 605.74f, 66.61f, 604.89f, 66.31f)
curveTo(604.04f, 66f, 602.95f, 65.73f, 601.61f, 65.52f)
lineTo(598.19f, 64.99f)
curveTo(594.93f, 64.49f, 592.45f, 63.49f, 590.74f, 62f)
curveTo(589.02f, 60.51f, 588.11f, 58.55f, 587.99f, 56.15f)
curveTo(587.89f, 54.09f, 588.34f, 52.27f, 589.34f, 50.69f)
curveTo(590.36f, 49.1f, 591.82f, 47.83f, 593.73f, 46.88f)
curveTo(595.64f, 45.91f, 597.88f, 45.37f, 600.47f, 45.24f)
curveTo(603.11f, 45.11f, 605.4f, 45.44f, 607.35f, 46.21f)
curveTo(609.3f, 46.98f, 610.83f, 48.14f, 611.96f, 49.7f)
curveTo(613.1f, 51.25f, 613.76f, 53.16f, 613.95f, 55.42f)
lineTo(606.57f, 55.77f)
curveTo(606.4f, 54.41f, 605.8f, 53.36f, 604.78f, 52.62f)
curveTo(603.76f, 51.89f, 602.47f, 51.56f, 600.89f, 51.63f)
curveTo(599.9f, 51.68f, 599.02f, 51.87f, 598.25f, 52.21f)
curveTo(597.5f, 52.54f, 596.91f, 52.98f, 596.5f, 53.53f)
curveTo(596.09f, 54.07f, 595.91f, 54.69f, 595.94f, 55.38f)
curveTo(595.97f, 55.99f, 596.18f, 56.5f, 596.57f, 56.93f)
curveTo(596.96f, 57.34f, 597.56f, 57.69f, 598.35f, 57.97f)
curveTo(599.15f, 58.26f, 600.19f, 58.5f, 601.45f, 58.69f)
lineTo(604.38f, 59.12f)
curveTo(606.23f, 59.4f, 607.83f, 59.79f, 609.17f, 60.29f)
curveTo(610.52f, 60.77f, 611.64f, 61.37f, 612.52f, 62.1f)
curveTo(613.41f, 62.83f, 614.08f, 63.69f, 614.53f, 64.69f)
curveTo(614.99f, 65.67f, 615.25f, 66.8f, 615.32f, 68.07f)
curveTo(615.42f, 70.28f, 614.98f, 72.21f, 613.98f, 73.84f)
curveTo(612.97f, 75.45f, 611.48f, 76.73f, 609.5f, 77.67f)
curveTo(607.52f, 78.61f, 605.11f, 79.15f, 602.28f, 79.29f)
close()
}
path(fill = SolidColor(MaterialTheme.colorScheme.surfaceContainerHighest)) {
moveTo(697.94f, 336.99f)
curveTo(698.02f, 338.48f, 698.01f, 339.95f, 697.92f, 341.39f)
lineTo(18.68f, 376.62f)
curveTo(18.44f, 375.19f, 18.28f, 373.73f, 18.2f, 372.25f)
lineTo(6.3f, 142.67f)
lineTo(686.03f, 107.41f)
lineTo(697.94f, 336.99f)
close()
}
path(fill = SolidColor(MaterialTheme.colorScheme.onSurface)) {
moveTo(61.89f, 291.63f)
curveTo(60.93f, 291.68f, 60.22f, 291.36f, 59.77f, 290.66f)
curveTo(59.31f, 289.96f, 59.09f, 289.16f, 59.1f, 288.26f)
lineTo(62.49f, 224.9f)
curveTo(62.56f, 224.05f, 62.77f, 223.35f, 63.1f, 222.79f)
curveTo(63.49f, 222.23f, 64.25f, 221.92f, 65.39f, 221.86f)
curveTo(73.06f, 221.46f, 79.51f, 221.7f, 84.72f, 222.57f)
curveTo(89.93f, 223.44f, 93.83f, 225.1f, 96.43f, 227.55f)
curveTo(99.07f, 229.94f, 100.33f, 233.3f, 100.19f, 237.63f)
curveTo(100.1f, 240.46f, 99.13f, 243.13f, 97.27f, 245.63f)
curveTo(95.42f, 248.07f, 92.83f, 250.24f, 89.5f, 252.16f)
curveTo(86.23f, 254.07f, 82.38f, 255.62f, 77.93f, 256.82f)
curveTo(73.55f, 258f, 68.75f, 258.73f, 63.53f, 259f)
lineTo(63.65f, 254.31f)
curveTo(69.52f, 254.01f, 74.76f, 253.04f, 79.37f, 251.42f)
curveTo(84.03f, 249.74f, 87.73f, 247.68f, 90.49f, 245.26f)
curveTo(93.25f, 242.77f, 94.7f, 240.14f, 94.86f, 237.37f)
curveTo(95.02f, 234.6f, 94.09f, 232.39f, 92.08f, 230.75f)
curveTo(90.14f, 229.11f, 87.13f, 227.94f, 83.07f, 227.25f)
curveTo(79.01f, 226.56f, 73.89f, 226.35f, 67.71f, 226.61f)
lineTo(64.5f, 288.16f)
curveTo(64.43f, 288.94f, 64.25f, 289.7f, 63.99f, 290.44f)
curveTo(63.79f, 291.17f, 63.09f, 291.57f, 61.89f, 291.63f)
close()
moveTo(94.88f, 289.92f)
curveTo(94.46f, 289.94f, 93.92f, 289.82f, 93.24f, 289.55f)
curveTo(92.62f, 289.22f, 92.03f, 288.71f, 91.45f, 288.02f)
lineTo(64.42f, 256.98f)
lineTo(70.59f, 255.93f)
lineTo(95.69f, 284.56f)
curveTo(96.39f, 285.3f, 96.81f, 286f, 96.97f, 286.66f)
curveTo(97.18f, 287.25f, 97.23f, 287.75f, 97.14f, 288.18f)
curveTo(97.1f, 288.6f, 96.85f, 289.01f, 96.39f, 289.39f)
curveTo(95.92f, 289.71f, 95.42f, 289.89f, 94.88f, 289.92f)
close()
moveTo(116.69f, 288.88f)
curveTo(114.35f, 289f, 112.31f, 288.56f, 110.58f, 287.57f)
curveTo(108.9f, 286.58f, 107.51f, 285.21f, 106.4f, 283.46f)
curveTo(105.35f, 281.71f, 104.58f, 279.74f, 104.11f, 277.54f)
curveTo(103.63f, 275.28f, 103.45f, 272.98f, 103.57f, 270.63f)
curveTo(103.84f, 266.47f, 104.64f, 262.94f, 106f, 260.05f)
curveTo(107.41f, 257.15f, 109.22f, 254.92f, 111.42f, 253.37f)
curveTo(113.62f, 251.75f, 116.04f, 250.87f, 118.67f, 250.74f)
curveTo(120.41f, 250.65f, 122.05f, 250.92f, 123.58f, 251.56f)
curveTo(125.18f, 252.14f, 126.48f, 252.98f, 127.5f, 254.06f)
curveTo(128.51f, 255.09f, 129.06f, 256.27f, 129.13f, 257.58f)
curveTo(129.2f, 258.96f, 128.59f, 260.53f, 127.29f, 262.28f)
curveTo(126.06f, 263.96f, 124.41f, 265.7f, 122.34f, 267.49f)
curveTo(120.27f, 269.28f, 118.04f, 271.05f, 115.67f, 272.8f)
curveTo(113.36f, 274.48f, 111.15f, 276.06f, 109.07f, 277.55f)
lineTo(108.17f, 272.37f)
curveTo(109.73f, 271.27f, 111.41f, 270.04f, 113.21f, 268.69f)
curveTo(115.06f, 267.33f, 116.79f, 265.98f, 118.4f, 264.63f)
curveTo(120.01f, 263.23f, 121.3f, 261.99f, 122.27f, 260.92f)
curveTo(123.29f, 259.78f, 123.79f, 258.91f, 123.75f, 258.32f)
curveTo(123.72f, 257.65f, 123.3f, 257.05f, 122.49f, 256.49f)
curveTo(121.68f, 255.87f, 120.43f, 255.6f, 118.75f, 255.69f)
curveTo(116.17f, 255.82f, 113.96f, 257.2f, 112.11f, 259.82f)
curveTo(110.27f, 262.44f, 109.22f, 266.04f, 108.98f, 270.62f)
curveTo(108.86f, 272.97f, 109.04f, 275.18f, 109.5f, 277.26f)
curveTo(110.03f, 279.34f, 110.9f, 281.01f, 112.11f, 282.27f)
curveTo(113.37f, 283.52f, 115f, 284.1f, 116.97f, 283.99f)
curveTo(118.35f, 283.92f, 119.7f, 283.34f, 121.03f, 282.25f)
curveTo(122.35f, 281.1f, 123.44f, 279.54f, 124.3f, 277.58f)
curveTo(124.57f, 277.02f, 125.04f, 276.64f, 125.68f, 276.42f)
curveTo(126.39f, 276.2f, 127.09f, 276.29f, 127.77f, 276.67f)
curveTo(128.45f, 277f, 128.9f, 277.49f, 129.11f, 278.14f)
curveTo(129.32f, 278.79f, 129.29f, 279.39f, 129.02f, 279.95f)
curveTo(127.83f, 282.41f, 126.22f, 284.48f, 124.21f, 286.14f)
curveTo(122.19f, 287.81f, 119.68f, 288.72f, 116.69f, 288.88f)
close()
moveTo(143.9f, 285.12f)
lineTo(136.1f, 254.79f)
curveTo(135.79f, 253.36f, 135.85f, 252.25f, 136.29f, 251.45f)
curveTo(136.73f, 250.64f, 137.43f, 250.21f, 138.39f, 250.16f)
curveTo(138.93f, 250.14f, 139.45f, 250.32f, 139.95f, 250.71f)
curveTo(140.45f, 251.05f, 140.81f, 251.6f, 141.03f, 252.37f)
lineTo(147.4f, 279.62f)
lineTo(146.49f, 279.4f)
lineTo(157.12f, 251.54f)
curveTo(157.55f, 250.61f, 158f, 249.99f, 158.46f, 249.66f)
curveTo(158.93f, 249.28f, 159.43f, 249.07f, 159.96f, 249.04f)
curveTo(160.62f, 249.01f, 161.17f, 249.16f, 161.61f, 249.5f)
curveTo(162.11f, 249.84f, 162.43f, 250.33f, 162.59f, 250.98f)
curveTo(162.74f, 251.63f, 162.63f, 252.42f, 162.26f, 253.34f)
lineTo(149.57f, 285.01f)
curveTo(149.2f, 285.87f, 148.77f, 286.46f, 148.31f, 286.79f)
curveTo(147.84f, 287.05f, 147.28f, 287.2f, 146.62f, 287.23f)
curveTo(146.02f, 287.27f, 145.45f, 287.15f, 144.89f, 286.87f)
curveTo(144.39f, 286.54f, 144.06f, 285.96f, 143.9f, 285.12f)
close()
moveTo(180.16f, 285.59f)
curveTo(177.04f, 285.75f, 174.48f, 284.95f, 172.46f, 283.19f)
curveTo(170.51f, 281.43f, 169.07f, 279.13f, 168.14f, 276.29f)
curveTo(167.27f, 273.45f, 166.91f, 270.47f, 167.04f, 267.34f)
curveTo(167.38f, 261.13f, 169f, 256.33f, 171.88f, 252.93f)
curveTo(174.77f, 249.48f, 178.19f, 247.65f, 182.15f, 247.44f)
curveTo(185.26f, 247.28f, 187.8f, 248.08f, 189.75f, 249.84f)
curveTo(191.77f, 251.6f, 193.21f, 253.93f, 194.08f, 256.83f)
curveTo(195.01f, 259.67f, 195.38f, 262.68f, 195.18f, 265.88f)
curveTo(195.04f, 268.89f, 194.38f, 271.9f, 193.22f, 274.9f)
curveTo(192.11f, 277.85f, 190.46f, 280.33f, 188.29f, 282.37f)
curveTo(186.16f, 284.34f, 183.46f, 285.42f, 180.16f, 285.59f)
close()
moveTo(180.45f, 280.7f)
curveTo(181.88f, 280.63f, 183.29f, 279.98f, 184.67f, 278.77f)
curveTo(186.05f, 277.5f, 187.19f, 275.79f, 188.1f, 273.64f)
curveTo(189.07f, 271.42f, 189.63f, 268.87f, 189.78f, 265.98f)
curveTo(189.83f, 264.71f, 189.76f, 263.3f, 189.56f, 261.75f)
curveTo(189.42f, 260.2f, 189.07f, 258.68f, 188.51f, 257.21f)
curveTo(187.96f, 255.74f, 187.17f, 254.54f, 186.16f, 253.63f)
curveTo(185.15f, 252.73f, 183.84f, 252.31f, 182.22f, 252.4f)
curveTo(179.65f, 252.53f, 177.43f, 253.91f, 175.59f, 256.53f)
curveTo(173.74f, 259.15f, 172.7f, 262.75f, 172.45f, 267.33f)
curveTo(172.33f, 269.68f, 172.51f, 271.89f, 172.98f, 273.97f)
curveTo(173.51f, 276.05f, 174.37f, 277.71f, 175.58f, 278.97f)
curveTo(176.85f, 280.23f, 178.47f, 280.81f, 180.45f, 280.7f)
close()
moveTo(206.54f, 284.13f)
curveTo(205.88f, 284.16f, 205.3f, 283.95f, 204.79f, 283.5f)
curveTo(204.29f, 282.98f, 204.04f, 282.3f, 204.06f, 281.46f)
lineTo(207.59f, 217.46f)
curveTo(207.66f, 216.55f, 207.89f, 215.82f, 208.28f, 215.26f)
curveTo(208.74f, 214.7f, 209.35f, 214.39f, 210.13f, 214.35f)
curveTo(210.97f, 214.31f, 211.67f, 214.51f, 212.24f, 214.96f)
curveTo(212.8f, 215.36f, 213.05f, 216.13f, 212.99f, 217.27f)
lineTo(209.45f, 281.18f)
curveTo(209.38f, 282.21f, 209.09f, 282.94f, 208.57f, 283.39f)
curveTo(208.05f, 283.84f, 207.38f, 284.08f, 206.54f, 284.13f)
close()
moveTo(229.32f, 282.95f)
curveTo(228.66f, 282.98f, 228.02f, 282.8f, 227.4f, 282.42f)
curveTo(226.77f, 281.97f, 226.47f, 281.32f, 226.48f, 280.48f)
lineTo(229.61f, 224.34f)
curveTo(229.69f, 223.62f, 230f, 223.06f, 230.52f, 222.67f)
curveTo(231.03f, 222.22f, 231.59f, 221.98f, 232.19f, 221.95f)
curveTo(232.91f, 221.91f, 233.55f, 222.12f, 234.12f, 222.57f)
curveTo(234.74f, 223.02f, 235.02f, 223.73f, 234.95f, 224.69f)
lineTo(231.89f, 280.38f)
curveTo(231.81f, 281.22f, 231.51f, 281.87f, 231f, 282.32f)
curveTo(230.54f, 282.7f, 229.98f, 282.91f, 229.32f, 282.95f)
close()
moveTo(221.16f, 250.74f)
curveTo(220.08f, 250.79f, 219.29f, 250.6f, 218.78f, 250.14f)
curveTo(218.27f, 249.63f, 218f, 249.04f, 217.97f, 248.38f)
curveTo(217.93f, 247.72f, 218.09f, 247.17f, 218.42f, 246.73f)
curveTo(218.76f, 246.24f, 219.47f, 245.96f, 220.54f, 245.9f)
lineTo(242.21f, 244.78f)
curveTo(243.29f, 244.72f, 244.05f, 244.92f, 244.49f, 245.38f)
curveTo(244.94f, 245.78f, 245.17f, 246.31f, 245.21f, 246.97f)
curveTo(245.24f, 247.63f, 245.12f, 248.23f, 244.85f, 248.79f)
curveTo(244.58f, 249.28f, 243.9f, 249.56f, 242.82f, 249.62f)
lineTo(221.16f, 250.74f)
close()
moveTo(272.4f, 281.16f)
curveTo(268.57f, 281.36f, 265.18f, 280.45f, 262.26f, 278.44f)
curveTo(259.33f, 276.43f, 257.08f, 273.6f, 255.51f, 269.96f)
curveTo(253.93f, 266.26f, 253.26f, 262.02f, 253.49f, 257.26f)
lineTo(255.73f, 215.14f)
curveTo(255.8f, 214.3f, 256.07f, 213.56f, 256.51f, 212.94f)
curveTo(257.02f, 212.25f, 257.69f, 211.89f, 258.53f, 211.84f)
curveTo(259.37f, 211.8f, 260.02f, 212.13f, 260.47f, 212.82f)
curveTo(260.99f, 213.46f, 261.21f, 214.2f, 261.13f, 215.04f)
lineTo(258.91f, 257.34f)
curveTo(258.68f, 261.08f, 259.09f, 264.39f, 260.14f, 267.29f)
curveTo(261.26f, 270.17f, 262.84f, 272.43f, 264.91f, 274.07f)
curveTo(267.04f, 275.64f, 269.48f, 276.36f, 272.23f, 276.21f)
curveTo(275.23f, 276.06f, 277.97f, 275.04f, 280.46f, 273.17f)
curveTo(282.94f, 271.24f, 284.94f, 268.67f, 286.46f, 265.47f)
curveTo(288.04f, 262.26f, 288.93f, 258.7f, 289.15f, 254.78f)
lineTo(291.47f, 212.66f)
curveTo(291.5f, 212f, 291.68f, 211.42f, 292.01f, 210.92f)
curveTo(292.4f, 210.36f, 293.08f, 210.05f, 294.04f, 210f)
curveTo(295f, 209.95f, 295.7f, 210.19f, 296.15f, 210.7f)
curveTo(296.65f, 211.16f, 296.87f, 211.81f, 296.79f, 212.65f)
lineTo(294.64f, 254.5f)
curveTo(294.41f, 259.38f, 293.25f, 263.8f, 291.18f, 267.75f)
curveTo(289.16f, 271.7f, 286.53f, 274.87f, 283.29f, 277.26f)
curveTo(280.05f, 279.65f, 276.42f, 280.95f, 272.4f, 281.16f)
close()
moveTo(318.53f, 278.41f)
curveTo(315.95f, 278.54f, 313.65f, 278.27f, 311.64f, 277.6f)
curveTo(309.62f, 276.92f, 307.89f, 275.99f, 306.44f, 274.8f)
curveTo(305.56f, 274.06f, 304.92f, 273.32f, 304.52f, 272.55f)
curveTo(304.12f, 271.73f, 304.2f, 270.98f, 304.77f, 270.29f)
curveTo(305.39f, 269.48f, 306f, 269.05f, 306.6f, 269.02f)
curveTo(307.25f, 268.93f, 307.96f, 269.19f, 308.71f, 269.81f)
curveTo(309.83f, 270.66f, 311.23f, 271.46f, 312.89f, 272.21f)
curveTo(314.55f, 272.91f, 316.4f, 273.2f, 318.43f, 273.1f)
curveTo(320.11f, 273.01f, 321.38f, 272.55f, 322.24f, 271.73f)
curveTo(323.1f, 270.84f, 323.49f, 269.71f, 323.42f, 268.33f)
curveTo(323.37f, 267.43f, 323.05f, 266.61f, 322.48f, 265.86f)
curveTo(321.96f, 265.1f, 320.98f, 264.25f, 319.55f, 263.3f)
curveTo(318.12f, 262.36f, 315.98f, 261.14f, 313.14f, 259.67f)
curveTo(310.86f, 258.46f, 309.11f, 257.17f, 307.89f, 255.79f)
curveTo(306.67f, 254.36f, 306.01f, 252.53f, 305.89f, 250.31f)
curveTo(305.75f, 247.55f, 306.66f, 245.28f, 308.61f, 243.5f)
curveTo(310.61f, 241.65f, 313.39f, 240.64f, 316.92f, 240.45f)
curveTo(318.36f, 240.38f, 319.93f, 240.54f, 321.63f, 240.93f)
curveTo(323.34f, 241.32f, 325.12f, 242.04f, 326.97f, 243.09f)
curveTo(328.02f, 243.63f, 328.78f, 244.4f, 329.26f, 245.4f)
curveTo(329.73f, 246.34f, 329.74f, 247.18f, 329.3f, 247.92f)
curveTo(328.92f, 248.66f, 328.33f, 249.03f, 327.55f, 249.01f)
curveTo(326.77f, 248.99f, 325.94f, 248.7f, 325.07f, 248.14f)
curveTo(324.14f, 247.53f, 322.94f, 246.99f, 321.47f, 246.53f)
curveTo(320.06f, 246f, 318.4f, 245.79f, 316.48f, 245.88f)
curveTo(314.74f, 245.98f, 313.41f, 246.4f, 312.49f, 247.17f)
curveTo(311.57f, 247.94f, 311.14f, 248.93f, 311.2f, 250.12f)
curveTo(311.26f, 251.26f, 311.7f, 252.2f, 312.52f, 252.94f)
curveTo(313.34f, 253.62f, 314.61f, 254.4f, 316.34f, 255.27f)
curveTo(319.67f, 257.02f, 322.21f, 258.51f, 323.96f, 259.74f)
curveTo(325.77f, 260.97f, 327f, 262.2f, 327.67f, 263.42f)
curveTo(328.33f, 264.65f, 328.71f, 266.13f, 328.8f, 267.87f)
curveTo(328.9f, 269.91f, 328.55f, 271.7f, 327.73f, 273.24f)
curveTo(326.9f, 274.79f, 325.71f, 276.02f, 324.13f, 276.95f)
curveTo(322.61f, 277.81f, 320.75f, 278.29f, 318.53f, 278.41f)
close()
moveTo(349.77f, 276.79f)
curveTo(347.43f, 276.91f, 345.4f, 276.47f, 343.66f, 275.48f)
curveTo(341.99f, 274.49f, 340.6f, 273.12f, 339.48f, 271.37f)
curveTo(338.43f, 269.63f, 337.67f, 267.65f, 337.19f, 265.45f)
curveTo(336.72f, 263.19f, 336.54f, 260.89f, 336.65f, 258.54f)
curveTo(336.92f, 254.38f, 337.73f, 250.85f, 339.08f, 247.96f)
curveTo(340.49f, 245.06f, 342.3f, 242.83f, 344.5f, 241.28f)
curveTo(346.7f, 239.66f, 349.12f, 238.78f, 351.76f, 238.65f)
curveTo(353.5f, 238.56f, 355.13f, 238.83f, 356.67f, 239.47f)
curveTo(358.26f, 240.05f, 359.57f, 240.89f, 360.58f, 241.98f)
curveTo(361.6f, 243f, 362.14f, 244.18f, 362.21f, 245.5f)
curveTo(362.28f, 246.87f, 361.67f, 248.44f, 360.38f, 250.19f)
curveTo(359.14f, 251.87f, 357.49f, 253.61f, 355.42f, 255.4f)
curveTo(353.35f, 257.19f, 351.13f, 258.96f, 348.76f, 260.71f)
curveTo(346.44f, 262.39f, 344.24f, 263.98f, 342.15f, 265.46f)
lineTo(341.25f, 260.28f)
curveTo(342.82f, 259.18f, 344.5f, 257.95f, 346.29f, 256.6f)
curveTo(348.14f, 255.24f, 349.87f, 253.89f, 351.49f, 252.54f)
curveTo(353.1f, 251.14f, 354.39f, 249.9f, 355.35f, 248.83f)
curveTo(356.37f, 247.69f, 356.87f, 246.82f, 356.84f, 246.23f)
curveTo(356.8f, 245.57f, 356.38f, 244.96f, 355.57f, 244.4f)
curveTo(354.76f, 243.78f, 353.51f, 243.51f, 351.83f, 243.6f)
curveTo(349.26f, 243.73f, 347.05f, 245.11f, 345.2f, 247.73f)
curveTo(343.35f, 250.35f, 342.31f, 253.95f, 342.06f, 258.53f)
curveTo(341.94f, 260.88f, 342.12f, 263.09f, 342.59f, 265.17f)
curveTo(343.12f, 267.25f, 343.98f, 268.92f, 345.19f, 270.17f)
curveTo(346.46f, 271.43f, 348.08f, 272.01f, 350.06f, 271.91f)
curveTo(351.44f, 271.83f, 352.79f, 271.25f, 354.11f, 270.16f)
curveTo(355.44f, 269.01f, 356.53f, 267.45f, 357.39f, 265.49f)
curveTo(357.66f, 264.93f, 358.12f, 264.55f, 358.77f, 264.33f)
curveTo(359.48f, 264.12f, 360.17f, 264.2f, 360.86f, 264.59f)
curveTo(361.53f, 264.91f, 361.98f, 265.4f, 362.19f, 266.05f)
curveTo(362.41f, 266.7f, 362.38f, 267.3f, 362.11f, 267.86f)
curveTo(360.91f, 270.32f, 359.31f, 272.39f, 357.29f, 274.05f)
curveTo(355.27f, 275.72f, 352.77f, 276.63f, 349.77f, 276.79f)
close()
moveTo(373.14f, 275.49f)
curveTo(372.42f, 275.52f, 371.78f, 275.32f, 371.22f, 274.86f)
curveTo(370.71f, 274.41f, 370.47f, 273.7f, 370.48f, 272.74f)
lineTo(372.16f, 240.92f)
curveTo(372.23f, 239.96f, 372.55f, 239.22f, 373.13f, 238.71f)
curveTo(373.76f, 238.2f, 374.41f, 237.92f, 375.07f, 237.89f)
curveTo(375.73f, 237.85f, 376.31f, 238.09f, 376.82f, 238.61f)
curveTo(377.39f, 239.12f, 377.64f, 239.92f, 377.57f, 241f)
lineTo(375.87f, 272.46f)
curveTo(375.8f, 273.42f, 375.48f, 274.16f, 374.9f, 274.67f)
curveTo(374.39f, 275.18f, 373.8f, 275.45f, 373.14f, 275.49f)
close()
moveTo(395.74f, 247.18f)
curveTo(395.16f, 247.57f, 394.48f, 247.7f, 393.69f, 247.56f)
curveTo(392.9f, 247.42f, 392.43f, 247.05f, 392.28f, 246.46f)
curveTo(391.98f, 245.27f, 391.56f, 244.24f, 391.04f, 243.37f)
curveTo(390.51f, 242.44f, 389.76f, 241.99f, 388.8f, 242.04f)
curveTo(387.37f, 242.12f, 385.93f, 242.88f, 384.51f, 244.34f)
curveTo(383.08f, 245.8f, 381.58f, 248.07f, 379.99f, 251.15f)
curveTo(378.41f, 254.18f, 376.63f, 258.21f, 374.67f, 263.24f)
lineTo(375.05f, 251.41f)
curveTo(377.03f, 246.68f, 379.1f, 243.09f, 381.25f, 240.63f)
curveTo(383.41f, 238.18f, 385.95f, 236.87f, 388.89f, 236.72f)
curveTo(390.99f, 236.61f, 392.73f, 237.24f, 394.13f, 238.61f)
curveTo(395.58f, 239.92f, 396.59f, 241.55f, 397.17f, 243.5f)
curveTo(397.47f, 244.51f, 397.45f, 245.29f, 397.11f, 245.85f)
curveTo(396.78f, 246.41f, 396.33f, 246.85f, 395.74f, 247.18f)
close()
moveTo(423.98f, 272.85f)
curveTo(422.66f, 272.92f, 421.5f, 272.56f, 420.5f, 271.77f)
curveTo(419.56f, 270.98f, 419.1f, 269.74f, 419.14f, 268.05f)
lineTo(422.03f, 216.16f)
curveTo(422.14f, 214.71f, 422.65f, 213.67f, 423.58f, 213.02f)
curveTo(424.51f, 212.31f, 425.63f, 211.92f, 426.95f, 211.85f)
curveTo(428.39f, 211.78f, 429.67f, 212.13f, 430.79f, 212.91f)
curveTo(431.97f, 213.69f, 432.51f, 214.87f, 432.41f, 216.43f)
lineTo(429.7f, 268.41f)
curveTo(429.6f, 269.91f, 428.93f, 271.03f, 427.71f, 271.75f)
curveTo(426.54f, 272.42f, 425.3f, 272.78f, 423.98f, 272.85f)
close()
moveTo(450.5f, 271.47f)
curveTo(449.06f, 271.55f, 447.73f, 271.26f, 446.49f, 270.6f)
curveTo(445.31f, 269.88f, 444.79f, 268.58f, 444.94f, 266.71f)
lineTo(447.65f, 214.74f)
curveTo(447.75f, 213.3f, 448.39f, 212.24f, 449.56f, 211.58f)
curveTo(450.73f, 210.92f, 451.94f, 210.55f, 453.2f, 210.49f)
curveTo(454.46f, 210.43f, 455.61f, 210.76f, 456.67f, 211.48f)
curveTo(457.79f, 212.15f, 458.3f, 213.35f, 458.21f, 215.1f)
lineTo(455.41f, 267.07f)
curveTo(455.37f, 268.58f, 454.86f, 269.68f, 453.87f, 270.4f)
curveTo(452.94f, 271.05f, 451.82f, 271.4f, 450.5f, 271.47f)
close()
moveTo(411.29f, 259.27f)
curveTo(409.79f, 259.34f, 408.48f, 258.96f, 407.35f, 258.12f)
curveTo(406.22f, 257.21f, 405.57f, 256.14f, 405.38f, 254.88f)
curveTo(405.26f, 253.63f, 405.62f, 252.56f, 406.48f, 251.67f)
curveTo(407.39f, 250.78f, 408.63f, 250.3f, 410.19f, 250.22f)
lineTo(464.85f, 247.38f)
curveTo(466.46f, 247.3f, 467.8f, 247.65f, 468.87f, 248.44f)
curveTo(469.93f, 249.22f, 470.52f, 250.24f, 470.65f, 251.5f)
curveTo(470.77f, 252.76f, 470.41f, 253.88f, 469.56f, 254.89f)
curveTo(468.77f, 255.83f, 467.59f, 256.35f, 466.04f, 256.43f)
lineTo(411.29f, 259.27f)
close()
moveTo(412.57f, 235.22f)
curveTo(410.95f, 235.31f, 409.61f, 234.96f, 408.55f, 234.17f)
curveTo(407.48f, 233.32f, 406.85f, 232.27f, 406.67f, 231.02f)
curveTo(406.49f, 229.83f, 406.82f, 228.76f, 407.67f, 227.81f)
curveTo(408.58f, 226.8f, 409.85f, 226.26f, 411.46f, 226.18f)
lineTo(466.03f, 223.35f)
curveTo(467.59f, 223.26f, 468.93f, 223.68f, 470.06f, 224.58f)
curveTo(471.19f, 225.42f, 471.84f, 226.44f, 472.02f, 227.63f)
curveTo(472.21f, 228.88f, 471.82f, 229.99f, 470.84f, 230.94f)
curveTo(469.93f, 231.83f, 468.69f, 232.31f, 467.13f, 232.39f)
lineTo(412.57f, 235.22f)
close()
moveTo(489.41f, 269.46f)
curveTo(487.61f, 269.55f, 486.23f, 269.08f, 485.28f, 268.05f)
curveTo(484.38f, 267.01f, 484.01f, 265.53f, 484.15f, 263.6f)
lineTo(486.71f, 213.89f)
curveTo(486.81f, 212.44f, 487.32f, 211.21f, 488.23f, 210.21f)
curveTo(489.19f, 209.13f, 490.49f, 208.56f, 492.1f, 208.47f)
curveTo(494.02f, 208.37f, 495.4f, 208.87f, 496.24f, 209.97f)
curveTo(497.08f, 211.07f, 497.47f, 212.37f, 497.43f, 213.87f)
lineTo(494.88f, 263.67f)
curveTo(494.79f, 265.48f, 494.23f, 266.89f, 493.2f, 267.91f)
curveTo(492.23f, 268.86f, 490.97f, 269.38f, 489.41f, 269.46f)
close()
moveTo(543.95f, 261.94f)
curveTo(544.02f, 263.32f, 543.63f, 264.48f, 542.78f, 265.43f)
curveTo(541.98f, 266.31f, 540.8f, 266.79f, 539.24f, 266.87f)
lineTo(511.83f, 268.29f)
curveTo(510.45f, 268.36f, 509.35f, 268f, 508.52f, 267.2f)
curveTo(507.7f, 266.4f, 507.29f, 265.34f, 507.28f, 264.02f)
curveTo(507.33f, 262.7f, 507.86f, 261.32f, 508.86f, 259.88f)
curveTo(510.88f, 257.07f, 512.84f, 254.36f, 514.75f, 251.74f)
curveTo(516.66f, 249.11f, 518.43f, 246.68f, 520.05f, 244.43f)
curveTo(521.74f, 242.18f, 523.26f, 240.15f, 524.6f, 238.34f)
curveTo(526.01f, 236.46f, 527.19f, 234.87f, 528.14f, 233.55f)
curveTo(529.16f, 232.24f, 529.89f, 231.27f, 530.34f, 230.65f)
curveTo(531.4f, 229.09f, 532.34f, 227.6f, 533.17f, 226.17f)
curveTo(534.05f, 224.68f, 534.73f, 223.3f, 535.21f, 222.01f)
curveTo(535.74f, 220.66f, 535.98f, 219.54f, 535.93f, 218.64f)
curveTo(535.88f, 217.68f, 535.36f, 216.96f, 534.38f, 216.46f)
curveTo(533.45f, 215.97f, 532.18f, 215.77f, 530.56f, 215.85f)
curveTo(528.58f, 215.95f, 526.47f, 216.45f, 524.24f, 217.35f)
curveTo(522f, 218.19f, 520.08f, 219.43f, 518.48f, 221.07f)
curveTo(517.05f, 222.53f, 515.53f, 223.21f, 513.9f, 223.12f)
curveTo(512.33f, 222.96f, 511.16f, 222.45f, 510.39f, 221.59f)
curveTo(509.62f, 220.6f, 509.17f, 219.51f, 509.05f, 218.32f)
curveTo(508.99f, 217.12f, 509.64f, 215.82f, 511.02f, 214.43f)
curveTo(512.39f, 213.04f, 514.15f, 211.77f, 516.32f, 210.64f)
curveTo(518.54f, 209.44f, 520.92f, 208.48f, 523.47f, 207.75f)
curveTo(526.01f, 207.01f, 528.46f, 206.59f, 530.79f, 206.46f)
curveTo(533.97f, 206.3f, 536.69f, 206.67f, 538.96f, 207.57f)
curveTo(541.29f, 208.48f, 543.11f, 209.85f, 544.41f, 211.71f)
curveTo(545.76f, 213.5f, 546.51f, 215.69f, 546.64f, 218.26f)
curveTo(546.77f, 220.78f, 546.08f, 223.7f, 544.57f, 227.02f)
curveTo(543.06f, 230.29f, 540.7f, 234.13f, 537.51f, 238.57f)
curveTo(536.83f, 239.5f, 535.91f, 240.75f, 534.73f, 242.32f)
curveTo(533.6f, 243.82f, 532.28f, 245.57f, 530.76f, 247.57f)
curveTo(529.24f, 249.57f, 527.64f, 251.73f, 525.96f, 254.04f)
curveTo(524.28f, 256.35f, 522.57f, 258.69f, 520.83f, 261.07f)
lineTo(519.53f, 258.7f)
lineTo(538.05f, 257.74f)
curveTo(539.85f, 257.64f, 541.25f, 257.96f, 542.24f, 258.69f)
curveTo(543.3f, 259.42f, 543.87f, 260.5f, 543.95f, 261.94f)
close()
moveTo(554.97f, 254.79f)
curveTo(555.74f, 253.55f, 556.73f, 252.83f, 557.92f, 252.65f)
curveTo(559.11f, 252.41f, 560.51f, 252.82f, 562.13f, 253.88f)
curveTo(563.12f, 254.49f, 564.23f, 254.97f, 565.45f, 255.33f)
curveTo(566.67f, 255.68f, 568.51f, 255.8f, 570.97f, 255.67f)
curveTo(575.22f, 255.45f, 578.42f, 254.59f, 580.57f, 253.1f)
curveTo(582.71f, 251.61f, 583.84f, 249.48f, 583.93f, 246.71f)
curveTo(584.05f, 244.3f, 583.65f, 242.42f, 582.74f, 241.09f)
curveTo(581.83f, 239.75f, 580.55f, 238.8f, 578.9f, 238.22f)
curveTo(577.24f, 237.65f, 575.36f, 237.32f, 573.26f, 237.25f)
curveTo(571.21f, 237.18f, 569.05f, 237.2f, 566.77f, 237.32f)
curveTo(565.33f, 237.39f, 564.14f, 237.01f, 563.19f, 236.15f)
curveTo(562.31f, 235.3f, 561.83f, 234.27f, 561.77f, 233.07f)
curveTo(561.69f, 231.51f, 562.17f, 230.29f, 563.2f, 229.39f)
curveTo(564.24f, 228.44f, 565.38f, 227.93f, 566.64f, 227.86f)
curveTo(570.78f, 227.65f, 574f, 227.24f, 576.31f, 226.64f)
curveTo(578.62f, 225.98f, 580.26f, 225.08f, 581.22f, 223.95f)
curveTo(582.24f, 222.76f, 582.79f, 221.26f, 582.88f, 219.45f)
curveTo(582.99f, 218.12f, 582.75f, 217.02f, 582.17f, 216.15f)
curveTo(581.64f, 215.28f, 580.77f, 214.66f, 579.55f, 214.3f)
curveTo(578.38f, 213.88f, 576.87f, 213.72f, 575.02f, 213.82f)
curveTo(572.8f, 213.93f, 570.92f, 214.27f, 569.39f, 214.83f)
curveTo(567.91f, 215.33f, 566.68f, 215.87f, 565.69f, 216.46f)
curveTo(564.46f, 217.19f, 563.14f, 217.65f, 561.7f, 217.84f)
curveTo(560.33f, 218.03f, 559.2f, 217.64f, 558.31f, 216.67f)
curveTo(557.47f, 215.57f, 557.1f, 214.35f, 557.22f, 213.03f)
curveTo(557.33f, 211.7f, 558.07f, 210.43f, 559.45f, 209.21f)
curveTo(560.54f, 208.2f, 562.32f, 207.17f, 564.79f, 206.14f)
curveTo(567.26f, 205.05f, 570.53f, 204.4f, 574.61f, 204.19f)
curveTo(578.98f, 203.97f, 582.61f, 204.41f, 585.49f, 205.52f)
curveTo(588.37f, 206.57f, 590.47f, 208.27f, 591.79f, 210.6f)
curveTo(593.18f, 212.93f, 593.78f, 215.94f, 593.61f, 219.61f)
curveTo(593.51f, 222.2f, 592.63f, 224.47f, 590.99f, 226.42f)
curveTo(589.41f, 228.3f, 587.29f, 229.82f, 584.65f, 230.98f)
curveTo(582.07f, 232.14f, 579.16f, 232.95f, 575.94f, 233.42f)
lineTo(576.33f, 230.42f)
curveTo(580.18f, 230.52f, 583.5f, 231.34f, 586.28f, 232.88f)
curveTo(589.06f, 234.42f, 591.18f, 236.41f, 592.63f, 238.86f)
curveTo(594.08f, 241.31f, 594.73f, 243.95f, 594.57f, 246.79f)
curveTo(594.27f, 252.57f, 592.16f, 257.01f, 588.23f, 260.09f)
curveTo(584.31f, 263.18f, 578.54f, 264.92f, 570.93f, 265.32f)
curveTo(567.27f, 265.51f, 564.31f, 265.21f, 562.05f, 264.43f)
curveTo(559.84f, 263.64f, 558.15f, 262.83f, 556.96f, 261.99f)
curveTo(555.46f, 260.86f, 554.59f, 259.67f, 554.34f, 258.43f)
curveTo(554.16f, 257.17f, 554.37f, 255.96f, 554.97f, 254.79f)
close()
moveTo(625.38f, 262.4f)
curveTo(623.7f, 262.49f, 622.44f, 261.95f, 621.6f, 260.8f)
curveTo(620.82f, 259.58f, 620.47f, 258.09f, 620.56f, 256.34f)
lineTo(622.11f, 223.72f)
curveTo(622.15f, 222.16f, 622.69f, 221.02f, 623.74f, 220.3f)
curveTo(624.78f, 219.59f, 626.05f, 219.22f, 627.56f, 219.2f)
curveTo(629f, 219.19f, 630.1f, 219.7f, 630.88f, 220.74f)
curveTo(631.65f, 221.73f, 632.02f, 223f, 631.98f, 224.56f)
lineTo(630.71f, 257.44f)
curveTo(630.61f, 258.95f, 630.13f, 260.14f, 629.27f, 261.03f)
curveTo(628.42f, 261.86f, 627.12f, 262.31f, 625.38f, 262.4f)
close()
moveTo(610.22f, 244.62f)
curveTo(608.54f, 244.71f, 607.13f, 244.27f, 606f, 243.31f)
curveTo(604.93f, 242.28f, 604.41f, 241.11f, 604.47f, 239.78f)
lineTo(606.19f, 206.97f)
curveTo(606.29f, 205.46f, 606.86f, 204.32f, 607.9f, 203.55f)
curveTo(609.01f, 202.77f, 610.22f, 202.35f, 611.53f, 202.28f)
curveTo(612.91f, 202.21f, 614.14f, 202.59f, 615.2f, 203.44f)
curveTo(616.32f, 204.22f, 616.87f, 205.49f, 616.84f, 207.23f)
lineTo(615.19f, 237.96f)
lineTo(612.15f, 234.97f)
lineTo(638.94f, 233.58f)
curveTo(640.5f, 233.5f, 641.72f, 233.88f, 642.6f, 234.74f)
curveTo(643.55f, 235.59f, 644.03f, 236.68f, 644.03f, 238f)
curveTo(644.05f, 239.38f, 643.63f, 240.57f, 642.78f, 241.58f)
curveTo(641.99f, 242.52f, 640.84f, 243.03f, 639.34f, 243.11f)
lineTo(610.22f, 244.62f)
close()
}
path(fill = SolidColor(Color(HL_USERNAME))) {
moveTo(49.21f, 302.37f)
lineToRelative(353.01f, -18.31f)
lineToRelative(0.62f, 11.92f)
lineToRelative(-353.01f, 18.31f)
close()
}
path(fill = SolidColor(Color(HL_TAG))) {
moveTo(482.01f, 279.92f)
lineToRelative(169.77f, -8.81f)
lineToRelative(0.62f, 11.92f)
lineToRelative(-169.77f, 8.81f)
close()
}
}.build()
return _RevoltTagIntro!!
}
@Suppress("ObjectPropertyName")
private var _RevoltTagIntro: ImageVector? = null
@Preview(showBackground = true)
@Composable
fun RevoltTagIntroPreview() {
Image(
imageVector = RevoltTagIntro,
contentDescription = null
)
}

View File

@ -22,12 +22,17 @@ import androidx.webkit.WebViewAssetLoader
import chat.revolt.activities.InviteActivity
import chat.revolt.api.REVOLT_APP
internal fun Color.asHexString(): String {
internal fun Color.asHexString(includeAlphaComponent: Boolean = true): String {
val argb = toArgb()
val alpha = (argb shr 24 and 0xff) / 255.0f
val red = argb shr 16 and 0xff
val green = argb shr 8 and 0xff
val blue = argb and 0xff
if (!includeAlphaComponent) {
return String.format("#%02x%02x%02x", red, green, blue)
}
val alpha = (argb shr 24 and 0xff) / 255.0f
return String.format("#%02x%02x%02x%02x", red, green, blue, (alpha * 255).toInt())
}

View File

@ -1,50 +1,472 @@
package chat.revolt.screens.chat.views
import android.content.Context
import android.widget.Toast
import androidx.activity.compose.BackHandler
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material3.Button
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FloatingActionButtonMenu
import androidx.compose.material3.FloatingActionButtonMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.material3.ToggleFloatingActionButton
import androidx.compose.material3.ToggleFloatingActionButtonDefaults.animateIcon
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.animateFloatingActionButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.isTraversalGroup
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.traversalIndex
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.fromHtml
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.api.internals.FriendRequests
import chat.revolt.api.internals.UserQR
import chat.revolt.api.internals.UserQRContents
import chat.revolt.api.routes.user.friendUser
import chat.revolt.api.routes.user.unfriendUser
import chat.revolt.api.schemas.AutumnResource
import chat.revolt.api.schemas.Metadata
import chat.revolt.api.settings.LoadedSettings
import chat.revolt.callbacks.Action
import chat.revolt.callbacks.ActionChannel
import chat.revolt.components.vectorassets.HL_TAG
import chat.revolt.components.vectorassets.HL_USERNAME
import chat.revolt.components.vectorassets.RevoltTagIntro
import chat.revolt.composables.chat.MemberListItem
import chat.revolt.composables.generic.CountableListHeader
import chat.revolt.composables.generic.UserAvatar
import chat.revolt.internals.extensions.zero
import chat.revolt.markdown.jbm.asHexString
import io.github.g00fy2.quickie.QRResult
import io.github.g00fy2.quickie.ScanQRCode
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
private fun showInvalidClipboardToast(context: Context) {
Toast.makeText(
context,
context.getString(R.string.friends_add_by_tag_sheet_invalid_clipboard),
Toast.LENGTH_SHORT
).show()
}
@OptIn(
ExperimentalMaterial3Api::class,
ExperimentalFoundationApi::class,
ExperimentalMaterial3ExpressiveApi::class
)
@Composable
fun FriendsScreen(topNav: NavController, useDrawer: Boolean, onDrawerClicked: () -> Unit) {
val clipboard = LocalClipboard.current
val context = LocalContext.current
var overflowMenuShown by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
val listState = rememberLazyListState()
val fabVisible by remember { derivedStateOf { listState.firstVisibleItemIndex == 0 } }
var fabMenuExpanded by rememberSaveable { mutableStateOf(false) }
var addByTagSheetVisible by rememberSaveable { mutableStateOf(false) }
var qrResult by rememberSaveable { mutableStateOf<QRResult?>(null) }
val scanQrCodeLauncher = rememberLauncherForActivityResult(ScanQRCode()) { result ->
qrResult = result
}
BackHandler(fabMenuExpanded) { fabMenuExpanded = false }
if (addByTagSheetVisible) {
val addByTagSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
var username by rememberSaveable { mutableStateOf("") }
var tag by rememberSaveable { mutableStateOf("") }
var error by rememberSaveable { mutableStateOf<String?>(null) }
ModalBottomSheet(
onDismissRequest = {
addByTagSheetVisible = false
},
sheetGesturesEnabled = false,
dragHandle = {},
sheetState = addByTagSheetState,
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(
imageVector = RevoltTagIntro,
contentDescription = null,
modifier = Modifier
.fillMaxWidth(0.5f)
)
Text(
text = stringResource(R.string.friends_add_by_tag),
style = MaterialTheme.typography.titleMedium,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Text(
text = AnnotatedString.fromHtml(
stringResource(
R.string.friends_add_by_tag_sheet_description,
"<font color=\"${Color(HL_USERNAME).asHexString(false)}\">",
"<font color=\"${Color(HL_TAG).asHexString(false)}\">",
"</font>",
)
),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current.copy(alpha = 0.7f),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.Bottom
) {
TextField(
value = username,
onValueChange = {
// Cf. https://github.com/revoltchat/backend/blob/aab1734615ac3e09cd447d2c2862ae0f33f5ce5f/crates/delta/src/routes/onboard/complete.rs#L16
if (it.length <= 32 && it.all { char ->
char.isLetterOrDigit() ||
char == '_' || char == '.' || char == '-'
}) {
username = it
}
},
label = {
Text(stringResource(R.string.friends_add_by_tag_sheet_username))
},
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
supportingText = {
Text(
text = error ?: "",
color = MaterialTheme.colorScheme.error
)
},
isError = error != null,
modifier = Modifier.weight(1f),
)
Text("#", modifier = Modifier.padding(bottom = 36.dp))
TextField(
value = tag,
onValueChange = {
// up to 4 characters, only numbers
if (it.length <= 4 && it.all { char -> char.isDigit() }) {
tag = it
}
},
label = {
Text(stringResource(R.string.friends_add_by_tag_sheet_tag))
},
supportingText = {
Text("") // Layout hack
},
modifier = Modifier.width(80.dp),
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
)
)
}
Row(
horizontalArrangement = Arrangement.spacedBy(
8.dp,
Alignment.CenterHorizontally
),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
TextButton(
onClick = {
scope.launch {
val clipboardText =
clipboard.getClipEntry()?.clipData?.getItemAt(0)?.coerceToText(
context
) ?: ""
try {
if (clipboardText.isEmpty()) {
showInvalidClipboardToast(context)
return@launch
}
val parts = clipboardText.toString().replace(" ", "").split("#")
if (parts.size == 2) {
if (parts[0].length > 32 || parts[0].any { char ->
!char.isLetterOrDigit() && char != '_' && char != '.' && char != '-'
}) {
showInvalidClipboardToast(context)
return@launch
}
if (parts[1].length > 4 || parts[1].any { char -> !char.isDigit() }) {
showInvalidClipboardToast(context)
return@launch
}
username = parts[0].trim()
tag = parts[1].trim()
} else {
showInvalidClipboardToast(context)
}
} catch (_: Exception) {
showInvalidClipboardToast(context)
}
}
}
) {
Text(stringResource(R.string.friends_add_by_tag_sheet_paste_from_clipboard))
}
Button(
onClick = {
scope.launch {
if (username.isNotBlank() && tag.isNotBlank()) {
try {
error = null
friendUser("$username#$tag")
addByTagSheetVisible = false
} catch (e: Exception) {
error = e.localizedMessage ?: e.toString()
}
}
}
},
enabled = username.isNotBlank() && tag.isNotBlank()
) {
Text(stringResource(R.string.friends_add_by_tag_sheet_add))
}
}
}
}
}
if (qrResult != null) {
val qrResultSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
var contents by rememberSaveable { mutableStateOf<UserQRContents?>(null) }
LaunchedEffect(qrResult) {
when (qrResult) {
is QRResult.QRUserCanceled -> {
// Silently dismiss ourselves.
qrResult = null
}
is QRResult.QRSuccess -> {
contents =
UserQR.fromUri((qrResult as QRResult.QRSuccess).content.rawValue ?: "")
}
else -> {
contents = null
}
}
}
ModalBottomSheet(
onDismissRequest = {
qrResult = null
contents = null
},
sheetGesturesEnabled = false,
dragHandle = {},
sheetState = qrResultSheetState,
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
when {
qrResult is QRResult.QRMissingPermission -> {
Text(
text = stringResource(R.string.friends_scan_qr_result_sheet_missing_permission_title),
style = MaterialTheme.typography.titleMedium,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Text(
text = stringResource(R.string.friends_scan_qr_result_sheet_missing_permission_description),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current.copy(alpha = 0.7f),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Button(
onClick = {
qrResult = null
contents = null
},
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.ok))
}
}
qrResult is QRResult.QRSuccess && contents != null -> {
Text(
text = stringResource(R.string.friends_scan_qr_result_sheet_success_title),
style = MaterialTheme.typography.titleMedium,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
UserAvatar(
username = contents?.username ?: stringResource(R.string.unknown),
userId = contents?.id ?: "",
allowAnimation = false,
shape = RoundedCornerShape(LoadedSettings.avatarRadius),
size = 128.dp,
avatar = contents?.avatar?.let {
AutumnResource(
tag = "avatars",
id = it,
metadata = Metadata(
type = "image/png",
width = 128,
height = 128,
)
)
}
)
Text(
text = buildAnnotatedString {
val displayNameSameAsUsername = contents?.displayName?.trim() ==
contents?.username?.trim()
if (!displayNameSameAsUsername) {
pushStyle(SpanStyle(fontWeight = FontWeight.Bold))
append(contents?.displayName)
pop()
append("\n")
}
append("${contents?.username}")
pushStyle(SpanStyle(fontWeight = FontWeight.ExtraLight))
append("#${contents?.discriminator}")
pop()
},
style = MaterialTheme.typography.bodyMedium,
fontSize = 21.sp,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Button(
onClick = {
scope.launch {
contents?.let { userContents ->
try {
friendUser("${userContents.username}#${userContents.discriminator}")
qrResult = null
contents = null
} catch (e: Exception) {
Toast.makeText(
context,
e.localizedMessage ?: e.toString(),
Toast.LENGTH_SHORT
).show()
}
}
}
},
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.friends_add_by_tag_sheet_add))
}
}
qrResult is QRResult.QRError || contents == null -> {
Text(
text = stringResource(R.string.friends_scan_qr_result_sheet_invalid_title),
style = MaterialTheme.typography.titleMedium,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Text(
text = stringResource(R.string.friends_scan_qr_result_sheet_invalid_description),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current.copy(alpha = 0.7f),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Button(
onClick = {
qrResult = null
contents = null
},
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.ok))
}
}
}
}
}
}
Scaffold(
topBar = {
@ -69,14 +491,6 @@ fun FriendsScreen(topNav: NavController, useDrawer: Boolean, onDrawerClicked: ()
}
},
actions = {
IconButton(onClick = {
topNav.navigate("create/group")
}) {
Icon(
painter = painterResource(R.drawable.ic_account_multiple_plus_24dp),
contentDescription = stringResource(R.string.frends_new_group)
)
}
IconButton(onClick = {
overflowMenuShown = true
}) {
@ -111,14 +525,14 @@ fun FriendsScreen(topNav: NavController, useDrawer: Boolean, onDrawerClicked: ()
},
windowInsets = WindowInsets.zero
)
},
}
) { pv ->
Column(
Box(
modifier = Modifier
.padding(pv)
.fillMaxHeight()
) {
LazyColumn {
LazyColumn(state = listState) {
stickyHeader(key = "incoming") {
CountableListHeader(
text = stringResource(id = R.string.friends_incoming_requests),
@ -234,7 +648,7 @@ fun FriendsScreen(topNav: NavController, useDrawer: Boolean, onDrawerClicked: ()
items(FriendRequests.getBlocked().size) {
val item = FriendRequests.getBlocked().getOrNull(it)
if (item == null) return@items
MemberListItem(
member = null,
user = item,
@ -250,6 +664,80 @@ fun FriendsScreen(topNav: NavController, useDrawer: Boolean, onDrawerClicked: ()
)
}
}
FloatingActionButtonMenu(
modifier = Modifier.align(Alignment.BottomEnd),
expanded = fabMenuExpanded,
button = {
ToggleFloatingActionButton(
modifier =
Modifier
.semantics {
traversalIndex = -1f
}
.animateFloatingActionButton(
visible = fabVisible || fabMenuExpanded,
alignment = Alignment.BottomEnd
),
checked = fabMenuExpanded,
onCheckedChange = { fabMenuExpanded = !fabMenuExpanded }
) {
val imageVector by remember {
derivedStateOf {
if (checkedProgress > 0.5f) Icons.Filled.Close else Icons.Filled.Add
}
}
Icon(
painter = rememberVectorPainter(imageVector),
contentDescription = null,
modifier = Modifier.animateIcon({ checkedProgress })
)
}
}
) {
FloatingActionButtonMenuItem(
modifier = Modifier.semantics { isTraversalGroup = true },
onClick = {
topNav.navigate("create/group")
fabMenuExpanded = false
},
icon = {
Icon(
painterResource(R.drawable.ic_account_multiple_plus_24dp),
contentDescription = null
)
},
text = { Text(stringResource(R.string.friends_new_group)) },
)
FloatingActionButtonMenuItem(
modifier = Modifier.semantics { isTraversalGroup = true },
onClick = {
fabMenuExpanded = false
scanQrCodeLauncher.launch(null)
},
icon = {
Icon(
painterResource(R.drawable.ic_qrcode_scan_24dp),
contentDescription = null
)
},
text = { Text(stringResource(R.string.friends_scan_qr)) },
)
FloatingActionButtonMenuItem(
modifier = Modifier.semantics { isTraversalGroup = true },
onClick = {
fabMenuExpanded = false
addByTagSheetVisible = true
},
icon = {
Icon(
painterResource(R.drawable.ic_pound_24dp),
contentDescription = null
)
},
text = { Text(stringResource(R.string.friends_add_by_tag)) },
)
}
}
}
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M4,4H10V10H4V4M20,4V10H14V4H20M14,15H16V13H14V11H16V13H18V11H20V13H18V15H20V18H18V20H16V18H13V20H11V16H14V15M16,15V18H18V15H16M4,20V14H10V20H4M6,6V8H8V6H6M16,6V8H18V6H16M6,16V18H8V16H6M4,11H6V13H4V11M9,11H13V15H11V13H9V11M11,6H13V10H11V6M2,2V6H0V2A2,2 0 0,1 2,0H6V2H2M22,0A2,2 0 0,1 24,2V6H22V2H18V0H22M2,18V22H6V24H2A2,2 0 0,1 0,22V18H2M22,22V18H24V22A2,2 0 0,1 22,24H18V22H22Z" />
</vector>

View File

@ -234,7 +234,7 @@
<string name="channel_age_gate_dob_month">الشهر</string>
<string name="channel_age_gate_dob_year">السنة</string>
<string name="report_user_heading">أخبرنا ما هو الخطأ في هذا المستخدم</string>
<string name="frends_new_group">مجموعة جديدة</string>
<string name="friends_new_group">مجموعة جديدة</string>
<string name="create_group">إنشاء مجموعة جديدة</string>
<string name="create_group_description">اجمع فريقك في محادثة جماعية. يمكنك إضافة ما يصل إلى %1$d شخصًا</string>
<string name="file_picker_chip_documents">الملفات</string>

View File

@ -434,7 +434,7 @@
<string name="message_context_sheet_actions_delete_confirmation_no">Пакінуць</string>
<string name="server_context_sheet_actions_report">Паскардзіцца</string>
<string name="settings_feedback_description">Далучыцеся да сервера Revolt, каб пакінуць водгук або пракановы і паведаміць аб памылках.</string>
<string name="frends_new_group">Новая група</string>
<string name="friends_new_group">Новая група</string>
<string name="create_group">Стварыць новую групу</string>
<string name="create_group_description">Збярыце сваю каманду ў групавым чаце. Вы можаце дадаць да %1$d чалавек.</string>
<string name="user_info_sheet_user_is_bot">Гэта бот.</string>

View File

@ -286,7 +286,7 @@
<string name="server_flag_official">অফিসিয়াল সার্ভার</string>
<string name="system_message_channel_icon_changed_alt">চ্যানেলের আইকন পরিবর্তিত হয়েছে</string>
<string name="channel_link_invalid">আপনি এই চ্যানেলটি দেখতে পারবেন না</string>
<string name="frends_new_group">নতুন গ্রুপ</string>
<string name="friends_new_group">নতুন গ্রুপ</string>
<string name="create_group_search">বন্ধুদের খুঁজুন</string>
<string name="message_context_sheet_actions_delete_confirmation_title">মেসেজটি মুছে ফেলতে চান\?</string>
<string name="message_context_sheet_actions_delete_confirmation_no">রাখুন</string>

View File

@ -195,7 +195,7 @@
<string name="status_invisible_explainer">Revolt budete moci používat jako obvykle, ale pro ostatní lidi se budete vypadat offline.</string>
<string name="channel_link_invalid">Tento kanál nelze zobrazit</string>
<string name="channel_info_sheet_options_notifications_manage">Správa oznámení</string>
<string name="frends_new_group">Nová skupina</string>
<string name="friends_new_group">Nová skupina</string>
<string name="create_group">Vytvořit novou skupinu</string>
<string name="create_group_name">Název skupiny</string>
<string name="create_group_search">Hledat přátele</string>

View File

@ -434,7 +434,7 @@
<string name="message_context_sheet_actions_delete_confirmation_no">Behalten</string>
<string name="server_context_sheet_actions_report">Melden</string>
<string name="settings_feedback_description">Tritt dem Revolt-Server bei, um Feedback und Vorschläge zu geben oder Fehler zu melden.</string>
<string name="frends_new_group">Neue Gruppe</string>
<string name="friends_new_group">Neue Gruppe</string>
<string name="create_group_description">Bring deine Crew in einem Gruppenchat zusammen. Du kannst bis zu %1$d Personen hinzufügen.</string>
<string name="user_info_sheet_user_is_bot_easter_egg">Das ist ein Bot. Er hat einen Plan.</string>
<string name="create_group">Neue Gruppe erstellen</string>

View File

@ -310,7 +310,7 @@
<string name="no_active_channel_body">Επιλέξτε έναν server από τα αριστερά για να ξεκινήσετε. Εάν αισθάνεστε περιπετειώδεις, μπορείτε να δημιουργήσετε έναν νέο server.</string>
<string name="discover_alt">Discover</string>
<string name="friends_deny_all_incoming">Εκκαθάριση όλων των εισερχόμενων αιτημάτων</string>
<string name="frends_new_group">Νέα Ομάδα</string>
<string name="friends_new_group">Νέα Ομάδα</string>
<string name="create_group">Δημιουργία νέας ομάδας</string>
<string name="create_group_description">Μαζέψτε τη παρέα σας σε μια ομαδική συνομιλία. Μπορείτε να προσθέσετε έως και %1$d άτομα.</string>
<string name="create_group_search">Αναζήτηση φίλων</string>

View File

@ -70,7 +70,7 @@
<string name="create_group_name">Nomo de grupo</string>
<string name="create_group_search">Serĉi Amikojn</string>
<string name="create_group_action">Krei</string>
<string name="frends_new_group">Nova Grupo</string>
<string name="friends_new_group">Nova Grupo</string>
<string name="channel_group">Grupo</string>
<string name="start_of_conversation">Jen la komenco de via konversacio</string>
<string name="reply_message_empty_has_attachments">Senditaj kunsendaĵoj</string>

View File

@ -434,7 +434,7 @@
<string name="settings_changelogs_historical_version_header">Registro de Cambios para %1$s</string>
<string name="settings_changelogs_historical_version_header_placeholder">esa versión</string>
<string name="settings_feedback_description">Unete al servidor de Revolt para dar una opinion o sugerencia y reportar bugs.</string>
<string name="frends_new_group">Nuevo Grupo</string>
<string name="friends_new_group">Nuevo Grupo</string>
<string name="create_group">Crear un nuevo grupo</string>
<string name="create_group_action">Crear</string>
<string name="settings_chat_quick_reply_none">Manten presionado para responder</string>

View File

@ -103,7 +103,7 @@
<string name="friends_all">همه</string>
<string name="friends_blocked">مسدود</string>
<string name="friends_deny_all_incoming">تمام درخواست های دریافتی را پاک کنید</string>
<string name="frends_new_group">گروه جدید</string>
<string name="friends_new_group">گروه جدید</string>
<string name="create_group">یک گروه جدید ایجاد کنید</string>
<string name="create_group_name">اسم گروه</string>
<string name="create_group_search">جستجوی دوستان</string>

View File

@ -433,7 +433,7 @@
<string name="message_context_sheet_actions_delete_confirmation_yes">Burahin</string>
<string name="message_context_sheet_actions_delete_confirmation_no">Panatilihin</string>
<string name="server_context_sheet_actions_report">Iulat</string>
<string name="frends_new_group">Bagong Groupo</string>
<string name="friends_new_group">Bagong Groupo</string>
<string name="create_group">Gumawa ng bagong groupo</string>
<string name="create_group_name">Pangalan ng Groupo</string>
<string name="create_group_search">Maghanap ng Mga Kaibigan</string>

View File

@ -460,7 +460,7 @@
<string name="channel_settings_delete_confirm_yes">Supprimer</string>
<string name="channel_settings_delete_confirm_no">Conserver</string>
<string name="discover_alt">Découvrir</string>
<string name="frends_new_group">Nouveau groupe</string>
<string name="friends_new_group">Nouveau groupe</string>
<string name="create_group">Créer un nouveau groupe</string>
<string name="create_group_description">Rassemblez vos amis dans un groupe de conversation. Vous pouvez ajouter jusqu\'à %1$d personnes.</string>
<string name="create_group_name">Nom du groupe</string>

View File

@ -434,7 +434,7 @@
<string name="message_context_sheet_actions_delete_confirmation_yes">Törlés</string>
<string name="message_context_sheet_actions_delete_confirmation_no">Mégsem törlöm</string>
<string name="settings_feedback_description">Csatlakozz a Revolt szerveréhez itt jelezhetsz vissza nekünk és tudsz minket elérni, jelentheted a hibákat.</string>
<string name="frends_new_group">Új csoport</string>
<string name="friends_new_group">Új csoport</string>
<string name="create_group_description">Szedd össze a csapatodat csoportos chatbe. Legfeljebb %1$d személyt adhatsz hozzá.</string>
<string name="user_info_sheet_user_is_bot">Ez egy Robi 🤖</string>
<string name="create_group">Új csoport létrehozása</string>

View File

@ -309,7 +309,7 @@
<string name="status_invisible_explainer">Kamu bisa menggunakan Revolt seperti biasa, namun kamu tidak akan terlihat daring oleh orang lain.</string>
<string name="status_offline">Luring</string>
<string name="emote_info_from_unicode">Emoji bawaan yang bisa digunakan di mana saja</string>
<string name="frends_new_group">Grup Baru</string>
<string name="friends_new_group">Grup Baru</string>
<string name="create_group">Buat grup baru</string>
<string name="create_group_description">Undang teman-temanmu ke obrolan grup. Kamu bisa menambahkan %1$d orang.</string>
<string name="create_group_name">Nama Grup</string>

View File

@ -439,7 +439,7 @@
<string name="user_info_sheet_user_is_bot">Questo è un bot.</string>
<string name="create_group_search">Cerca Amici</string>
<string name="create_group_action">Crea</string>
<string name="frends_new_group">Nuovo Gruppo</string>
<string name="friends_new_group">Nuovo Gruppo</string>
<string name="create_group_name">Nome del Gruppo</string>
<string name="user_info_sheet_user_is_bot_easter_egg">Questo è un bot... che ha un piano.</string>
<string name="user_info_sheet_category_owner">Proprietario</string>

View File

@ -136,7 +136,7 @@
<string name="friends_outgoing_requests">Išsiųsti prašymai</string>
<string name="friends_all">Visi</string>
<string name="friends_blocked">Užblokuotas</string>
<string name="frends_new_group">Nauja grupė</string>
<string name="friends_new_group">Nauja grupė</string>
<string name="create_group">Sukurti naują grupę</string>
<string name="create_group_description">Surinkite savo komandą į grupinį pokalbį. Galite įtraukti iki %1$d žmonių.</string>
<string name="create_group_name">Grupės pavadinimas</string>

View File

@ -103,7 +103,7 @@
<string name="friends_outgoing_requests">Izejošie pieprasījumi</string>
<string name="friends_all">Visi</string>
<string name="friends_blocked">Bloķēts</string>
<string name="frends_new_group">Jauna grupa</string>
<string name="friends_new_group">Jauna grupa</string>
<string name="create_group_name">Grupas nosaukums</string>
<string name="create_group_search">Meklēt draugus</string>
<string name="create_group_action">Izveidot</string>

View File

@ -471,7 +471,7 @@
<string name="channel_settings_overview_nsfw">Marcar cumo Einaporpriado (+18)</string>
<string name="channel_settings_overview_nsfw_description">Outelizadores son requesitados a cunfirmar la sue eidade antes de s\'ouniren a canales Einaporpriados (+18).</string>
<string name="channel_settings_overview_nsfw_undo_confirm_description">Outelizadores yá nun ban a ser requesitados a cunfirmar la sue eidade antes de s\'ouniren a este canal. Por fabor stá seguro que\'l cuntenido ye aporpriado a to las eidades.</string>
<string name="frends_new_group">Nuobo Grupo</string>
<string name="friends_new_group">Nuobo Grupo</string>
<string name="message_field_editing_message_cancel_alt">Cancelar eidiçon</string>
<string name="channel_context_sheet_open">Abrir canales daçones</string>
<string name="colour_picker_use_default">Padron</string>

View File

@ -434,7 +434,7 @@
<string name="message_context_sheet_actions_delete_confirmation_yes">Usuń</string>
<string name="message_context_sheet_actions_delete_confirmation_no">Zachowaj</string>
<string name="settings_feedback_description">Dołącz do serwera Revolt, aby przekazywać opinie i sugestie oraz zgłaszać błędy.</string>
<string name="frends_new_group">Nowa grupa</string>
<string name="friends_new_group">Nowa grupa</string>
<string name="create_group_description">Zbierz załogę na czacie grupowym. Możesz dodać do %1$d osób.</string>
<string name="user_info_sheet_user_is_bot">To jest bot.</string>
<string name="create_group">Stwórz nową grupę</string>

View File

@ -476,7 +476,7 @@
<string name="rate_limit_toast">Fica frio aí! Você tá fazendo isso demais em muito pouco tempo.</string>
<string name="service_health_alert_body_default">Estamos passando por dificuldades com nossos serviços. Confira a página de status para mais informações.</string>
<string name="attachment_preview_remove">Remover</string>
<string name="frends_new_group">Novo Grupo</string>
<string name="friends_new_group">Novo Grupo</string>
<string name="create_group_description">Reúna sua turma em um bate-papo em grupo. Você pode adicionar até %1$d pessoas.</string>
<string name="message_field_editing_message">Editando mensagem</string>
<string name="message_failed_to_send">Falha ao enviar, segure para ver opções</string>

View File

@ -337,7 +337,7 @@
<string name="settings_changelogs_historical_version_header">Registro de alterações de %1$s</string>
<string name="settings_changelogs_new_header">O que está cozinhando ✨</string>
<string name="settings_changelogs">Registros de alterações</string>
<string name="frends_new_group">Novo grupo</string>
<string name="friends_new_group">Novo grupo</string>
<string name="create_group">Crie um novo grupo</string>
<string name="create_group_name">Nome do grupo</string>
<string name="create_group_search">Procurar amigos</string>

View File

@ -306,7 +306,7 @@
<string name="friends_all">Toate</string>
<string name="friends_blocked">Blocați</string>
<string name="friends_deny_all_incoming">Elimină toate cererile primite</string>
<string name="frends_new_group">Grup nou</string>
<string name="friends_new_group">Grup nou</string>
<string name="create_group">Creează un grup nou</string>
<string name="create_group_name">Numele grupului</string>
<string name="create_group_search">Căutare prieteni</string>

View File

@ -434,7 +434,7 @@
<string name="message_context_sheet_actions_delete_confirmation_yes">Удалить</string>
<string name="message_context_sheet_actions_delete_confirmation_no">Оставить</string>
<string name="settings_feedback_description">Присоединяйтесь к серверу Revolt, чтобы оставлять отзывы и предложения и сообщать об ошибках.</string>
<string name="frends_new_group">Новая группа</string>
<string name="friends_new_group">Новая группа</string>
<string name="create_group_description">Соберите свою команду в групповом чате. Вы можете добавить до %1$d человек.</string>
<string name="user_info_sheet_user_is_bot">Это бот.</string>
<string name="create_group">Создать новую группу</string>

View File

@ -104,7 +104,7 @@
<string name="friends_outgoing_requests">คำขอเป็นเพื่อนขาออก</string>
<string name="friends_all">ทั้งหมด</string>
<string name="friends_deny_all_incoming">ลบคำขอขาเข้าทั้งหมด</string>
<string name="frends_new_group">กลุ่มใหม่</string>
<string name="friends_new_group">กลุ่มใหม่</string>
<string name="create_group">สร้างกลุ่มใหม่</string>
<string name="create_group_description">รวมพลกับเพื่อนๆ ของคุณในแชท คุณสามารถเพิ่มได้สูงสุด %1$d คน</string>
<string name="create_group_name">ชื่อกลุ่ม</string>

View File

@ -266,7 +266,7 @@
<string name="channel_age_gate_title">Bu kanal NSFW olarak işaretlendi</string>
<string name="channel_age_gate_description">Bu kanalı görüntülemek için 18 yaşında veya üzerinde olmalısın.</string>
<string name="channel_age_gate_dob_section">Doğum tarihi</string>
<string name="frends_new_group">Yeni Grup</string>
<string name="friends_new_group">Yeni Grup</string>
<string name="create_group">Yeni grup oluştur</string>
<string name="create_group_name">Grup İsmi</string>
<string name="create_group_action">Oluştur</string>

View File

@ -448,7 +448,7 @@
<string name="channel_age_gate_title">Цей канал позначено як NSFW</string>
<string name="channel_age_gate_dob_section">Дата народження</string>
<string name="server_context_sheet_actions_report">Поскаржитись</string>
<string name="frends_new_group">Створити групу</string>
<string name="friends_new_group">Створити групу</string>
<string name="create_group">Створити нову групу</string>
<string name="create_group_description">Зберіть команду в груповому чаті. Ви можете додати до %1$d людей.</string>
<string name="create_group_name">Назва групи</string>

View File

@ -434,7 +434,7 @@
<string name="message_context_sheet_actions_delete_confirmation_yes">删除</string>
<string name="message_context_sheet_actions_delete_confirmation_no">保留</string>
<string name="settings_feedback_description">加入 Revolt 服务器来提出反馈建议和报告错误。</string>
<string name="frends_new_group">新群组</string>
<string name="friends_new_group">新群组</string>
<string name="create_group">创建新群组</string>
<string name="user_info_sheet_user_is_bot_easter_egg">这是个机器人。它很有主见。</string>
<string name="user_info_sheet_user_is_bot">这是个机器人。</string>

View File

@ -171,7 +171,20 @@
<string name="friends_all">All</string>
<string name="friends_blocked">Blocked</string>
<string name="friends_deny_all_incoming">Clear all incoming requests</string>
<string name="frends_new_group">New Group</string>
<string name="friends_new_group">New group</string>
<string name="friends_scan_qr">Scan QR code</string>
<string name="friends_scan_qr_result_sheet_invalid_title">Invalid QR code</string>
<string name="friends_scan_qr_result_sheet_invalid_description">This is not a valid Revolt QR code.</string>
<string name="friends_scan_qr_result_sheet_missing_permission_title">Missing camera permission</string>
<string name="friends_scan_qr_result_sheet_missing_permission_description">You need to grant the camera permission to scan QR codes.</string>
<string name="friends_scan_qr_result_sheet_success_title">Add friend?</string>
<string name="friends_add_by_tag">Add with username and tag</string>
<string name="friends_add_by_tag_sheet_description">You can add friends by their %1$susername%3$s and %2$stag%3$s. For example, if their username is %1$sjane%3$s and their tag is %2$s1234%3$s, you can add them with %1$sjane%3$s#%2$s1234%3$s.</string>
<string name="friends_add_by_tag_sheet_username">Username</string>
<string name="friends_add_by_tag_sheet_tag">Tag</string>
<string name="friends_add_by_tag_sheet_add">Add</string>
<string name="friends_add_by_tag_sheet_paste_from_clipboard">Paste clipboard</string>
<string name="friends_add_by_tag_sheet_invalid_clipboard">The clipboard does not contain a valid username and tag.</string>
<!-- In an experimental iteration of the app's UI, there are three tabs. This is the tab which contains servers. -->
<string name="main_tab_communities">Communities</string>