diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f898083a..ccafec7a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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") diff --git a/app/src/main/java/chat/revolt/api/internals/UserQR.kt b/app/src/main/java/chat/revolt/api/internals/UserQR.kt index 58b4c14e..9c3e21ce 100644 --- a/app/src/main/java/chat/revolt/api/internals/UserQR.kt +++ b/app/src/main/java/chat/revolt/api/internals/UserQR.kt @@ -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 + } + } } \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/composables/vectorassets/RevoltTagIntro.kt b/app/src/main/java/chat/revolt/composables/vectorassets/RevoltTagIntro.kt new file mode 100644 index 00000000..c040e5fc --- /dev/null +++ b/app/src/main/java/chat/revolt/composables/vectorassets/RevoltTagIntro.kt @@ -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 + ) +} diff --git a/app/src/main/java/chat/revolt/markdown/jbm/KatexRenderer.kt b/app/src/main/java/chat/revolt/markdown/jbm/KatexRenderer.kt index 0ee336db..76bf46e1 100644 --- a/app/src/main/java/chat/revolt/markdown/jbm/KatexRenderer.kt +++ b/app/src/main/java/chat/revolt/markdown/jbm/KatexRenderer.kt @@ -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()) } diff --git a/app/src/main/java/chat/revolt/screens/chat/views/FriendsScreen.kt b/app/src/main/java/chat/revolt/screens/chat/views/FriendsScreen.kt index e8dd5163..583be0ee 100644 --- a/app/src/main/java/chat/revolt/screens/chat/views/FriendsScreen.kt +++ b/app/src/main/java/chat/revolt/screens/chat/views/FriendsScreen.kt @@ -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(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(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, + "", + "", + "", + ) + ), + 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(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)) }, + ) + } } } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_qrcode_scan_24dp.xml b/app/src/main/res/drawable/ic_qrcode_scan_24dp.xml new file mode 100644 index 00000000..976944aa --- /dev/null +++ b/app/src/main/res/drawable/ic_qrcode_scan_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 38b8d1f7..ee109e9f 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -234,7 +234,7 @@ الشهر السنة أخبرنا ما هو الخطأ في هذا المستخدم - مجموعة جديدة + مجموعة جديدة إنشاء مجموعة جديدة اجمع فريقك في محادثة جماعية. يمكنك إضافة ما يصل إلى %1$d شخصًا الملفات diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index a13826f5..614ac6b6 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -434,7 +434,7 @@ Пакінуць Паскардзіцца Далучыцеся да сервера Revolt, каб пакінуць водгук або пракановы і паведаміць аб памылках. - Новая група + Новая група Стварыць новую групу Збярыце сваю каманду ў групавым чаце. Вы можаце дадаць да %1$d чалавек. Гэта бот. diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index 6726ae06..e6c88a43 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -286,7 +286,7 @@ অফিসিয়াল সার্ভার চ্যানেলের আইকন পরিবর্তিত হয়েছে আপনি এই চ্যানেলটি দেখতে পারবেন না - নতুন গ্রুপ + নতুন গ্রুপ বন্ধুদের খুঁজুন মেসেজটি মুছে ফেলতে চান\? রাখুন diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 45e73d3f..ae726ab2 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -195,7 +195,7 @@ Revolt budete moci používat jako obvykle, ale pro ostatní lidi se budete vypadat offline. Tento kanál nelze zobrazit Správa oznámení - Nová skupina + Nová skupina Vytvořit novou skupinu Název skupiny Hledat přátele diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9e489802..47c63f84 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -434,7 +434,7 @@ Behalten Melden Tritt dem Revolt-Server bei, um Feedback und Vorschläge zu geben oder Fehler zu melden. - Neue Gruppe + Neue Gruppe Bring deine Crew in einem Gruppenchat zusammen. Du kannst bis zu %1$d Personen hinzufügen. Das ist ein Bot. Er hat einen Plan. Neue Gruppe erstellen diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index d16ed1ae..80bfff46 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -310,7 +310,7 @@ Επιλέξτε έναν server από τα αριστερά για να ξεκινήσετε. Εάν αισθάνεστε περιπετειώδεις, μπορείτε να δημιουργήσετε έναν νέο server. Discover Εκκαθάριση όλων των εισερχόμενων αιτημάτων - Νέα Ομάδα + Νέα Ομάδα Δημιουργία νέας ομάδας Μαζέψτε τη παρέα σας σε μια ομαδική συνομιλία. Μπορείτε να προσθέσετε έως και %1$d άτομα. Αναζήτηση φίλων diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 4bd225ea..e7afd3ad 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -70,7 +70,7 @@ Nomo de grupo Serĉi Amikojn Krei - Nova Grupo + Nova Grupo Grupo Jen la komenco de via konversacio Senditaj kunsendaĵoj diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 8fca0838..40b3b94d 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -434,7 +434,7 @@ Registro de Cambios para %1$s esa versión Unete al servidor de Revolt para dar una opinion o sugerencia y reportar bugs. - Nuevo Grupo + Nuevo Grupo Crear un nuevo grupo Crear Manten presionado para responder diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index ed5bb728..a6a73c2d 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -103,7 +103,7 @@ همه مسدود تمام درخواست های دریافتی را پاک کنید - گروه جدید + گروه جدید یک گروه جدید ایجاد کنید اسم گروه جستجوی دوستان diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml index 9717af85..c087d65d 100644 --- a/app/src/main/res/values-fil/strings.xml +++ b/app/src/main/res/values-fil/strings.xml @@ -433,7 +433,7 @@ Burahin Panatilihin Iulat - Bagong Groupo + Bagong Groupo Gumawa ng bagong groupo Pangalan ng Groupo Maghanap ng Mga Kaibigan diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index ffffc793..149d4fd1 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -460,7 +460,7 @@ Supprimer Conserver Découvrir - Nouveau groupe + Nouveau groupe Créer un nouveau groupe Rassemblez vos amis dans un groupe de conversation. Vous pouvez ajouter jusqu\'à %1$d personnes. Nom du groupe diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 82cdd41c..02426811 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -434,7 +434,7 @@ Törlés Mégsem törlöm Csatlakozz a Revolt szerveréhez – itt jelezhetsz vissza nekünk és tudsz minket elérni, jelentheted a hibákat. - Új csoport + Új csoport Szedd össze a csapatodat csoportos chatbe. Legfeljebb %1$d személyt adhatsz hozzá. Ez egy Robi 🤖 Új csoport létrehozása diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index f0a73b17..429e2083 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -309,7 +309,7 @@ Kamu bisa menggunakan Revolt seperti biasa, namun kamu tidak akan terlihat daring oleh orang lain. Luring Emoji bawaan yang bisa digunakan di mana saja - Grup Baru + Grup Baru Buat grup baru Undang teman-temanmu ke obrolan grup. Kamu bisa menambahkan %1$d orang. Nama Grup diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 60e40abf..c2d232f8 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -439,7 +439,7 @@ Questo è un bot. Cerca Amici Crea - Nuovo Gruppo + Nuovo Gruppo Nome del Gruppo Questo è un bot... che ha un piano. Proprietario diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index a0171c21..abcec1a4 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -136,7 +136,7 @@ Išsiųsti prašymai Visi Užblokuotas - Nauja grupė + Nauja grupė Sukurti naują grupę Surinkite savo komandą į grupinį pokalbį. Galite įtraukti iki %1$d žmonių. Grupės pavadinimas diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 6a469485..85bd1b60 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -103,7 +103,7 @@ Izejošie pieprasījumi Visi Bloķēts - Jauna grupa + Jauna grupa Grupas nosaukums Meklēt draugus Izveidot diff --git a/app/src/main/res/values-mwl/strings.xml b/app/src/main/res/values-mwl/strings.xml index e6156185..7547ae78 100644 --- a/app/src/main/res/values-mwl/strings.xml +++ b/app/src/main/res/values-mwl/strings.xml @@ -471,7 +471,7 @@ Marcar cumo Einaporpriado (+18) Outelizadores son requesitados a cunfirmar la sue eidade antes de s\'ouniren a canales Einaporpriados (+18). 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. - Nuobo Grupo + Nuobo Grupo Cancelar eidiçon Abrir canales d’açones Padron diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 2df8bc8b..6498c944 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -434,7 +434,7 @@ Usuń Zachowaj Dołącz do serwera Revolt, aby przekazywać opinie i sugestie oraz zgłaszać błędy. - Nowa grupa + Nowa grupa Zbierz załogę na czacie grupowym. Możesz dodać do %1$d osób. To jest bot. Stwórz nową grupę diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index e9181daa..4ccc1add 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -476,7 +476,7 @@ Fica frio aí! Você tá fazendo isso demais em muito pouco tempo. Estamos passando por dificuldades com nossos serviços. Confira a página de status para mais informações. Remover - Novo Grupo + Novo Grupo Reúna sua turma em um bate-papo em grupo. Você pode adicionar até %1$d pessoas. Editando mensagem Falha ao enviar, segure para ver opções diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 7ab40c4f..f1e29179 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -337,7 +337,7 @@ Registro de alterações de %1$s O que está cozinhando ✨ Registros de alterações - Novo grupo + Novo grupo Crie um novo grupo Nome do grupo Procurar amigos diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 35a21dce..834ba3de 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -306,7 +306,7 @@ Toate Blocați Elimină toate cererile primite - Grup nou + Grup nou Creează un grup nou Numele grupului Căutare prieteni diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index b1e94749..cf45ba30 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -434,7 +434,7 @@ Удалить Оставить Присоединяйтесь к серверу Revolt, чтобы оставлять отзывы и предложения и сообщать об ошибках. - Новая группа + Новая группа Соберите свою команду в групповом чате. Вы можете добавить до %1$d человек. Это бот. Создать новую группу diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 06ee2f53..51efa331 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -104,7 +104,7 @@ คำขอเป็นเพื่อนขาออก ทั้งหมด ลบคำขอขาเข้าทั้งหมด - กลุ่มใหม่ + กลุ่มใหม่ สร้างกลุ่มใหม่ รวมพลกับเพื่อนๆ ของคุณในแชท คุณสามารถเพิ่มได้สูงสุด %1$d คน ชื่อกลุ่ม diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index ed62ef5e..cbacfe59 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -266,7 +266,7 @@ Bu kanal NSFW olarak işaretlendi Bu kanalı görüntülemek için 18 yaşında veya üzerinde olmalısın. Doğum tarihi - Yeni Grup + Yeni Grup Yeni grup oluştur Grup İsmi Oluştur diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index b3b5f317..fb0e7dc1 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -448,7 +448,7 @@ Цей канал позначено як NSFW Дата народження Поскаржитись - Створити групу + Створити групу Створити нову групу Зберіть команду в груповому чаті. Ви можете додати до %1$d людей. Назва групи diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 91d4080e..78738dbb 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -434,7 +434,7 @@ 删除 保留 加入 Revolt 服务器来提出反馈建议和报告错误。 - 新群组 + 新群组 创建新群组 这是个机器人。它很有主见。 这是个机器人。 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fbac9dbb..83fec096 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -171,7 +171,20 @@ All Blocked Clear all incoming requests - New Group + New group + Scan QR code + Invalid QR code + This is not a valid Revolt QR code. + Missing camera permission + You need to grant the camera permission to scan QR codes. + Add friend? + Add with username and tag + 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. + Username + Tag + Add + Paste clipboard + The clipboard does not contain a valid username and tag. Communities