Merge branch 'develop' of https://github.com/vector-im/element-x-android into dla/feature/room_list_decoration

This commit is contained in:
David Langley
2023-09-15 15:48:15 +01:00
76 changed files with 1144 additions and 181 deletions

View File

@@ -198,6 +198,7 @@ dependencies {
allLibrariesImpl()
allServicesImpl()
allFeaturesImpl(rootDir, logger)
implementation(projects.features.call)
implementation(projects.anvilannotations)
implementation(projects.appnav)
anvil(projects.anvilcodegen)

1
changelog.d/1300.feature Normal file
View File

@@ -0,0 +1 @@
Integrate Element Call into EX by embedding a call in a WebView.

1
changelog.d/1332.feature Normal file
View File

@@ -0,0 +1 @@
[Rich text editor] Update design

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
id("io.element.android-compose-library")
alias(libs.plugins.anvil)
alias(libs.plugins.ksp)
}
android {
namespace = "io.element.android.features.call"
}
dependencies {
implementation(projects.libraries.architecture)
implementation(projects.libraries.designsystem)
implementation(projects.libraries.network)
implementation(libs.androidx.webkit)
ksp(libs.showkase.processor)
testImplementation(libs.test.junit)
testImplementation(libs.test.truth)
testImplementation(libs.test.robolectric)
}

View File

@@ -0,0 +1,61 @@
<!--
~ Copyright (c) 2023 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.microphone" android:required="false" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application>
<activity
android:name=".ElementCallActivity"
android:label="@string/element_call"
android:exported="true"
android:taskAffinity="io.element.android.features.call"
android:configChanges="screenSize|screenLayout|orientation|keyboardHidden|keyboard|navigation|uiMode"
android:launchMode="singleTask">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="call.element.io" />
</intent-filter>
<!-- Custom scheme to handle urls from other domains in the format: element://call?url=https%3A%2F%2Felement.io -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="element" />
<data android:host="call" />
</intent-filter>
</activity>
<service android:name=".CallForegroundService" android:enabled="true" android:foregroundServiceType="mediaPlayback" />
</application>
</manifest>

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.call
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationChannelCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.PendingIntentCompat
import androidx.core.graphics.drawable.IconCompat
import io.element.android.libraries.designsystem.utils.CommonDrawables
class CallForegroundService : Service() {
companion object {
fun start(context: Context) {
val intent = Intent(context, CallForegroundService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
}
fun stop(context: Context) {
val intent = Intent(context, CallForegroundService::class.java)
context.stopService(intent)
}
}
private lateinit var notificationManagerCompat: NotificationManagerCompat
override fun onCreate() {
super.onCreate()
notificationManagerCompat = NotificationManagerCompat.from(this)
val foregroundServiceChannel = NotificationChannelCompat.Builder(
"call_foreground_service_channel",
NotificationManagerCompat.IMPORTANCE_LOW,
).setName(
getString(R.string.call_foreground_service_channel_title_android).ifEmpty { "Ongoing call" }
).build()
notificationManagerCompat.createNotificationChannel(foregroundServiceChannel)
val callActivityIntent = Intent(this, ElementCallActivity::class.java)
val pendingIntent = PendingIntentCompat.getActivity(this, 0, callActivityIntent, 0, false)
val notification = NotificationCompat.Builder(this, foregroundServiceChannel.id)
.setSmallIcon(IconCompat.createWithResource(this, CommonDrawables.ic_notification_small))
.setContentTitle(getString(R.string.call_foreground_service_title_android))
.setContentText(getString(R.string.call_foreground_service_message_android))
.setContentIntent(pendingIntent)
.build()
startForeground(1, notification)
}
@Suppress("DEPRECATION")
override fun onDestroy() {
super.onDestroy()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
stopForeground(STOP_FOREGROUND_REMOVE)
} else {
stopForeground(true)
}
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.call
import android.net.Uri
import java.net.URLDecoder
object CallIntentDataParser {
private val validHttpSchemes = sequenceOf("http", "https")
fun parse(data: String?): String? {
val parsedUrl = data?.let { Uri.parse(data) } ?: return null
val scheme = parsedUrl.scheme
return when {
scheme in validHttpSchemes && parsedUrl.host == "call.element.io" -> data
scheme == "element" && parsedUrl.host == "call" -> {
// We use this custom scheme to load arbitrary URLs for other instances of Element Call,
// so we can only verify it's an HTTP/HTTPs URL with a non-empty host
parsedUrl.getQueryParameter("url")
?.let { URLDecoder.decode(it, "utf-8") }
?.takeIf {
val internalUri = Uri.parse(it)
internalUri.scheme in validHttpSchemes && !internalUri.host.isNullOrBlank()
}
}
// This should never be possible, but we still need to take into account the possibility
else -> null
}
}
}

View File

@@ -0,0 +1,152 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.call
import android.annotation.SuppressLint
import android.view.ViewGroup
import android.webkit.PermissionRequest
import android.webkit.WebChromeClient
import android.webkit.WebView
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.viewinterop.AndroidView
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.DayNightPreviews
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.theme.ElementTheme
typealias RequestPermissionCallback = (Array<String>) -> Unit
@OptIn(ExperimentalMaterial3Api::class)
@Composable
internal fun CallScreenView(
url: String?,
userAgent: String,
requestPermissions: (Array<String>, RequestPermissionCallback) -> Unit,
onClose: () -> Unit,
modifier: Modifier = Modifier,
) {
ElementTheme {
Scaffold(
modifier = modifier,
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.element_call)) },
navigationIcon = {
BackButton(
imageVector = Icons.Default.Close,
onClick = onClose
)
}
)
}
) { padding ->
CallWebView(
modifier = Modifier
.padding(padding)
.consumeWindowInsets(padding)
.fillMaxSize(),
url = url,
userAgent = userAgent,
onPermissionsRequested = { request ->
val androidPermissions = mapWebkitPermissions(request.resources)
val callback: RequestPermissionCallback = { request.grant(it) }
requestPermissions(androidPermissions.toTypedArray(), callback)
}
)
}
}
}
@Composable
private fun CallWebView(
url: String?,
userAgent: String,
onPermissionsRequested: (PermissionRequest) -> Unit,
modifier: Modifier = Modifier,
) {
val isInpectionMode = LocalInspectionMode.current
AndroidView(
modifier = modifier,
factory = { context ->
WebView(context).apply {
if (!isInpectionMode) {
setup(userAgent, onPermissionsRequested)
if (url != null) {
loadUrl(url)
}
}
}
},
update = { webView ->
if (!isInpectionMode && url != null) {
webView.loadUrl(url)
}
},
onRelease = { webView ->
webView.destroy()
}
)
}
@SuppressLint("SetJavaScriptEnabled")
private fun WebView.setup(userAgent: String, onPermissionsRequested: (PermissionRequest) -> Unit) {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
with(settings) {
javaScriptEnabled = true
allowContentAccess = true
allowFileAccess = true
domStorageEnabled = true
mediaPlaybackRequiresUserGesture = false
databaseEnabled = true
loadsImagesAutomatically = true
userAgentString = userAgent
}
webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest) {
onPermissionsRequested(request)
}
}
}
@DayNightPreviews
@Composable
internal fun CallScreenViewPreview() {
ElementTheme {
CallScreenView(
url = "https://call.element.io/some-actual-call?with=parameters",
userAgent = "",
requestPermissions = { _, _ -> },
onClose = { },
)
}
}

View File

@@ -0,0 +1,208 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.call
import android.Manifest
import android.content.Intent
import android.content.res.Configuration
import android.media.AudioAttributes
import android.media.AudioFocusRequest
import android.media.AudioManager
import android.os.Build
import android.os.Bundle
import android.view.WindowManager
import android.webkit.PermissionRequest
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.mutableStateOf
import io.element.android.features.call.di.CallBindings
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.network.useragent.UserAgentProvider
import javax.inject.Inject
class ElementCallActivity : ComponentActivity() {
@Inject lateinit var userAgentProvider: UserAgentProvider
private lateinit var audioManager: AudioManager
private var requestPermissionCallback: RequestPermissionCallback? = null
private var audiofocusRequest: AudioFocusRequest? = null
private var audioFocusChangeListener: AudioManager.OnAudioFocusChangeListener? = null
private val requestPermissionsLauncher = registerPermissionResultLauncher()
private var isDarkMode = false
private val urlState = mutableStateOf<String?>(null)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
applicationContext.bindings<CallBindings>().inject(this)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
urlState.value = intent?.dataString?.let(::parseUrl) ?: run {
finish()
return
}
if (savedInstanceState == null) {
updateUiMode(resources.configuration)
}
audioManager = getSystemService(AUDIO_SERVICE) as AudioManager
requestAudioFocus()
val userAgent = userAgentProvider.provide()
setContent {
CallScreenView(
url = urlState.value,
userAgent = userAgent,
onClose = this::finish,
requestPermissions = { permissions, callback ->
requestPermissionCallback = callback
requestPermissionsLauncher.launch(permissions)
}
)
}
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
updateUiMode(newConfig)
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
val intentUrl = intent?.dataString?.let(::parseUrl)
when {
// New URL, update it and reload the webview
intentUrl != null -> urlState.value = intentUrl
// Re-opened the activity but we have no url to load or a cached one, finish the activity
intent?.dataString == null && urlState.value == null -> finish()
// Coming back from notification, do nothing
else -> return
}
}
override fun onStart() {
super.onStart()
CallForegroundService.stop(this)
}
override fun onStop() {
super.onStop()
if (!isFinishing && !isChangingConfigurations) {
CallForegroundService.start(this)
}
}
override fun onDestroy() {
super.onDestroy()
releaseAudioFocus()
CallForegroundService.stop(this)
}
override fun finish() {
// Also remove the task from recents
finishAndRemoveTask()
}
private fun parseUrl(url: String?): String? = CallIntentDataParser.parse(url)
private fun registerPermissionResultLauncher(): ActivityResultLauncher<Array<String>> {
return registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val callback = requestPermissionCallback ?: return@registerForActivityResult
val permissionsToGrant = mutableListOf<String>()
permissions.forEach { (permission, granted) ->
if (granted) {
val webKitPermission = when (permission) {
Manifest.permission.CAMERA -> PermissionRequest.RESOURCE_VIDEO_CAPTURE
Manifest.permission.RECORD_AUDIO -> PermissionRequest.RESOURCE_AUDIO_CAPTURE
else -> return@forEach
}
permissionsToGrant.add(webKitPermission)
}
}
callback(permissionsToGrant.toTypedArray())
}
}
@Suppress("DEPRECATION")
private fun requestAudioFocus() {
val audioAttributes = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val request = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(audioAttributes)
.build()
audioManager.requestAudioFocus(request)
audiofocusRequest = request
} else {
val listener = AudioManager.OnAudioFocusChangeListener { }
audioManager.requestAudioFocus(
listener,
AudioManager.STREAM_VOICE_CALL,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE,
)
audioFocusChangeListener = listener
}
}
@Suppress("DEPRECATION")
private fun releaseAudioFocus() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
audiofocusRequest?.let { audioManager.abandonAudioFocusRequest(it) }
} else {
audioFocusChangeListener?.let { audioManager.abandonAudioFocus(it) }
}
}
private fun updateUiMode(configuration: Configuration) {
val prevDarkMode = isDarkMode
val currentNightMode = configuration.uiMode and Configuration.UI_MODE_NIGHT_YES
isDarkMode = currentNightMode != 0
if (prevDarkMode != isDarkMode) {
if (isDarkMode) {
window.setBackgroundDrawableResource(android.R.drawable.screen_background_dark)
} else {
window.setBackgroundDrawableResource(android.R.drawable.screen_background_light)
}
}
}
}
internal fun mapWebkitPermissions(permissions: Array<String>): List<String> {
return permissions.mapNotNull { permission ->
when (permission) {
PermissionRequest.RESOURCE_AUDIO_CAPTURE -> Manifest.permission.RECORD_AUDIO
PermissionRequest.RESOURCE_VIDEO_CAPTURE -> Manifest.permission.CAMERA
else -> null
}
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.call.di
import com.squareup.anvil.annotations.ContributesTo
import io.element.android.features.call.ElementCallActivity
import io.element.android.libraries.di.AppScope
@ContributesTo(AppScope::class)
interface CallBindings {
fun inject(callActivity: ElementCallActivity)
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="call_foreground_service_channel_title_android">"Appel en cours"</string>
<string name="call_foreground_service_message_android">"Appuyez pour retourner à l\'appel."</string>
<string name="call_foreground_service_title_android">"☎️ Appel en cours"</string>
</resources>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2023 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<string translatable="false" name="element_call">Element Call</string>
</resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="call_foreground_service_channel_title_android">"Ongoing call"</string>
<string name="call_foreground_service_message_android">"Tap to return to the call"</string>
<string name="call_foreground_service_title_android">"☎️ Call in progress"</string>
</resources>

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.call
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import java.net.URLEncoder
@RunWith(RobolectricTestRunner::class)
class CallIntentDataParserTests {
@Test
fun `a null data returns null`() {
val url: String? = null
assertThat(CallIntentDataParser.parse(url)).isNull()
}
@Test
fun `empty data returns null`() {
val url = ""
assertThat(CallIntentDataParser.parse(url)).isNull()
}
@Test
fun `invalid data returns null`() {
val url = "!"
assertThat(CallIntentDataParser.parse(url)).isNull()
}
@Test
fun `data with no scheme returns null`() {
val url = "test"
assertThat(CallIntentDataParser.parse(url)).isNull()
}
@Test
fun `Element Call urls will be returned as is`() {
val httpBaseUrl = "http://call.element.io"
val httpCallUrl = "http://call.element.io/some-actual-call?with=parameters"
val httpsBaseUrl = "https://call.element.io"
val httpsCallUrl = "https://call.element.io/some-actual-call?with=parameters"
assertThat(CallIntentDataParser.parse(httpBaseUrl)).isEqualTo(httpBaseUrl)
assertThat(CallIntentDataParser.parse(httpCallUrl)).isEqualTo(httpCallUrl)
assertThat(CallIntentDataParser.parse(httpsBaseUrl)).isEqualTo(httpsBaseUrl)
assertThat(CallIntentDataParser.parse(httpsCallUrl)).isEqualTo(httpsCallUrl)
}
@Test
fun `HTTP and HTTPS urls that don't come from EC return null`() {
val httpBaseUrl = "http://app.element.io"
val httpsBaseUrl = "https://app.element.io"
val httpInvalidUrl = "http://"
val httpsInvalidUrl = "http://"
assertThat(CallIntentDataParser.parse(httpBaseUrl)).isNull()
assertThat(CallIntentDataParser.parse(httpsBaseUrl)).isNull()
assertThat(CallIntentDataParser.parse(httpInvalidUrl)).isNull()
assertThat(CallIntentDataParser.parse(httpsInvalidUrl)).isNull()
}
@Test
fun `element scheme with call host and url param gets url extracted`() {
val embeddedUrl = "http://call.element.io/some-actual-call?with=parameters"
val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8")
val url = "element://call?url=$encodedUrl"
assertThat(CallIntentDataParser.parse(url)).isEqualTo(embeddedUrl)
}
@Test
fun `element scheme with call host and no url param returns null`() {
val embeddedUrl = "http://call.element.io/some-actual-call?with=parameters"
val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8")
val url = "element://call?no-url=$encodedUrl"
assertThat(CallIntentDataParser.parse(url)).isNull()
}
@Test
fun `element scheme with no call host returns null`() {
val embeddedUrl = "http://call.element.io/some-actual-call?with=parameters"
val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8")
val url = "element://no-call?url=$encodedUrl"
assertThat(CallIntentDataParser.parse(url)).isNull()
}
@Test
fun `element scheme with no data returns null`() {
val url = "element://call?url="
assertThat(CallIntentDataParser.parse(url)).isNull()
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.call
import android.Manifest
import android.webkit.PermissionRequest
import com.google.common.truth.Truth.assertThat
import org.junit.Test
class MapWebkitPermissionsTest {
@Test
fun `given Webkit's RESOURCE_AUDIO_CAPTURE returns Android's RECORD_AUDIO permission`() {
val permission = mapWebkitPermissions(arrayOf(PermissionRequest.RESOURCE_AUDIO_CAPTURE))
assertThat(permission).isEqualTo(listOf(Manifest.permission.RECORD_AUDIO))
}
@Test
fun `given Webkit's RESOURCE_VIDEO_CAPTURE returns Android's CAMERA permission`() {
val permission = mapWebkitPermissions(arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE))
assertThat(permission).isEqualTo(listOf(Manifest.permission.CAMERA))
}
@Test
fun `given any other permission, it returns nothing`() {
val permission = mapWebkitPermissions(arrayOf(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID))
assertThat(permission).isEqualTo(emptyList<String>())
}
}

View File

@@ -91,6 +91,7 @@ androidx_activity_activity = { module = "androidx.activity:activity", version.re
androidx_activity_compose = { module = "androidx.activity:activity-compose", version.ref = "activity" }
androidx_startup = { module = "androidx.startup:startup-runtime", version.ref = "startup" }
androidx_preference = "androidx.preference:preference:1.2.1"
androidx_webkit = "androidx.webkit:webkit:1.8.0"
androidx_compose_bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose_bom" }
# Warning: issue on alpha07, make sure this is working when upgrading

View File

@@ -44,4 +44,6 @@ object VectorIcons {
val Mention = R.drawable.ic_mention
val Mute = R.drawable.ic_mute
val ThreadDecoration = R.drawable.ic_thread_decoration
val Plus = R.drawable.ic_plus
val Cancel = R.drawable.ic_cancel
}

View File

@@ -75,6 +75,16 @@ val SemanticColors.progressIndicatorTrackColor
Color(0x25F4F7FA)
}
// This color is not present in Semantic color, so put hard-coded value for now
val SemanticColors.iconSuccessPrimaryBackground
get() = if (isLight) {
// We want LightDesignTokens.colorGreen300
Color(0xffe3f7ed)
} else {
// We want DarkDesignTokens.colorGreen300
Color(0xff002513)
}
// Temporary color, which is not in the token right now
val SemanticColors.temporaryColorBgSpecial
get() = if (isLight) Color(0xFFE4E8F0) else Color(0xFF3A4048)
@@ -102,6 +112,7 @@ private fun ContentToPreview() {
"messageFromOtherBackground" to ElementTheme.colors.messageFromOtherBackground,
"progressIndicatorTrackColor" to ElementTheme.colors.progressIndicatorTrackColor,
"temporaryColorBgSpecial" to ElementTheme.colors.temporaryColorBgSpecial,
"iconSuccessPrimaryBackground" to ElementTheme.colors.iconSuccessPrimaryBackground,
)
)
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.utils
import io.element.android.libraries.designsystem.R
typealias CommonDrawables = R.drawable

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M8.8,19C8.25,19 7.779,18.804 7.388,18.413C6.996,18.021 6.8,17.55 6.8,17V7C6.8,6.45 6.996,5.979 7.388,5.588C7.779,5.196 8.25,5 8.8,5H12.325C13.408,5 14.408,5.333 15.325,6C16.242,6.667 16.7,7.592 16.7,8.775C16.7,9.625 16.508,10.279 16.125,10.738C15.742,11.196 15.383,11.525 15.05,11.725C15.467,11.908 15.929,12.25 16.438,12.75C16.946,13.25 17.2,14 17.2,15C17.2,16.483 16.658,17.521 15.575,18.112C14.492,18.704 13.475,19 12.525,19H8.8ZM9.825,16.2H12.425C13.225,16.2 13.712,15.996 13.887,15.587C14.063,15.179 14.15,14.883 14.15,14.7C14.15,14.517 14.063,14.221 13.887,13.813C13.712,13.404 13.2,13.2 12.35,13.2H9.825V16.2ZM9.825,10.5H12.15C12.7,10.5 13.1,10.358 13.35,10.075C13.6,9.792 13.725,9.475 13.725,9.125C13.725,8.725 13.583,8.4 13.3,8.15C13.017,7.9 12.65,7.775 12.2,7.775H9.825V10.5Z"
android:pathData="M7.333,15.833C6.875,15.833 6.483,15.67 6.156,15.343C5.83,15.017 5.667,14.624 5.667,14.166V5.833C5.667,5.374 5.83,4.982 6.156,4.656C6.483,4.329 6.875,4.166 7.333,4.166H10.271C11.174,4.166 12.007,4.444 12.771,4.999C13.535,5.555 13.917,6.326 13.917,7.312C13.917,8.02 13.757,8.565 13.438,8.947C13.118,9.329 12.819,9.604 12.542,9.77C12.889,9.923 13.274,10.208 13.698,10.624C14.122,11.041 14.333,11.666 14.333,12.499C14.333,13.736 13.882,14.6 12.979,15.093C12.076,15.586 11.229,15.833 10.438,15.833H7.333ZM8.188,13.499H10.354C11.021,13.499 11.427,13.329 11.573,12.989C11.719,12.649 11.792,12.402 11.792,12.249C11.792,12.097 11.719,11.85 11.573,11.51C11.427,11.17 11,10.999 10.292,10.999H8.188V13.499ZM8.188,8.749H10.125C10.583,8.749 10.917,8.631 11.125,8.395C11.333,8.159 11.438,7.895 11.438,7.604C11.438,7.27 11.319,6.999 11.083,6.791C10.847,6.583 10.542,6.479 10.167,6.479H8.188V8.749Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M10,19C9.717,19 9.479,18.904 9.288,18.712C9.096,18.521 9,18.283 9,18C9,17.717 9.096,17.479 9.288,17.288C9.479,17.096 9.717,17 10,17H20C20.283,17 20.521,17.096 20.712,17.288C20.904,17.479 21,17.717 21,18C21,18.283 20.904,18.521 20.712,18.712C20.521,18.904 20.283,19 20,19H10ZM10,13C9.717,13 9.479,12.904 9.288,12.712C9.096,12.521 9,12.283 9,12C9,11.717 9.096,11.479 9.288,11.288C9.479,11.096 9.717,11 10,11H20C20.283,11 20.521,11.096 20.712,11.288C20.904,11.479 21,11.717 21,12C21,12.283 20.904,12.521 20.712,12.712C20.521,12.904 20.283,13 20,13H10ZM10,7C9.717,7 9.479,6.904 9.288,6.713C9.096,6.521 9,6.283 9,6C9,5.717 9.096,5.479 9.288,5.287C9.479,5.096 9.717,5 10,5H20C20.283,5 20.521,5.096 20.712,5.287C20.904,5.479 21,5.717 21,6C21,6.283 20.904,6.521 20.712,6.713C20.521,6.904 20.283,7 20,7H10ZM5,20C4.45,20 3.979,19.804 3.588,19.413C3.196,19.021 3,18.55 3,18C3,17.45 3.196,16.979 3.588,16.587C3.979,16.196 4.45,16 5,16C5.55,16 6.021,16.196 6.412,16.587C6.804,16.979 7,17.45 7,18C7,18.55 6.804,19.021 6.412,19.413C6.021,19.804 5.55,20 5,20ZM5,14C4.45,14 3.979,13.804 3.588,13.413C3.196,13.021 3,12.55 3,12C3,11.45 3.196,10.979 3.588,10.587C3.979,10.196 4.45,10 5,10C5.55,10 6.021,10.196 6.412,10.587C6.804,10.979 7,11.45 7,12C7,12.55 6.804,13.021 6.412,13.413C6.021,13.804 5.55,14 5,14ZM5,8C4.45,8 3.979,7.804 3.588,7.412C3.196,7.021 3,6.55 3,6C3,5.45 3.196,4.979 3.588,4.588C3.979,4.196 4.45,4 5,4C5.55,4 6.021,4.196 6.412,4.588C6.804,4.979 7,5.45 7,6C7,6.55 6.804,7.021 6.412,7.412C6.021,7.804 5.55,8 5,8Z"
android:pathData="M8.333,15.834C8.097,15.834 7.899,15.754 7.74,15.594C7.58,15.435 7.5,15.237 7.5,15.001C7.5,14.764 7.58,14.567 7.74,14.407C7.899,14.247 8.097,14.167 8.333,14.167H16.667C16.903,14.167 17.101,14.247 17.26,14.407C17.42,14.567 17.5,14.764 17.5,15.001C17.5,15.237 17.42,15.435 17.26,15.594C17.101,15.754 16.903,15.834 16.667,15.834H8.333ZM8.333,10.834C8.097,10.834 7.899,10.754 7.74,10.594C7.58,10.435 7.5,10.237 7.5,10.001C7.5,9.765 7.58,9.567 7.74,9.407C7.899,9.247 8.097,9.167 8.333,9.167H16.667C16.903,9.167 17.101,9.247 17.26,9.407C17.42,9.567 17.5,9.765 17.5,10.001C17.5,10.237 17.42,10.435 17.26,10.594C17.101,10.754 16.903,10.834 16.667,10.834H8.333ZM8.333,5.834C8.097,5.834 7.899,5.754 7.74,5.594C7.58,5.435 7.5,5.237 7.5,5.001C7.5,4.765 7.58,4.567 7.74,4.407C7.899,4.247 8.097,4.167 8.333,4.167H16.667C16.903,4.167 17.101,4.247 17.26,4.407C17.42,4.567 17.5,4.765 17.5,5.001C17.5,5.237 17.42,5.435 17.26,5.594C17.101,5.754 16.903,5.834 16.667,5.834H8.333ZM4.167,16.667C3.708,16.667 3.316,16.504 2.99,16.178C2.663,15.851 2.5,15.459 2.5,15.001C2.5,14.542 2.663,14.15 2.99,13.824C3.316,13.497 3.708,13.334 4.167,13.334C4.625,13.334 5.017,13.497 5.344,13.824C5.67,14.15 5.833,14.542 5.833,15.001C5.833,15.459 5.67,15.851 5.344,16.178C5.017,16.504 4.625,16.667 4.167,16.667ZM4.167,11.667C3.708,11.667 3.316,11.504 2.99,11.178C2.663,10.851 2.5,10.459 2.5,10.001C2.5,9.542 2.663,9.15 2.99,8.824C3.316,8.497 3.708,8.334 4.167,8.334C4.625,8.334 5.017,8.497 5.344,8.824C5.67,9.15 5.833,9.542 5.833,10.001C5.833,10.459 5.67,10.851 5.344,11.178C5.017,11.504 4.625,11.667 4.167,11.667ZM4.167,6.667C3.708,6.667 3.316,6.504 2.99,6.178C2.663,5.851 2.5,5.459 2.5,5.001C2.5,4.542 2.663,4.15 2.99,3.824C3.316,3.497 3.708,3.334 4.167,3.334C4.625,3.334 5.017,3.497 5.344,3.824C5.67,4.15 5.833,4.542 5.833,5.001C5.833,5.459 5.67,5.851 5.344,6.178C5.017,6.504 4.625,6.667 4.167,6.667Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -0,0 +1,26 @@
<!--
~ Copyright (c) 2023 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="30dp"
android:height="30dp"
android:viewportWidth="30"
android:viewportHeight="30">
<path
android:pathData="M4.393,4.393C-1.464,10.251 -1.464,19.749 4.393,25.607C10.251,31.465 19.749,31.465 25.607,25.607C31.465,19.749 31.465,10.251 25.607,4.393C19.749,-1.464 10.251,-1.464 4.393,4.393ZM11.465,19.95L15,16.414L18.535,19.95C18.736,20.15 18.972,20.25 19.243,20.25C19.514,20.25 19.749,20.15 19.95,19.95C20.15,19.749 20.25,19.514 20.25,19.243C20.25,18.972 20.15,18.736 19.95,18.535L16.414,15L19.95,11.465C20.15,11.264 20.25,11.028 20.25,10.757C20.25,10.486 20.15,10.251 19.95,10.05C19.749,9.85 19.514,9.75 19.243,9.75C18.972,9.75 18.736,9.85 18.535,10.05L15,13.586L11.465,10.05C11.264,9.85 11.028,9.75 10.757,9.75C10.486,9.75 10.251,9.85 10.05,10.05C9.85,10.251 9.75,10.486 9.75,10.757C9.75,11.028 9.85,11.264 10.05,11.465L13.586,15L10.05,18.535C9.85,18.736 9.75,18.972 9.75,19.243C9.75,19.514 9.85,19.749 10.05,19.95C10.251,20.15 10.486,20.25 10.757,20.25C11.028,20.25 11.264,20.15 11.465,19.95Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M8.825,12L10.3,10.525C10.5,10.325 10.6,10.092 10.6,9.825C10.6,9.558 10.5,9.325 10.3,9.125C10.1,8.925 9.863,8.825 9.587,8.825C9.313,8.825 9.075,8.925 8.875,9.125L6.7,11.3C6.6,11.4 6.529,11.508 6.488,11.625C6.446,11.742 6.425,11.867 6.425,12C6.425,12.133 6.446,12.258 6.488,12.375C6.529,12.492 6.6,12.6 6.7,12.7L8.875,14.875C9.075,15.075 9.313,15.175 9.587,15.175C9.863,15.175 10.1,15.075 10.3,14.875C10.5,14.675 10.6,14.442 10.6,14.175C10.6,13.908 10.5,13.675 10.3,13.475L8.825,12ZM15.175,12L13.7,13.475C13.5,13.675 13.4,13.908 13.4,14.175C13.4,14.442 13.5,14.675 13.7,14.875C13.9,15.075 14.137,15.175 14.413,15.175C14.688,15.175 14.925,15.075 15.125,14.875L17.3,12.7C17.4,12.6 17.471,12.492 17.513,12.375C17.554,12.258 17.575,12.133 17.575,12C17.575,11.867 17.554,11.742 17.513,11.625C17.471,11.508 17.4,11.4 17.3,11.3L15.125,9.125C15.025,9.025 14.913,8.95 14.788,8.9C14.663,8.85 14.538,8.825 14.413,8.825C14.288,8.825 14.163,8.85 14.038,8.9C13.913,8.95 13.8,9.025 13.7,9.125C13.5,9.325 13.4,9.558 13.4,9.825C13.4,10.092 13.5,10.325 13.7,10.525L15.175,12ZM5,21C4.45,21 3.979,20.804 3.588,20.413C3.196,20.021 3,19.55 3,19V5C3,4.45 3.196,3.979 3.588,3.588C3.979,3.196 4.45,3 5,3H19C19.55,3 20.021,3.196 20.413,3.588C20.804,3.979 21,4.45 21,5V19C21,19.55 20.804,20.021 20.413,20.413C20.021,20.804 19.55,21 19,21H5ZM5,19H19V5H5V19Z"
android:pathData="M7.354,10L8.583,8.771C8.75,8.604 8.833,8.41 8.833,8.188C8.833,7.965 8.75,7.771 8.583,7.604C8.417,7.438 8.219,7.354 7.99,7.354C7.76,7.354 7.563,7.438 7.396,7.604L5.583,9.417C5.5,9.5 5.441,9.59 5.406,9.688C5.372,9.785 5.354,9.889 5.354,10C5.354,10.111 5.372,10.215 5.406,10.313C5.441,10.41 5.5,10.5 5.583,10.583L7.396,12.396C7.563,12.563 7.76,12.646 7.99,12.646C8.219,12.646 8.417,12.563 8.583,12.396C8.75,12.229 8.833,12.035 8.833,11.813C8.833,11.59 8.75,11.396 8.583,11.229L7.354,10ZM12.646,10L11.417,11.229C11.25,11.396 11.167,11.59 11.167,11.813C11.167,12.035 11.25,12.229 11.417,12.396C11.583,12.563 11.781,12.646 12.01,12.646C12.24,12.646 12.438,12.563 12.604,12.396L14.417,10.583C14.5,10.5 14.559,10.41 14.594,10.313C14.628,10.215 14.646,10.111 14.646,10C14.646,9.889 14.628,9.785 14.594,9.688C14.559,9.59 14.5,9.5 14.417,9.417L12.604,7.604C12.521,7.521 12.427,7.458 12.323,7.417C12.219,7.375 12.115,7.354 12.01,7.354C11.906,7.354 11.802,7.375 11.698,7.417C11.594,7.458 11.5,7.521 11.417,7.604C11.25,7.771 11.167,7.965 11.167,8.188C11.167,8.41 11.25,8.604 11.417,8.771L12.646,10ZM4.167,17.5C3.708,17.5 3.316,17.337 2.99,17.01C2.663,16.684 2.5,16.292 2.5,15.833V4.167C2.5,3.708 2.663,3.316 2.99,2.99C3.316,2.663 3.708,2.5 4.167,2.5H15.833C16.292,2.5 16.684,2.663 17.01,2.99C17.337,3.316 17.5,3.708 17.5,4.167V15.833C17.5,16.292 17.337,16.684 17.01,17.01C16.684,17.337 16.292,17.5 15.833,17.5H4.167ZM4.167,15.833H15.833V4.167H4.167V15.833Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M4,21C3.717,21 3.479,20.904 3.287,20.712C3.096,20.521 3,20.283 3,20C3,19.717 3.096,19.479 3.287,19.288C3.479,19.096 3.717,19 4,19H20C20.283,19 20.521,19.096 20.712,19.288C20.904,19.479 21,19.717 21,20C21,20.283 20.904,20.521 20.712,20.712C20.521,20.904 20.283,21 20,21H4ZM12,17C11.717,17 11.479,16.904 11.288,16.712C11.096,16.521 11,16.283 11,16C11,15.717 11.096,15.479 11.288,15.288C11.479,15.096 11.717,15 12,15H20C20.283,15 20.521,15.096 20.712,15.288C20.904,15.479 21,15.717 21,16C21,16.283 20.904,16.521 20.712,16.712C20.521,16.904 20.283,17 20,17H12ZM12,13C11.717,13 11.479,12.904 11.288,12.712C11.096,12.521 11,12.283 11,12C11,11.717 11.096,11.479 11.288,11.288C11.479,11.096 11.717,11 12,11H20C20.283,11 20.521,11.096 20.712,11.288C20.904,11.479 21,11.717 21,12C21,12.283 20.904,12.521 20.712,12.712C20.521,12.904 20.283,13 20,13H12ZM12,9C11.717,9 11.479,8.904 11.288,8.712C11.096,8.521 11,8.283 11,8C11,7.717 11.096,7.479 11.288,7.287C11.479,7.096 11.717,7 12,7H20C20.283,7 20.521,7.096 20.712,7.287C20.904,7.479 21,7.717 21,8C21,8.283 20.904,8.521 20.712,8.712C20.521,8.904 20.283,9 20,9H12ZM4,5C3.717,5 3.479,4.904 3.287,4.713C3.096,4.521 3,4.283 3,4C3,3.717 3.096,3.479 3.287,3.287C3.479,3.096 3.717,3 4,3H20C20.283,3 20.521,3.096 20.712,3.287C20.904,3.479 21,3.717 21,4C21,4.283 20.904,4.521 20.712,4.713C20.521,4.904 20.283,5 20,5H4ZM6.15,15.15L3.35,12.35C3.25,12.25 3.2,12.133 3.2,12C3.2,11.867 3.25,11.75 3.35,11.65L6.15,8.85C6.317,8.683 6.5,8.642 6.7,8.725C6.9,8.808 7,8.967 7,9.2V14.8C7,15.033 6.9,15.192 6.7,15.275C6.5,15.358 6.317,15.317 6.15,15.15Z"
android:pathData="M3.333,17.5C3.097,17.5 2.899,17.42 2.74,17.26C2.58,17.101 2.5,16.903 2.5,16.667C2.5,16.431 2.58,16.233 2.74,16.073C2.899,15.913 3.097,15.833 3.333,15.833H16.667C16.903,15.833 17.101,15.913 17.26,16.073C17.42,16.233 17.5,16.431 17.5,16.667C17.5,16.903 17.42,17.101 17.26,17.26C17.101,17.42 16.903,17.5 16.667,17.5H3.333ZM10,14.167C9.764,14.167 9.566,14.087 9.406,13.927C9.247,13.767 9.167,13.569 9.167,13.333C9.167,13.097 9.247,12.899 9.406,12.74C9.566,12.58 9.764,12.5 10,12.5H16.667C16.903,12.5 17.101,12.58 17.26,12.74C17.42,12.899 17.5,13.097 17.5,13.333C17.5,13.569 17.42,13.767 17.26,13.927C17.101,14.087 16.903,14.167 16.667,14.167H10ZM10,10.833C9.764,10.833 9.566,10.753 9.406,10.594C9.247,10.434 9.167,10.236 9.167,10C9.167,9.764 9.247,9.566 9.406,9.406C9.566,9.247 9.764,9.167 10,9.167H16.667C16.903,9.167 17.101,9.247 17.26,9.406C17.42,9.566 17.5,9.764 17.5,10C17.5,10.236 17.42,10.434 17.26,10.594C17.101,10.753 16.903,10.833 16.667,10.833H10ZM10,7.5C9.764,7.5 9.566,7.42 9.406,7.26C9.247,7.101 9.167,6.903 9.167,6.667C9.167,6.431 9.247,6.233 9.406,6.073C9.566,5.913 9.764,5.833 10,5.833H16.667C16.903,5.833 17.101,5.913 17.26,6.073C17.42,6.233 17.5,6.431 17.5,6.667C17.5,6.903 17.42,7.101 17.26,7.26C17.101,7.42 16.903,7.5 16.667,7.5H10ZM3.333,4.167C3.097,4.167 2.899,4.087 2.74,3.927C2.58,3.767 2.5,3.569 2.5,3.333C2.5,3.097 2.58,2.899 2.74,2.74C2.899,2.58 3.097,2.5 3.333,2.5H16.667C16.903,2.5 17.101,2.58 17.26,2.74C17.42,2.899 17.5,3.097 17.5,3.333C17.5,3.569 17.42,3.767 17.26,3.927C17.101,4.087 16.903,4.167 16.667,4.167H3.333ZM5.125,12.625L2.792,10.292C2.708,10.208 2.667,10.111 2.667,10C2.667,9.889 2.708,9.792 2.792,9.708L5.125,7.375C5.264,7.236 5.417,7.201 5.583,7.271C5.75,7.34 5.833,7.472 5.833,7.667V12.333C5.833,12.528 5.75,12.66 5.583,12.729C5.417,12.799 5.264,12.764 5.125,12.625Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M4,21C3.717,21 3.479,20.904 3.287,20.712C3.096,20.521 3,20.283 3,20C3,19.717 3.096,19.479 3.287,19.288C3.479,19.096 3.717,19 4,19H20C20.283,19 20.521,19.096 20.712,19.288C20.904,19.479 21,19.717 21,20C21,20.283 20.904,20.521 20.712,20.712C20.521,20.904 20.283,21 20,21H4ZM12,17C11.717,17 11.479,16.904 11.288,16.712C11.096,16.521 11,16.283 11,16C11,15.717 11.096,15.479 11.288,15.288C11.479,15.096 11.717,15 12,15H20C20.283,15 20.521,15.096 20.712,15.288C20.904,15.479 21,15.717 21,16C21,16.283 20.904,16.521 20.712,16.712C20.521,16.904 20.283,17 20,17H12ZM12,13C11.717,13 11.479,12.904 11.288,12.712C11.096,12.521 11,12.283 11,12C11,11.717 11.096,11.479 11.288,11.288C11.479,11.096 11.717,11 12,11H20C20.283,11 20.521,11.096 20.712,11.288C20.904,11.479 21,11.717 21,12C21,12.283 20.904,12.521 20.712,12.712C20.521,12.904 20.283,13 20,13H12ZM12,9C11.717,9 11.479,8.904 11.288,8.712C11.096,8.521 11,8.283 11,8C11,7.717 11.096,7.479 11.288,7.287C11.479,7.096 11.717,7 12,7H20C20.283,7 20.521,7.096 20.712,7.287C20.904,7.479 21,7.717 21,8C21,8.283 20.904,8.521 20.712,8.712C20.521,8.904 20.283,9 20,9H12ZM4,5C3.717,5 3.479,4.904 3.287,4.713C3.096,4.521 3,4.283 3,4C3,3.717 3.096,3.479 3.287,3.287C3.479,3.096 3.717,3 4,3H20C20.283,3 20.521,3.096 20.712,3.287C20.904,3.479 21,3.717 21,4C21,4.283 20.904,4.521 20.712,4.713C20.521,4.904 20.283,5 20,5H4ZM3.85,15.15C3.683,15.317 3.5,15.358 3.3,15.275C3.1,15.192 3,15.033 3,14.8V9.2C3,8.967 3.1,8.808 3.3,8.725C3.5,8.642 3.683,8.683 3.85,8.85L6.65,11.65C6.75,11.75 6.8,11.867 6.8,12C6.8,12.133 6.75,12.25 6.65,12.35L3.85,15.15Z"
android:pathData="M3.333,17.5C3.097,17.5 2.899,17.42 2.74,17.26C2.58,17.101 2.5,16.903 2.5,16.667C2.5,16.431 2.58,16.233 2.74,16.073C2.899,15.913 3.097,15.833 3.333,15.833H16.667C16.903,15.833 17.101,15.913 17.26,16.073C17.42,16.233 17.5,16.431 17.5,16.667C17.5,16.903 17.42,17.101 17.26,17.26C17.101,17.42 16.903,17.5 16.667,17.5H3.333ZM10,14.167C9.764,14.167 9.566,14.087 9.406,13.927C9.247,13.767 9.167,13.569 9.167,13.333C9.167,13.097 9.247,12.899 9.406,12.74C9.566,12.58 9.764,12.5 10,12.5H16.667C16.903,12.5 17.101,12.58 17.26,12.74C17.42,12.899 17.5,13.097 17.5,13.333C17.5,13.569 17.42,13.767 17.26,13.927C17.101,14.087 16.903,14.167 16.667,14.167H10ZM10,10.833C9.764,10.833 9.566,10.753 9.406,10.594C9.247,10.434 9.167,10.236 9.167,10C9.167,9.764 9.247,9.566 9.406,9.406C9.566,9.247 9.764,9.167 10,9.167H16.667C16.903,9.167 17.101,9.247 17.26,9.406C17.42,9.566 17.5,9.764 17.5,10C17.5,10.236 17.42,10.434 17.26,10.594C17.101,10.753 16.903,10.833 16.667,10.833H10ZM10,7.5C9.764,7.5 9.566,7.42 9.406,7.26C9.247,7.101 9.167,6.903 9.167,6.667C9.167,6.431 9.247,6.233 9.406,6.073C9.566,5.913 9.764,5.833 10,5.833H16.667C16.903,5.833 17.101,5.913 17.26,6.073C17.42,6.233 17.5,6.431 17.5,6.667C17.5,6.903 17.42,7.101 17.26,7.26C17.101,7.42 16.903,7.5 16.667,7.5H10ZM3.333,4.167C3.097,4.167 2.899,4.087 2.74,3.927C2.58,3.767 2.5,3.569 2.5,3.333C2.5,3.097 2.58,2.899 2.74,2.74C2.899,2.58 3.097,2.5 3.333,2.5H16.667C16.903,2.5 17.101,2.58 17.26,2.74C17.42,2.899 17.5,3.097 17.5,3.333C17.5,3.569 17.42,3.767 17.26,3.927C17.101,4.087 16.903,4.167 16.667,4.167H3.333ZM3.208,12.625C3.069,12.764 2.917,12.799 2.75,12.729C2.583,12.66 2.5,12.528 2.5,12.333V7.667C2.5,7.472 2.583,7.34 2.75,7.271C2.917,7.201 3.069,7.236 3.208,7.375L5.542,9.708C5.625,9.792 5.667,9.889 5.667,10C5.667,10.111 5.625,10.208 5.542,10.292L3.208,12.625Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -1,15 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M14.958,5.621C15.116,5.092 14.816,4.534 14.287,4.375C13.758,4.217 13.201,4.517 13.042,5.046L9.042,18.379C8.883,18.908 9.184,19.466 9.713,19.625C10.242,19.783 10.799,19.483 10.958,18.954L14.958,5.621Z"
android:pathData="M12.465,4.684C12.597,4.244 12.347,3.779 11.906,3.647C11.465,3.514 11.001,3.765 10.868,4.205L7.535,15.316C7.403,15.757 7.653,16.222 8.094,16.354C8.535,16.486 8.999,16.236 9.131,15.795L12.465,4.684Z"
android:fillColor="#656D77"/>
<path
android:pathData="M5.974,7.232C5.549,6.878 4.919,6.936 4.565,7.36L1.232,11.36C0.923,11.731 0.923,12.269 1.232,12.64L4.565,16.64C4.919,17.065 5.549,17.122 5.974,16.768C6.398,16.415 6.455,15.784 6.102,15.36L3.302,12L6.102,8.64C6.455,8.216 6.398,7.585 5.974,7.232Z"
android:pathData="M4.978,6.027C4.624,5.732 4.099,5.78 3.804,6.134L1.026,9.467C0.769,9.776 0.769,10.225 1.026,10.534L3.804,13.867C4.099,14.221 4.624,14.269 4.978,13.974C5.331,13.679 5.379,13.154 5.085,12.8L2.751,10L5.085,7.201C5.379,6.847 5.331,6.322 4.978,6.027Z"
android:fillColor="#656D77"/>
<path
android:pathData="M18.027,7.232C18.451,6.878 19.081,6.936 19.435,7.36L22.768,11.36C23.077,11.731 23.077,12.269 22.768,12.64L19.435,16.64C19.081,17.065 18.451,17.122 18.027,16.768C17.602,16.415 17.545,15.784 17.898,15.36L20.698,12L17.898,8.64C17.545,8.216 17.602,7.585 18.027,7.232Z"
android:pathData="M15.022,6.027C15.375,5.732 15.901,5.78 16.196,6.134L18.973,9.467C19.231,9.776 19.231,10.225 18.973,10.534L16.196,13.867C15.901,14.221 15.375,14.269 15.022,13.974C14.668,13.679 14.621,13.154 14.915,12.8L17.249,10L14.915,7.201C14.621,6.847 14.668,6.322 15.022,6.027Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M6.25,19C5.9,19 5.604,18.879 5.363,18.638C5.121,18.396 5,18.1 5,17.75C5,17.4 5.121,17.104 5.363,16.862C5.604,16.621 5.9,16.5 6.25,16.5H9L12,7.5H9.25C8.9,7.5 8.604,7.379 8.363,7.137C8.121,6.896 8,6.6 8,6.25C8,5.9 8.121,5.604 8.363,5.363C8.604,5.121 8.9,5 9.25,5H16.75C17.1,5 17.396,5.121 17.638,5.363C17.879,5.604 18,5.9 18,6.25C18,6.6 17.879,6.896 17.638,7.137C17.396,7.379 17.1,7.5 16.75,7.5H14.5L11.5,16.5H13.75C14.1,16.5 14.396,16.621 14.637,16.862C14.879,17.104 15,17.4 15,17.75C15,18.1 14.879,18.396 14.637,18.638C14.396,18.879 14.1,19 13.75,19H6.25Z"
android:pathData="M5.208,15.833C4.917,15.833 4.67,15.732 4.469,15.531C4.267,15.329 4.167,15.083 4.167,14.791C4.167,14.499 4.267,14.253 4.469,14.051C4.67,13.85 4.917,13.749 5.208,13.749H7.5L10,6.249H7.708C7.417,6.249 7.17,6.149 6.969,5.947C6.767,5.746 6.667,5.499 6.667,5.208C6.667,4.916 6.767,4.669 6.969,4.468C7.17,4.267 7.417,4.166 7.708,4.166H13.958C14.25,4.166 14.497,4.267 14.698,4.468C14.899,4.669 15,4.916 15,5.208C15,5.499 14.899,5.746 14.698,5.947C14.497,6.149 14.25,6.249 13.958,6.249H12.083L9.583,13.749H11.458C11.75,13.749 11.997,13.85 12.198,14.051C12.399,14.253 12.5,14.499 12.5,14.791C12.5,15.083 12.399,15.329 12.198,15.531C11.997,15.732 11.75,15.833 11.458,15.833H5.208Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M12,19.071C11.022,20.049 9.843,20.538 8.464,20.538C7.086,20.538 5.907,20.049 4.929,19.071C3.951,18.093 3.462,16.914 3.462,15.536C3.462,14.157 3.951,12.978 4.929,12L7.05,9.879C7.251,9.678 7.486,9.578 7.757,9.578C8.028,9.578 8.264,9.678 8.464,9.879C8.665,10.079 8.765,10.315 8.765,10.586C8.765,10.857 8.665,11.093 8.464,11.293L6.343,13.414C5.754,14.003 5.459,14.711 5.459,15.536C5.459,16.361 5.754,17.068 6.343,17.657C6.932,18.246 7.639,18.541 8.464,18.541C9.289,18.541 9.997,18.246 10.586,17.657L12.707,15.536C12.907,15.335 13.143,15.235 13.414,15.235C13.685,15.235 13.921,15.335 14.121,15.536C14.322,15.736 14.422,15.972 14.422,16.243C14.422,16.514 14.322,16.749 14.121,16.95L12,19.071ZM10.586,14.828C10.385,15.029 10.15,15.129 9.879,15.129C9.608,15.129 9.372,15.029 9.172,14.828C8.971,14.628 8.871,14.392 8.871,14.121C8.871,13.85 8.971,13.615 9.172,13.414L13.414,9.172C13.615,8.971 13.85,8.871 14.121,8.871C14.392,8.871 14.628,8.971 14.828,9.172C15.029,9.372 15.129,9.608 15.129,9.879C15.129,10.15 15.029,10.385 14.828,10.586L10.586,14.828ZM16.95,14.121C16.749,14.322 16.514,14.422 16.243,14.422C15.972,14.422 15.736,14.322 15.535,14.121C15.335,13.921 15.235,13.685 15.235,13.414C15.235,13.143 15.335,12.908 15.535,12.707L17.657,10.586C18.246,9.997 18.541,9.289 18.541,8.465C18.541,7.64 18.246,6.932 17.657,6.343C17.068,5.754 16.361,5.459 15.535,5.459C14.711,5.459 14.003,5.754 13.414,6.343L11.293,8.465C11.092,8.665 10.857,8.765 10.586,8.765C10.315,8.765 10.079,8.665 9.879,8.465C9.678,8.264 9.578,8.028 9.578,7.757C9.578,7.486 9.678,7.251 9.879,7.05L12,4.929C12.978,3.951 14.157,3.462 15.535,3.462C16.914,3.462 18.093,3.951 19.071,4.929C20.049,5.907 20.538,7.086 20.538,8.465C20.538,9.843 20.049,11.022 19.071,12L16.95,14.121Z"
android:pathData="M10,15.893C9.185,16.708 8.203,17.115 7.054,17.115C5.905,17.115 4.923,16.708 4.107,15.893C3.292,15.077 2.885,14.095 2.885,12.946C2.885,11.797 3.292,10.815 4.107,10L5.875,8.232C6.042,8.065 6.239,7.982 6.464,7.982C6.69,7.982 6.887,8.065 7.054,8.232C7.221,8.399 7.304,8.596 7.304,8.822C7.304,9.047 7.221,9.244 7.054,9.411L5.286,11.179C4.795,11.67 4.549,12.259 4.549,12.946C4.549,13.634 4.795,14.223 5.286,14.714C5.777,15.205 6.366,15.451 7.054,15.451C7.741,15.451 8.33,15.205 8.822,14.714L10.589,12.946C10.756,12.779 10.953,12.696 11.179,12.696C11.404,12.696 11.601,12.779 11.768,12.946C11.935,13.113 12.018,13.31 12.018,13.536C12.018,13.761 11.935,13.958 11.768,14.125L10,15.893ZM8.822,12.357C8.655,12.524 8.458,12.608 8.232,12.608C8.006,12.608 7.81,12.524 7.643,12.357C7.476,12.19 7.393,11.994 7.393,11.768C7.393,11.542 7.476,11.345 7.643,11.179L11.179,7.643C11.345,7.476 11.542,7.393 11.768,7.393C11.994,7.393 12.19,7.476 12.357,7.643C12.524,7.81 12.608,8.006 12.608,8.232C12.608,8.458 12.524,8.655 12.357,8.822L8.822,12.357ZM14.125,11.768C13.958,11.935 13.761,12.018 13.536,12.018C13.31,12.018 13.113,11.935 12.946,11.768C12.779,11.601 12.696,11.404 12.696,11.179C12.696,10.953 12.779,10.756 12.946,10.589L14.714,8.822C15.205,8.33 15.451,7.741 15.451,7.054C15.451,6.366 15.205,5.777 14.714,5.286C14.223,4.795 13.634,4.549 12.946,4.549C12.259,4.549 11.67,4.795 11.179,5.286L9.411,7.054C9.244,7.221 9.047,7.304 8.822,7.304C8.596,7.304 8.399,7.221 8.232,7.054C8.065,6.887 7.982,6.69 7.982,6.464C7.982,6.239 8.065,6.042 8.232,5.875L10,4.107C10.815,3.292 11.797,2.885 12.946,2.885C14.095,2.885 15.077,3.292 15.893,4.107C16.708,4.923 17.115,5.905 17.115,7.054C17.115,8.203 16.708,9.185 15.893,10L14.125,11.768Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -0,0 +1,7 @@
<vector android:height="32dp" android:viewportHeight="54"
android:viewportWidth="54" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:pathData="M19.4,3.2C19.4,1.5 20.9,0 22.7,0C34.6,0 44.3,9.7 44.3,21.6C44.3,23.4 42.8,24.8 41,24.8C39.3,24.8 37.8,23.4 37.8,21.6C37.8,13.3 31,6.5 22.7,6.5C20.9,6.5 19.4,5 19.4,3.2Z"/>
<path android:fillColor="#000000" android:pathData="M34.6,50.8C34.6,52.6 33.1,54 31.3,54C19.4,54 9.7,44.3 9.7,32.4C9.7,30.6 11.2,29.2 13,29.2C14.8,29.2 16.2,30.6 16.2,32.4C16.2,40.8 23,47.5 31.3,47.5C33.1,47.5 34.6,49 34.6,50.8Z"/>
<path android:fillColor="#000000" android:pathData="M3.2,34.6C1.5,34.6 -0,33.1 -0,31.3C-0,19.4 9.7,9.7 21.6,9.7C23.4,9.7 24.8,11.2 24.8,13C24.8,14.8 23.4,16.2 21.6,16.2C13.3,16.2 6.5,23 6.5,31.3C6.5,33.1 5,34.6 3.2,34.6Z"/>
<path android:fillColor="#000000" android:pathData="M50.8,19.4C52.6,19.4 54,20.9 54,22.7C54,34.6 44.3,44.3 32.4,44.3C30.6,44.3 29.2,42.8 29.2,41C29.2,39.3 30.6,37.8 32.4,37.8C40.8,37.8 47.5,31 47.5,22.7C47.5,20.9 49,19.4 50.8,19.4Z"/>
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M3.75,22C3.533,22 3.354,21.929 3.213,21.788C3.071,21.646 3,21.467 3,21.25C3,21.033 3.071,20.854 3.213,20.712C3.354,20.571 3.533,20.5 3.75,20.5H5.5V19.75H4.75C4.533,19.75 4.354,19.679 4.213,19.538C4.071,19.396 4,19.217 4,19C4,18.783 4.071,18.604 4.213,18.462C4.354,18.321 4.533,18.25 4.75,18.25H5.5V17.5H3.75C3.533,17.5 3.354,17.429 3.213,17.288C3.071,17.146 3,16.967 3,16.75C3,16.533 3.071,16.354 3.213,16.212C3.354,16.071 3.533,16 3.75,16H6C6.283,16 6.521,16.096 6.713,16.288C6.904,16.479 7,16.717 7,17V18C7,18.283 6.904,18.521 6.713,18.712C6.521,18.904 6.283,19 6,19C6.283,19 6.521,19.096 6.713,19.288C6.904,19.479 7,19.717 7,20V21C7,21.283 6.904,21.521 6.713,21.712C6.521,21.904 6.283,22 6,22H3.75ZM3.75,15C3.533,15 3.354,14.929 3.213,14.788C3.071,14.646 3,14.467 3,14.25V12.25C3,11.967 3.096,11.729 3.287,11.538C3.479,11.346 3.717,11.25 4,11.25H5.5V10.5H3.75C3.533,10.5 3.354,10.429 3.213,10.288C3.071,10.146 3,9.967 3,9.75C3,9.533 3.071,9.354 3.213,9.212C3.354,9.071 3.533,9 3.75,9H6C6.283,9 6.521,9.096 6.713,9.288C6.904,9.479 7,9.717 7,10V11.75C7,12.033 6.904,12.271 6.713,12.462C6.521,12.654 6.283,12.75 6,12.75H4.5V13.5H6.25C6.467,13.5 6.646,13.571 6.787,13.712C6.929,13.854 7,14.033 7,14.25C7,14.467 6.929,14.646 6.787,14.788C6.646,14.929 6.467,15 6.25,15H3.75ZM5.25,8C5.033,8 4.854,7.929 4.713,7.787C4.571,7.646 4.5,7.467 4.5,7.25V3.5H3.75C3.533,3.5 3.354,3.429 3.213,3.287C3.071,3.146 3,2.967 3,2.75C3,2.533 3.071,2.354 3.213,2.213C3.354,2.071 3.533,2 3.75,2H5.25C5.467,2 5.646,2.071 5.787,2.213C5.929,2.354 6,2.533 6,2.75V7.25C6,7.467 5.929,7.646 5.787,7.787C5.646,7.929 5.467,8 5.25,8ZM10,19C9.717,19 9.479,18.904 9.288,18.712C9.096,18.521 9,18.283 9,18C9,17.717 9.096,17.479 9.288,17.288C9.479,17.096 9.717,17 10,17H20C20.283,17 20.521,17.096 20.712,17.288C20.904,17.479 21,17.717 21,18C21,18.283 20.904,18.521 20.712,18.712C20.521,18.904 20.283,19 20,19H10ZM10,13C9.717,13 9.479,12.904 9.288,12.712C9.096,12.521 9,12.283 9,12C9,11.717 9.096,11.479 9.288,11.288C9.479,11.096 9.717,11 10,11H20C20.283,11 20.521,11.096 20.712,11.288C20.904,11.479 21,11.717 21,12C21,12.283 20.904,12.521 20.712,12.712C20.521,12.904 20.283,13 20,13H10ZM10,7C9.717,7 9.479,6.904 9.288,6.713C9.096,6.521 9,6.283 9,6C9,5.717 9.096,5.479 9.288,5.287C9.479,5.096 9.717,5 10,5H20C20.283,5 20.521,5.096 20.712,5.287C20.904,5.479 21,5.717 21,6C21,6.283 20.904,6.521 20.712,6.713C20.521,6.904 20.283,7 20,7H10Z"
android:pathData="M3.125,18.333C2.944,18.333 2.795,18.274 2.677,18.156C2.559,18.038 2.5,17.888 2.5,17.708C2.5,17.527 2.559,17.378 2.677,17.26C2.795,17.142 2.944,17.083 3.125,17.083H4.583V16.458H3.958C3.778,16.458 3.628,16.399 3.51,16.281C3.392,16.163 3.333,16.013 3.333,15.833C3.333,15.652 3.392,15.503 3.51,15.385C3.628,15.267 3.778,15.208 3.958,15.208H4.583V14.583H3.125C2.944,14.583 2.795,14.524 2.677,14.406C2.559,14.288 2.5,14.138 2.5,13.958C2.5,13.777 2.559,13.628 2.677,13.51C2.795,13.392 2.944,13.333 3.125,13.333H5C5.236,13.333 5.434,13.413 5.594,13.572C5.753,13.732 5.833,13.93 5.833,14.166V14.999C5.833,15.236 5.753,15.433 5.594,15.593C5.434,15.753 5.236,15.833 5,15.833C5.236,15.833 5.434,15.913 5.594,16.072C5.753,16.232 5.833,16.43 5.833,16.666V17.499C5.833,17.736 5.753,17.933 5.594,18.093C5.434,18.253 5.236,18.333 5,18.333H3.125ZM3.125,12.499C2.944,12.499 2.795,12.44 2.677,12.322C2.559,12.204 2.5,12.055 2.5,11.874V10.208C2.5,9.972 2.58,9.774 2.74,9.614C2.899,9.454 3.097,9.374 3.333,9.374H4.583V8.749H3.125C2.944,8.749 2.795,8.69 2.677,8.572C2.559,8.454 2.5,8.305 2.5,8.124C2.5,7.944 2.559,7.794 2.677,7.676C2.795,7.558 2.944,7.499 3.125,7.499H5C5.236,7.499 5.434,7.579 5.594,7.739C5.753,7.899 5.833,8.097 5.833,8.333V9.791C5.833,10.027 5.753,10.225 5.594,10.385C5.434,10.545 5.236,10.624 5,10.624H3.75V11.249H5.208C5.389,11.249 5.538,11.308 5.656,11.426C5.774,11.545 5.833,11.694 5.833,11.874C5.833,12.055 5.774,12.204 5.656,12.322C5.538,12.44 5.389,12.499 5.208,12.499H3.125ZM4.375,6.666C4.194,6.666 4.045,6.607 3.927,6.489C3.809,6.371 3.75,6.222 3.75,6.041V2.916H3.125C2.944,2.916 2.795,2.857 2.677,2.739C2.559,2.621 2.5,2.472 2.5,2.291C2.5,2.11 2.559,1.961 2.677,1.843C2.795,1.725 2.944,1.666 3.125,1.666H4.375C4.556,1.666 4.705,1.725 4.823,1.843C4.941,1.961 5,2.11 5,2.291V6.041C5,6.222 4.941,6.371 4.823,6.489C4.705,6.607 4.556,6.666 4.375,6.666ZM8.333,15.833C8.097,15.833 7.899,15.753 7.74,15.593C7.58,15.433 7.5,15.236 7.5,14.999C7.5,14.763 7.58,14.565 7.74,14.406C7.899,14.246 8.097,14.166 8.333,14.166H16.667C16.903,14.166 17.101,14.246 17.26,14.406C17.42,14.565 17.5,14.763 17.5,14.999C17.5,15.236 17.42,15.433 17.26,15.593C17.101,15.753 16.903,15.833 16.667,15.833H8.333ZM8.333,10.833C8.097,10.833 7.899,10.753 7.74,10.593C7.58,10.433 7.5,10.236 7.5,9.999C7.5,9.763 7.58,9.565 7.74,9.406C7.899,9.246 8.097,9.166 8.333,9.166H16.667C16.903,9.166 17.101,9.246 17.26,9.406C17.42,9.565 17.5,9.763 17.5,9.999C17.5,10.236 17.42,10.433 17.26,10.593C17.101,10.753 16.903,10.833 16.667,10.833H8.333ZM8.333,5.833C8.097,5.833 7.899,5.753 7.74,5.593C7.58,5.433 7.5,5.235 7.5,4.999C7.5,4.763 7.58,4.565 7.74,4.406C7.899,4.246 8.097,4.166 8.333,4.166H16.667C16.903,4.166 17.101,4.246 17.26,4.406C17.42,4.565 17.5,4.763 17.5,4.999C17.5,5.235 17.42,5.433 17.26,5.593C17.101,5.753 16.903,5.833 16.667,5.833H8.333Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -0,0 +1,29 @@
<!--
~ Copyright (c) 2023 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="30dp"
android:height="30dp"
android:viewportWidth="30"
android:viewportHeight="30">
<path
android:pathData="M0,15C0,23.284 6.716,30 15,30C23.284,30 30,23.284 30,15C30,6.716 23.284,0 15,0C6.716,0 0,6.716 0,15ZM16,21V16H21C21.283,16 21.521,15.904 21.712,15.712C21.904,15.521 22,15.283 22,15C22,14.717 21.904,14.479 21.712,14.288C21.521,14.096 21.283,14 21,14H16V9C16,8.717 15.904,8.479 15.712,8.288C15.521,8.096 15.283,8 15,8C14.717,8 14.479,8.096 14.288,8.288C14.096,8.479 14,8.717 14,9L14,14L9,14C8.717,14 8.479,14.096 8.288,14.288C8.096,14.479 8,14.717 8,15C8,15.283 8.096,15.521 8.288,15.712C8.479,15.904 8.717,16 9,16H14V21C14,21.283 14.096,21.521 14.288,21.712C14.479,21.904 14.717,22 15,22C15.283,22 15.521,21.904 15.712,21.712C15.904,21.521 16,21.283 16,21Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M14,16H9C8.717,16 8.479,15.904 8.288,15.712C8.096,15.521 8,15.283 8,15C8,14.717 8.096,14.479 8.288,14.288C8.479,14.096 8.717,14 9,14H14V9C14,8.717 14.096,8.479 14.288,8.288C14.479,8.096 14.717,8 15,8C15.283,8 15.521,8.096 15.712,8.288C15.904,8.479 16,8.717 16,9V14H21C21.283,14 21.521,14.096 21.712,14.288C21.904,14.479 22,14.717 22,15C22,15.283 21.904,15.521 21.712,15.712C21.521,15.904 21.283,16 21,16H16V21C16,21.283 15.904,21.521 15.712,21.712C15.521,21.904 15.283,22 15,22C14.717,22 14.479,21.904 14.288,21.712C14.096,21.521 14,21.283 14,21V16Z"
android:fillColor="#00000000"/>
</vector>

View File

@@ -1,18 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M4.719,4.34C4.813,3.698 4.353,3.104 3.691,3.012C3.028,2.92 2.415,3.366 2.32,4.008L1.512,9.486C1.418,10.128 1.878,10.723 2.54,10.814C3.203,10.906 3.816,10.46 3.911,9.818L4.719,4.34Z"
android:pathData="M3.932,3.617C4.011,3.082 3.628,2.586 3.076,2.51C2.524,2.434 2.012,2.805 1.933,3.34L1.26,7.905C1.181,8.44 1.565,8.936 2.117,9.012C2.669,9.088 3.18,8.717 3.259,8.182L3.932,3.617Z"
android:fillColor="#656D77"/>
<path
android:pathData="M16.834,14.514C16.928,13.872 16.468,13.277 15.806,13.186C15.144,13.094 14.53,13.54 14.435,14.182L13.627,19.66C13.533,20.302 13.993,20.896 14.656,20.988C15.318,21.08 15.932,20.634 16.026,19.992L16.834,14.514Z"
android:pathData="M14.028,12.095C14.107,11.56 13.724,11.064 13.172,10.988C12.62,10.912 12.108,11.283 12.029,11.818L11.356,16.383C11.277,16.918 11.661,17.414 12.213,17.49C12.765,17.566 13.276,17.195 13.355,16.66L14.028,12.095Z"
android:fillColor="#656D77"/>
<path
android:pathData="M9.318,3.009C9.983,3.086 10.456,3.671 10.376,4.315L10.354,4.49C10.34,4.602 10.319,4.763 10.293,4.961C10.242,5.358 10.17,5.902 10.088,6.496C9.927,7.667 9.72,9.075 9.553,9.882C9.422,10.518 8.784,10.931 8.128,10.803C7.472,10.676 7.046,10.058 7.177,9.422C7.326,8.701 7.523,7.37 7.687,6.185C7.767,5.599 7.838,5.061 7.889,4.669C7.915,4.473 7.935,4.314 7.949,4.204L7.97,4.034C8.05,3.39 8.654,2.931 9.318,3.009Z"
android:pathData="M7.765,2.507C8.319,2.572 8.713,3.059 8.647,3.596L8.628,3.742C8.616,3.835 8.599,3.969 8.578,4.134C8.535,4.465 8.475,4.919 8.407,5.413C8.272,6.389 8.1,7.562 7.961,8.235C7.852,8.765 7.32,9.109 6.773,9.003C6.226,8.897 5.872,8.381 5.981,7.852C6.105,7.251 6.269,6.142 6.406,5.154C6.473,4.666 6.532,4.217 6.574,3.891C6.595,3.727 6.612,3.595 6.624,3.503L6.642,3.362C6.709,2.825 7.212,2.442 7.765,2.507Z"
android:fillColor="#656D77"/>
<path
android:pathData="M22.488,14.514C22.582,13.872 22.122,13.277 21.46,13.186C20.797,13.094 20.184,13.54 20.089,14.182L19.281,19.66C19.187,20.302 19.647,20.896 20.309,20.988C20.972,21.08 21.585,20.634 21.68,19.992L22.488,14.514Z"
android:pathData="M18.74,12.095C18.819,11.56 18.435,11.064 17.883,10.988C17.331,10.912 16.82,11.283 16.741,11.818L16.068,16.383C15.989,16.918 16.372,17.414 16.924,17.49C17.476,17.566 17.988,17.195 18.067,16.66L18.74,12.095Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M12.15,20C10.883,20 9.758,19.625 8.775,18.875C7.792,18.125 7.083,17.1 6.65,15.8L8.85,14.85C9.083,15.65 9.488,16.308 10.063,16.825C10.637,17.342 11.35,17.6 12.2,17.6C12.9,17.6 13.533,17.433 14.1,17.1C14.667,16.767 14.95,16.233 14.95,15.5C14.95,15.2 14.892,14.925 14.775,14.675C14.658,14.425 14.5,14.2 14.3,14H17.1C17.183,14.233 17.246,14.471 17.288,14.712C17.329,14.954 17.35,15.217 17.35,15.5C17.35,16.933 16.837,18.042 15.813,18.825C14.788,19.608 13.567,20 12.15,20ZM3,12C2.717,12 2.479,11.904 2.287,11.712C2.096,11.521 2,11.283 2,11C2,10.717 2.096,10.479 2.287,10.288C2.479,10.096 2.717,10 3,10H21C21.283,10 21.521,10.096 21.712,10.288C21.904,10.479 22,10.717 22,11C22,11.283 21.904,11.521 21.712,11.712C21.521,11.904 21.283,12 21,12H3ZM12.05,3.85C13.15,3.85 14.113,4.121 14.938,4.662C15.762,5.204 16.4,6.033 16.85,7.15L14.65,8.125C14.5,7.642 14.221,7.208 13.813,6.825C13.404,6.442 12.833,6.25 12.1,6.25C11.417,6.25 10.85,6.404 10.4,6.713C9.95,7.021 9.7,7.45 9.65,8H7.25C7.283,6.85 7.738,5.871 8.613,5.063C9.488,4.254 10.633,3.85 12.05,3.85Z"
android:pathData="M10.125,16.665C9.07,16.665 8.132,16.353 7.313,15.728C6.493,15.103 5.903,14.249 5.542,13.165L7.375,12.374C7.57,13.04 7.906,13.589 8.385,14.019C8.865,14.45 9.458,14.665 10.167,14.665C10.75,14.665 11.278,14.526 11.75,14.249C12.222,13.971 12.458,13.526 12.458,12.915C12.458,12.665 12.41,12.436 12.313,12.228C12.215,12.019 12.083,11.832 11.917,11.665H14.25C14.319,11.86 14.372,12.058 14.406,12.259C14.441,12.46 14.458,12.679 14.458,12.915C14.458,14.11 14.031,15.033 13.177,15.686C12.323,16.339 11.306,16.665 10.125,16.665ZM2.5,9.999C2.264,9.999 2.066,9.919 1.906,9.759C1.747,9.599 1.667,9.401 1.667,9.165C1.667,8.929 1.747,8.731 1.906,8.572C2.066,8.412 2.264,8.332 2.5,8.332H17.5C17.736,8.332 17.934,8.412 18.094,8.572C18.254,8.731 18.333,8.929 18.333,9.165C18.333,9.401 18.254,9.599 18.094,9.759C17.934,9.919 17.736,9.999 17.5,9.999H2.5ZM10.042,3.207C10.958,3.207 11.76,3.433 12.448,3.884C13.135,4.335 13.667,5.026 14.042,5.957L12.208,6.77C12.083,6.367 11.851,6.006 11.51,5.686C11.17,5.367 10.694,5.207 10.083,5.207C9.514,5.207 9.042,5.335 8.667,5.592C8.292,5.849 8.083,6.207 8.042,6.665H6.042C6.07,5.707 6.448,4.891 7.177,4.217C7.906,3.544 8.861,3.207 10.042,3.207Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M6,21C5.717,21 5.479,20.904 5.287,20.712C5.096,20.521 5,20.283 5,20C5,19.717 5.096,19.479 5.287,19.288C5.479,19.096 5.717,19 6,19H18C18.283,19 18.521,19.096 18.712,19.288C18.904,19.479 19,19.717 19,20C19,20.283 18.904,20.521 18.712,20.712C18.521,20.904 18.283,21 18,21H6ZM12,17C10.317,17 9.008,16.475 8.075,15.425C7.142,14.375 6.675,12.983 6.675,11.25V4.275C6.675,3.925 6.804,3.625 7.063,3.375C7.321,3.125 7.625,3 7.975,3C8.325,3 8.625,3.125 8.875,3.375C9.125,3.625 9.25,3.925 9.25,4.275V11.4C9.25,12.333 9.483,13.092 9.95,13.675C10.417,14.258 11.1,14.55 12,14.55C12.9,14.55 13.583,14.258 14.05,13.675C14.517,13.092 14.75,12.333 14.75,11.4V4.275C14.75,3.925 14.879,3.625 15.137,3.375C15.396,3.125 15.7,3 16.05,3C16.4,3 16.7,3.125 16.95,3.375C17.2,3.625 17.325,3.925 17.325,4.275V11.25C17.325,12.983 16.858,14.375 15.925,15.425C14.992,16.475 13.683,17 12,17Z"
android:pathData="M5,17.5C4.764,17.5 4.566,17.42 4.406,17.26C4.247,17.101 4.167,16.903 4.167,16.667C4.167,16.431 4.247,16.233 4.406,16.073C4.566,15.913 4.764,15.833 5,15.833H15C15.236,15.833 15.434,15.913 15.594,16.073C15.754,16.233 15.833,16.431 15.833,16.667C15.833,16.903 15.754,17.101 15.594,17.26C15.434,17.42 15.236,17.5 15,17.5H5ZM10,14.167C8.597,14.167 7.507,13.729 6.729,12.854C5.951,11.979 5.563,10.819 5.563,9.375V3.563C5.563,3.271 5.67,3.021 5.885,2.813C6.101,2.604 6.354,2.5 6.646,2.5C6.938,2.5 7.188,2.604 7.396,2.813C7.604,3.021 7.708,3.271 7.708,3.563V9.5C7.708,10.278 7.903,10.91 8.292,11.396C8.681,11.882 9.25,12.125 10,12.125C10.75,12.125 11.319,11.882 11.708,11.396C12.097,10.91 12.292,10.278 12.292,9.5V3.563C12.292,3.271 12.399,3.021 12.615,2.813C12.83,2.604 13.083,2.5 13.375,2.5C13.667,2.5 13.917,2.604 14.125,2.813C14.333,3.021 14.438,3.271 14.438,3.563V9.375C14.438,10.819 14.049,11.979 13.271,12.854C12.493,13.729 11.403,14.167 10,14.167Z"
android:fillColor="#656D77"/>
</vector>

View File

@@ -38,6 +38,7 @@ dependencies {
implementation(projects.libraries.architecture)
implementation(projects.libraries.core)
implementation(projects.libraries.designsystem)
implementation(projects.libraries.di)
implementation(projects.libraries.androidutils)
implementation(projects.libraries.network)

View File

@@ -25,6 +25,7 @@ import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.designsystem.utils.CommonDrawables
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.user.MatrixUser
@@ -67,7 +68,7 @@ class NotificationFactory @Inject constructor(
else -> pendingIntentFactory.createOpenRoomPendingIntent(roomInfo.sessionId, roomInfo.roomId)
}
val smallIcon = R.drawable.ic_notification
val smallIcon = CommonDrawables.ic_notification_small
val channelId = notificationChannels.getChannelIdForMessage(roomInfo.shouldBing)
return NotificationCompat.Builder(context, channelId)
@@ -141,7 +142,7 @@ class NotificationFactory @Inject constructor(
inviteNotifiableEvent: InviteNotifiableEvent
): Notification {
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
val smallIcon = R.drawable.ic_notification
val smallIcon = CommonDrawables.ic_notification_small
val channelId = notificationChannels.getChannelIdForMessage(inviteNotifiableEvent.noisy)
return NotificationCompat.Builder(context, channelId)
.setOnlyAlertOnce(true)
@@ -185,7 +186,7 @@ class NotificationFactory @Inject constructor(
simpleNotifiableEvent: SimpleNotifiableEvent,
): Notification {
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
val smallIcon = R.drawable.ic_notification
val smallIcon = CommonDrawables.ic_notification_small
val channelId = notificationChannels.getChannelIdForMessage(simpleNotifiableEvent.noisy)
return NotificationCompat.Builder(context, channelId)
@@ -220,7 +221,7 @@ class NotificationFactory @Inject constructor(
fallbackNotifiableEvent: FallbackNotifiableEvent,
): Notification {
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
val smallIcon = R.drawable.ic_notification
val smallIcon = CommonDrawables.ic_notification_small
val channelId = notificationChannels.getChannelIdForMessage(false)
return NotificationCompat.Builder(context, channelId)
@@ -261,7 +262,7 @@ class NotificationFactory @Inject constructor(
lastMessageTimestamp: Long
): Notification {
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
val smallIcon = R.drawable.ic_notification
val smallIcon = CommonDrawables.ic_notification_small
val channelId = notificationChannels.getChannelIdForMessage(noisy)
return NotificationCompat.Builder(context, channelId)
.setOnlyAlertOnce(true)
@@ -301,7 +302,7 @@ class NotificationFactory @Inject constructor(
return NotificationCompat.Builder(context, notificationChannels.getChannelIdForTest())
.setContentTitle(buildMeta.applicationName)
.setContentText(stringProvider.getString(R.string.notification_test_push_notification_content))
.setSmallIcon(R.drawable.ic_notification)
.setSmallIcon(CommonDrawables.ic_notification_small)
.setLargeIcon(getBitmap(R.drawable.element_logo_green))
.setColor(ContextCompat.getColor(context, R.color.notification_accent_color))
.setPriority(NotificationCompat.PRIORITY_MAX)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -114,7 +114,7 @@ fun TextComposer(
start = 3.dp,
end = 6.dp,
top = 8.dp,
bottom = 5.dp,
bottom = 4.dp,
)
.fillMaxWidth(),
) {
@@ -137,7 +137,7 @@ fun TextComposer(
) {
Icon(
modifier = Modifier.size(30.dp.applyScaleUp()),
resourceId = R.drawable.ic_plus, // TODO Replace with design system icon when available
resourceId = VectorIcons.Plus,
contentDescription = stringResource(R.string.rich_text_editor_a11y_add_attachment),
tint = ElementTheme.colors.iconPrimary,
)
@@ -146,7 +146,7 @@ fun TextComposer(
val roundCornerLarge = 28.dp.applyScaleUp()
val roundedCornerSize = remember(state.lineCount, composerMode) {
if (state.lineCount > 1 || composerMode is MessageComposerMode.Special) {
if (composerMode is MessageComposerMode.Special) {
roundCornerSmall
} else {
roundCornerLarge
@@ -156,17 +156,13 @@ fun TextComposer(
targetValue = roundedCornerSize,
animationSpec = tween(
durationMillis = 100,
)
),
label = "roundedCornerSizeAnimation"
)
val roundedCorners = RoundedCornerShape(roundedCornerSizeState.value)
val colors = ElementTheme.colors
val bgColor = colors.bgSubtleSecondary
val borderColor by remember(state.hasFocus, colors) {
derivedStateOf {
if (state.hasFocus) colors.borderDisabled else bgColor
}
}
val borderColor = colors.borderDisabled
Column(
modifier = Modifier
@@ -180,7 +176,7 @@ fun TextComposer(
.fillMaxWidth()
.clip(roundedCorners)
.background(color = bgColor)
.border(1.dp, borderColor, roundedCorners)
.border(0.5.dp, borderColor, roundedCorners)
) {
if (composerMode is MessageComposerMode.Special) {
ComposerModeView(composerMode = composerMode, onResetComposerMode = onResetComposerMode)
@@ -272,7 +268,7 @@ private fun TextInput(
Text(
placeholder,
style = defaultTypography.copy(
color = ElementTheme.colors.textDisabled,
color = ElementTheme.colors.textSecondary,
),
)
}
@@ -280,6 +276,7 @@ private fun TextInput(
RichTextEditor(
state = state,
modifier = Modifier
.padding(top = 6.dp, bottom = 6.dp)
.fillMaxWidth(),
style = RichTextEditorDefaults.style(
text = RichTextEditorDefaults.textStyle(
@@ -323,7 +320,7 @@ private fun TextFormatting(
) {
Icon(
modifier = Modifier.size(30.dp.applyScaleUp()),
resourceId = R.drawable.ic_cancel, // TODO Replace with design system icon when available
resourceId = VectorIcons.Cancel,
contentDescription = stringResource(CommonStrings.action_close),
tint = ElementTheme.colors.iconPrimary,
)
@@ -335,8 +332,8 @@ private fun TextFormatting(
.constrainAs(formatting) {
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(close.end, margin = 3.dp)
end.linkTo(send.start, margin = 20.dp)
start.linkTo(close.end, margin = 1.dp)
end.linkTo(send.start, margin = 14.dp)
width = fillToConstraints
}
.horizontalScroll(scrollState),
@@ -589,7 +586,7 @@ private fun SendButton(
) {
Icon(
modifier = Modifier
.height(18.dp.applyScaleUp())
.height(24.dp.applyScaleUp())
.align(Alignment.Center),
resourceId = iconId,
contentDescription = contentDescription,

View File

@@ -18,17 +18,26 @@ package io.element.android.libraries.textcomposer.components
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.VectorIcons
import io.element.android.libraries.designsystem.preview.DayNightPreviews
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.text.applyScaleUp
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.iconSuccessPrimaryBackground
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.theme.compound.generated.SemanticColors
@@ -42,27 +51,65 @@ internal fun FormattingOption(
colors: SemanticColors = ElementTheme.colors,
) {
val backgroundColor = when (state) {
FormattingOptionState.Selected -> colors.bgActionPrimaryRest
FormattingOptionState.Selected -> colors.iconSuccessPrimaryBackground
FormattingOptionState.Default,
FormattingOptionState.Disabled -> Color.Transparent
}
val foregroundColor = when (state) {
FormattingOptionState.Selected -> colors.iconOnSolidPrimary
FormattingOptionState.Default -> colors.iconPrimary
FormattingOptionState.Selected -> colors.iconSuccessPrimary
FormattingOptionState.Default -> colors.iconSecondary
FormattingOptionState.Disabled -> colors.iconDisabled
}
Box(
modifier = modifier
.clickable { onClick() }
.size(44.dp.applyScaleUp())
.background(backgroundColor, shape = RoundedCornerShape(4.dp.applyScaleUp()))
.clickable(
onClick = onClick,
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(
bounded = false,
radius = 20.dp,
),
)
.size(48.dp.applyScaleUp())
) {
Icon(
modifier = Modifier.align(Alignment.Center),
imageVector = imageVector,
contentDescription = contentDescription,
tint = foregroundColor,
Box(
modifier = Modifier
.size(36.dp.applyScaleUp())
.align(Alignment.Center)
.background(backgroundColor, shape = RoundedCornerShape(8.dp.applyScaleUp()))
) {
Icon(
modifier = Modifier.align(Alignment.Center),
imageVector = imageVector,
contentDescription = contentDescription,
tint = foregroundColor,
)
}
}
}
@DayNightPreviews
@Composable
internal fun FormattingButtonPreview() = ElementPreview {
Row {
FormattingOption(
state = FormattingOptionState.Default,
onClick = { },
imageVector = ImageVector.vectorResource(VectorIcons.Bold),
contentDescription = "",
)
FormattingOption(
state = FormattingOptionState.Selected,
onClick = { },
imageVector = ImageVector.vectorResource(VectorIcons.Italic),
contentDescription = "",
)
FormattingOption(
state = FormattingOptionState.Disabled,
onClick = { },
imageVector = ImageVector.vectorResource(VectorIcons.Underline),
contentDescription = "",
)
}
}

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:pathData="M16,18.121L19.182,21.303C19.483,21.604 19.836,21.754 20.243,21.754C20.649,21.754 21.003,21.604 21.303,21.303C21.604,21.003 21.754,20.649 21.754,20.243C21.754,19.836 21.604,19.483 21.303,19.182L18.121,16L21.303,12.818C21.604,12.517 21.754,12.164 21.754,11.757C21.754,11.351 21.604,10.997 21.303,10.697C21.003,10.396 20.649,10.246 20.243,10.246C19.836,10.246 19.483,10.396 19.182,10.697L16,13.879L12.818,10.697C12.517,10.396 12.164,10.246 11.757,10.246C11.351,10.246 10.997,10.396 10.697,10.697C10.396,10.997 10.246,11.351 10.246,11.757C10.246,12.164 10.396,12.517 10.697,12.818L13.879,16L10.697,19.182C10.396,19.483 10.246,19.836 10.246,20.243C10.246,20.649 10.396,21.003 10.697,21.303C10.997,21.604 11.351,21.754 11.757,21.754C12.164,21.754 12.517,21.604 12.818,21.303L16,18.121ZM26.607,26.607C25.139,28.074 23.482,29.174 21.635,29.908C19.787,30.642 17.909,31.008 16,31.008C14.091,31.008 12.213,30.642 10.365,29.908C8.518,29.174 6.861,28.074 5.393,26.607C3.926,25.139 2.826,23.482 2.092,21.635C1.358,19.787 0.992,17.909 0.992,16C0.992,14.091 1.358,12.213 2.092,10.365C2.826,8.518 3.926,6.861 5.393,5.393C6.861,3.926 8.518,2.826 10.365,2.092C12.213,1.358 14.091,0.992 16,0.992C17.909,0.992 19.787,1.358 21.635,2.092C23.482,2.826 25.139,3.926 26.607,5.393C28.074,6.861 29.174,8.518 29.908,10.365C30.642,12.213 31.008,14.091 31.008,16C31.008,17.909 30.642,19.787 29.908,21.635C29.174,23.482 28.074,25.139 26.607,26.607Z"
android:fillColor="#1B1D22"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="30dp"
android:height="30dp"
android:viewportWidth="30"
android:viewportHeight="30">
<path
android:pathData="M13.5,16.5V21C13.5,21.425 13.644,21.781 13.931,22.069C14.219,22.356 14.575,22.5 15,22.5C15.425,22.5 15.781,22.356 16.069,22.069C16.356,21.781 16.5,21.425 16.5,21V16.5H21C21.425,16.5 21.781,16.356 22.069,16.069C22.356,15.781 22.5,15.425 22.5,15C22.5,14.575 22.356,14.219 22.069,13.931C21.781,13.644 21.425,13.5 21,13.5H16.5V9C16.5,8.575 16.356,8.219 16.069,7.931C15.781,7.644 15.425,7.5 15,7.5C14.575,7.5 14.219,7.644 13.931,7.931C13.644,8.219 13.5,8.575 13.5,9V13.5H9C8.575,13.5 8.219,13.644 7.931,13.931C7.644,14.219 7.5,14.575 7.5,15C7.5,15.425 7.644,15.781 7.931,16.069C8.219,16.356 8.575,16.5 9,16.5H13.5ZM15,30C12.925,30 10.975,29.606 9.15,28.819C7.325,28.031 5.738,26.962 4.387,25.612C3.037,24.263 1.969,22.675 1.181,20.85C0.394,19.025 0,17.075 0,15C0,12.925 0.394,10.975 1.181,9.15C1.969,7.325 3.037,5.738 4.387,4.387C5.738,3.037 7.325,1.969 9.15,1.181C10.975,0.394 12.925,0 15,0C17.075,0 19.025,0.394 20.85,1.181C22.675,1.969 24.263,3.037 25.612,4.387C26.962,5.738 28.031,7.325 28.819,9.15C29.606,10.975 30,12.925 30,15C30,17.075 29.606,19.025 28.819,20.85C28.031,22.675 26.962,24.263 25.612,25.612C24.263,26.962 22.675,28.031 20.85,28.819C19.025,29.606 17.075,30 15,30Z"
android:fillColor="#1B1D22"/>
</vector>

View File

@@ -1,9 +1,25 @@
<!--
~ Copyright (c) 2023 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="21dp"
android:height="18dp"
android:viewportWidth="21"
android:viewportHeight="18">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M20.252,10.085 L4.681,17.867c-1.049,0.525 -2.141,-0.601 -1.628,-1.627 0,0 1.93,-3.897 2.461,-4.918 0.531,-1.021 1.138,-1.197 6.781,-1.927 0.209,-0.027 0.38,-0.185 0.38,-0.395 0,-0.21 -0.171,-0.368 -0.38,-0.395C6.652,7.876 6.045,7.699 5.514,6.678 4.983,5.658 3.053,1.76 3.053,1.76 2.54,0.734 3.632,-0.391 4.681,0.133L20.252,7.915c0.894,0.446 0.894,1.723 0,2.17z"
android:fillColor="@android:color/white"/>
android:pathData="M21.829,13.085 L6.259,20.867c-1.049,0.525 -2.141,-0.601 -1.628,-1.627 0,0 1.93,-3.897 2.461,-4.918 0.531,-1.021 1.138,-1.197 6.781,-1.927 0.209,-0.027 0.38,-0.185 0.38,-0.395 0,-0.21 -0.171,-0.368 -0.38,-0.395C8.23,10.876 7.622,10.699 7.091,9.678c-0.531,-1.02 -2.461,-4.918 -2.461,-4.918 -0.513,-1.026 0.579,-2.152 1.628,-1.627L21.829,10.915c0.894,0.446 0.894,1.723 0,2.17z"
android:fillColor="#ffffff"/>
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="15dp"
android:viewportWidth="16"
android:viewportHeight="15">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M6.518,14.779C6.953,14.779 7.297,14.597 7.535,14.233L15.403,1.968C15.579,1.692 15.65,1.461 15.65,1.234C15.65,0.657 15.245,0.26 14.662,0.26C14.249,0.26 14.009,0.399 13.759,0.792L6.484,12.348L2.736,7.529C2.492,7.205 2.236,7.07 1.874,7.07C1.277,7.07 0.857,7.489 0.857,8.066C0.857,8.315 0.95,8.565 1.158,8.819L5.495,14.245C5.784,14.606 6.096,14.779 6.518,14.779Z"
android:pathData="M9.55,17.575C9.417,17.575 9.292,17.555 9.175,17.513C9.058,17.471 8.95,17.4 8.85,17.3L4.55,13C4.367,12.817 4.279,12.58 4.288,12.288C4.296,11.996 4.392,11.759 4.575,11.575C4.758,11.392 4.992,11.3 5.275,11.3C5.558,11.3 5.792,11.392 5.975,11.575L9.55,15.15L18.025,6.675C18.208,6.492 18.446,6.4 18.737,6.4C19.029,6.4 19.267,6.492 19.45,6.675C19.633,6.859 19.725,7.096 19.725,7.388C19.725,7.68 19.633,7.917 19.45,8.1L10.25,17.3C10.15,17.4 10.042,17.471 9.925,17.513C9.808,17.555 9.683,17.575 9.55,17.575Z"
android:fillColor="#ffffff"/>
</vector>

View File

@@ -195,9 +195,9 @@
<string name="screen_notification_settings_additional_settings_section_title">"Další nastavení"</string>
<string name="screen_notification_settings_calls_label">"Halsové a video hovory"</string>
<string name="screen_notification_settings_configuration_mismatch">"Neshoda konfigurace"</string>
<string name="screen_notification_settings_configuration_mismatch_description">"Zjednodušili jsme nastavení oznámení, abychom usnadnili hledání možností.
<string name="screen_notification_settings_configuration_mismatch_description">"Zjednodušili jsme nastavení oznámení, abychom usnadnili hledání možností.
Některá vlastní nastavení, která jste si vybrali v minulosti, se zde nezobrazují, ale jsou stále aktivní.
Některá vlastní nastavení, která jste si vybrali v minulosti, se zde nezobrazují, ale jsou stále aktivní.
Pokud budete pokračovat, některá nastavení se mohou změnit."</string>
<string name="screen_notification_settings_direct_chats">"Přímé zprávy"</string>

View File

@@ -67,9 +67,6 @@
<string name="action_take_photo">"Prendre une photo"</string>
<string name="action_view_source">"Afficher la source"</string>
<string name="action_yes">"Oui"</string>
<string name="call_foreground_service_channel_title_android">"Appel en cours"</string>
<string name="call_foreground_service_message_android">"Appuyez pour retourner à l\'appel."</string>
<string name="call_foreground_service_title_android">"☎️ Appel en cours"</string>
<string name="common_about">"À propos"</string>
<string name="common_acceptable_use_policy">"Politique d\'utilisation acceptable"</string>
<string name="common_advanced_settings">"Paramètres avancés"</string>

View File

@@ -194,9 +194,9 @@
<string name="screen_notification_settings_additional_settings_section_title">"Дополнительные параметры"</string>
<string name="screen_notification_settings_calls_label">"Аудио и видео звонки"</string>
<string name="screen_notification_settings_configuration_mismatch">"Несоответствие конфигурации"</string>
<string name="screen_notification_settings_configuration_mismatch_description">"Мы упростили настройки уведомлений, чтобы упростить поиск опций.
<string name="screen_notification_settings_configuration_mismatch_description">"Мы упростили настройки уведомлений, чтобы упростить поиск опций.
Некоторые пользовательские настройки, выбранные вами ранее, не отображаются в данном меню, но они все еще активны.
Некоторые пользовательские настройки, выбранные вами ранее, не отображаются в данном меню, но они все еще активны.
Если вы продолжите, некоторые настройки могут быть изменены."</string>
<string name="screen_notification_settings_direct_chats">"Прямые чаты"</string>

View File

@@ -67,9 +67,6 @@
<string name="action_take_photo">"Take photo"</string>
<string name="action_view_source">"View Source"</string>
<string name="action_yes">"Yes"</string>
<string name="call_foreground_service_channel_title_android">"Ongoing call"</string>
<string name="call_foreground_service_message_android">"Tap to return to the call"</string>
<string name="call_foreground_service_title_android">"☎️ Call in progress"</string>
<string name="common_about">"About"</string>
<string name="common_acceptable_use_policy">"Acceptable use policy"</string>
<string name="common_advanced_settings">"Advanced settings"</string>
@@ -207,6 +204,11 @@
<string name="room_timeline_beginning_of_room_no_name">"This is the beginning of this conversation."</string>
<string name="room_timeline_read_marker_title">"New"</string>
<string name="screen_analytics_settings_share_data">"Share analytics data"</string>
<string name="screen_edit_profile_display_name">"Display name"</string>
<string name="screen_edit_profile_display_name_placeholder">"Your display name"</string>
<string name="screen_edit_profile_error">"An unknown error was encountered and the information couldn\'t be changed."</string>
<string name="screen_edit_profile_error_title">"Unable to update profile"</string>
<string name="screen_edit_profile_updating_details">"Updating profile…"</string>
<string name="screen_media_picker_error_failed_selection">"Failed selecting media, please try again."</string>
<string name="screen_media_upload_preview_error_failed_processing">"Failed processing media to upload, please try again."</string>
<string name="screen_media_upload_preview_error_failed_sending">"Failed uploading media, please try again."</string>

View File

@@ -52,6 +52,7 @@ dependencies {
// `testOptions { unitTests.isIncludeAndroidResources = true }` in the app build.gradle.kts file
// implementation(projects.app)
implementation(projects.appnav)
implementation(projects.features.call)
allLibrariesImpl()
allServicesImpl()
allFeaturesImpl(rootDir, logger)

View File

@@ -48,6 +48,8 @@
<ignore path="**/localazy.xml" />
<!-- Ignore unused resource in debug build type -->
<ignore path="**/src/debug/**" />
<!-- Ignore unused resources in designsystem since they're imported elsewhere through aliases and can't be properly detected -->
<ignore path="**/libraries/designsystem/src/main/res/**" />
</issue>
<!-- UX -->

View File

@@ -128,6 +128,12 @@
"includeRegex": [
"screen_create_poll_.*"
]
},
{
"name": ":features:call",
"includeRegex": [
"call_.*"
]
}
]
}