forked from melod1n/fast-messenger
move all ui-related classes and files to ui module
This commit is contained in:
@@ -32,9 +32,14 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.core.designsystem)
|
||||
implementation(projects.core.common)
|
||||
api(projects.core.model)
|
||||
|
||||
implementation(libs.haze)
|
||||
implementation(libs.haze.materials)
|
||||
|
||||
implementation(platform(libs.compose.bom))
|
||||
implementation(libs.bundles.compose)
|
||||
|
||||
debugImplementation(libs.compose.ui.tooling)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.meloda.app.fast.ui.basic
|
||||
|
||||
import android.os.Build
|
||||
import android.view.autofill.AutofillManager
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.autofill.Autofill
|
||||
import androidx.compose.ui.autofill.AutofillNode
|
||||
import androidx.compose.ui.autofill.AutofillType
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.layout.boundsInWindow
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalAutofill
|
||||
import androidx.compose.ui.platform.LocalAutofillTree
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun Modifier.connectNode(handler: AutoFillHandler): Modifier {
|
||||
return with(handler) { fillBounds() }
|
||||
}
|
||||
|
||||
fun Modifier.defaultFocusChangeAutoFill(handler: AutoFillHandler): Modifier {
|
||||
return this.then(
|
||||
Modifier.onFocusChanged {
|
||||
if (it.isFocused) {
|
||||
handler.request()
|
||||
} else {
|
||||
handler.cancel()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun autoFillRequestHandler(
|
||||
autofillTypes: List<AutofillType> = listOf(),
|
||||
onFill: (String) -> Unit,
|
||||
): AutoFillHandler {
|
||||
val view = LocalView.current
|
||||
val context = LocalContext.current
|
||||
var isFillRecently = remember { false }
|
||||
val autoFillNode = remember {
|
||||
AutofillNode(
|
||||
autofillTypes = autofillTypes,
|
||||
onFill = {
|
||||
isFillRecently = true
|
||||
onFill(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
val autofill = LocalAutofill.current
|
||||
LocalAutofillTree.current += autoFillNode
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return EmptyAutoFillHandler
|
||||
|
||||
return remember {
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
object : AutoFillHandler {
|
||||
val autofillManager = context.getSystemService(AutofillManager::class.java)
|
||||
override fun requestManual() {
|
||||
autofillManager.requestAutofill(
|
||||
view,
|
||||
autoFillNode.id,
|
||||
autoFillNode.boundingBox?.toAndroidRect() ?: error("BoundingBox is not provided yet")
|
||||
)
|
||||
}
|
||||
|
||||
override fun requestVerifyManual() {
|
||||
if (isFillRecently) {
|
||||
isFillRecently = false
|
||||
requestManual()
|
||||
}
|
||||
}
|
||||
|
||||
override val autoFill: Autofill?
|
||||
get() = autofill
|
||||
|
||||
override val autoFillNode: AutofillNode
|
||||
get() = autoFillNode
|
||||
|
||||
override fun request() {
|
||||
autofill?.requestAutofillForNode(autofillNode = autoFillNode)
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
autofill?.cancelAutofillForNode(autofillNode = autoFillNode)
|
||||
}
|
||||
|
||||
override fun Modifier.fillBounds(): Modifier {
|
||||
return this.then(
|
||||
Modifier.onGloballyPositioned {
|
||||
autoFillNode.boundingBox = it.boundsInWindow()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Rect.toAndroidRect(): android.graphics.Rect {
|
||||
return android.graphics.Rect(
|
||||
left.roundToInt(),
|
||||
top.roundToInt(),
|
||||
right.roundToInt(),
|
||||
bottom.roundToInt()
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
interface AutoFillHandler {
|
||||
|
||||
val autoFill: Autofill?
|
||||
val autoFillNode: AutofillNode?
|
||||
fun requestVerifyManual()
|
||||
fun requestManual()
|
||||
fun request()
|
||||
fun cancel()
|
||||
fun Modifier.fillBounds(): Modifier
|
||||
}
|
||||
|
||||
@ExperimentalComposeUiApi
|
||||
data object EmptyAutoFillHandler : AutoFillHandler {
|
||||
override val autoFill: Autofill? = null
|
||||
override val autoFillNode: AutofillNode? = null
|
||||
override fun requestVerifyManual() {}
|
||||
override fun requestManual() {}
|
||||
override fun request() {}
|
||||
override fun cancel() {}
|
||||
override fun Modifier.fillBounds(): Modifier = this.then(Modifier)
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.meloda.app.fast.ui.basic
|
||||
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import androidx.annotation.FloatRange
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
import com.meloda.app.fast.ui.util.isUsingDarkTheme
|
||||
|
||||
/**
|
||||
* Default alpha levels used by Material components.
|
||||
*
|
||||
* See [LocalContentAlpha].
|
||||
*/
|
||||
object ContentAlpha {
|
||||
/**
|
||||
* A high level of content alpha, used to represent high emphasis text such as input text in a
|
||||
* selected [TextField].
|
||||
*/
|
||||
val high: Float
|
||||
@Composable
|
||||
get() = contentAlpha(
|
||||
highContrastAlpha = HighContrastContentAlpha.high,
|
||||
lowContrastAlpha = LowContrastContentAlpha.high
|
||||
)
|
||||
|
||||
/**
|
||||
* A medium level of content alpha, used to represent medium emphasis text such as
|
||||
* placeholder text in a [TextField].
|
||||
*/
|
||||
val medium: Float
|
||||
@Composable
|
||||
get() = contentAlpha(
|
||||
highContrastAlpha = HighContrastContentAlpha.medium,
|
||||
lowContrastAlpha = LowContrastContentAlpha.medium
|
||||
)
|
||||
|
||||
/**
|
||||
* A low level of content alpha used to represent disabled components, such as text in a
|
||||
* disabled [Button].
|
||||
*/
|
||||
val disabled: Float
|
||||
@Composable
|
||||
get() = contentAlpha(
|
||||
highContrastAlpha = HighContrastContentAlpha.disabled,
|
||||
lowContrastAlpha = LowContrastContentAlpha.disabled
|
||||
)
|
||||
|
||||
/**
|
||||
* This default implementation uses separate alpha levels depending on the luminance of the
|
||||
* incoming color, and whether the theme is light or dark. This is to ensure correct contrast
|
||||
* and accessibility on all surfaces.
|
||||
*
|
||||
* See [HighContrastContentAlpha] and [LowContrastContentAlpha] for what the levels are
|
||||
* used for, and under what circumstances.
|
||||
*/
|
||||
@Composable
|
||||
private fun contentAlpha(
|
||||
@FloatRange(from = 0.0, to = 1.0)
|
||||
highContrastAlpha: Float,
|
||||
@FloatRange(from = 0.0, to = 1.0)
|
||||
lowContrastAlpha: Float
|
||||
): Float {
|
||||
val contentColor = LocalContentColor.current
|
||||
return if (!isUsingDarkTheme()) {
|
||||
if (contentColor.luminance() > 0.5) highContrastAlpha else lowContrastAlpha
|
||||
} else {
|
||||
if (contentColor.luminance() < 0.5) highContrastAlpha else lowContrastAlpha
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CompositionLocal containing the preferred content alpha for a given position in the hierarchy.
|
||||
* This alpha is used for text and iconography ([Text] and [Icon]) to emphasize / de-emphasize
|
||||
* different parts of a component. See the Material guide on
|
||||
* [Text Legibility](https://material.io/design/color/text-legibility.html) for more information on
|
||||
* alpha levels used by text and iconography.
|
||||
*
|
||||
* See [ContentAlpha] for the default levels used by most Material components.
|
||||
*
|
||||
* [MaterialTheme] sets this to [ContentAlpha.high] by default, as this is the default alpha for
|
||||
* body text.
|
||||
*
|
||||
* @sample androidx.compose.material.samples.ContentAlphaSample
|
||||
*/
|
||||
val LocalContentAlpha = compositionLocalOf { 1f }
|
||||
|
||||
/**
|
||||
* Alpha levels for high luminance content in light theme, or low luminance content in dark theme.
|
||||
*
|
||||
* This content will typically be placed on colored surfaces, so it is important that the
|
||||
* contrast here is higher to meet accessibility standards, and increase legibility.
|
||||
*
|
||||
* These levels are typically used for text / iconography in primary colored tabs /
|
||||
* bottom navigation / etc.
|
||||
*/
|
||||
private object HighContrastContentAlpha {
|
||||
const val high: Float = 1.00f
|
||||
const val medium: Float = 0.74f
|
||||
const val disabled: Float = 0.38f
|
||||
}
|
||||
|
||||
/**
|
||||
* Alpha levels for low luminance content in light theme, or high luminance content in dark theme.
|
||||
*
|
||||
* This content will typically be placed on grayscale surfaces, so the contrast here can be lower
|
||||
* without sacrificing accessibility and legibility.
|
||||
*
|
||||
* These levels are typically used for body text on the main surface (white in light theme, grey
|
||||
* in dark theme) and text / iconography in surface colored tabs / bottom navigation / etc.
|
||||
*/
|
||||
private object LowContrastContentAlpha {
|
||||
const val high: Float = 0.87f
|
||||
const val medium: Float = 0.60f
|
||||
const val disabled: Float = 0.38f
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.meloda.app.fast.ui.basic
|
||||
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
@Composable
|
||||
fun LocalContentAlpha(
|
||||
defaultColor: Color = MaterialTheme.colorScheme.onBackground,
|
||||
alpha: Float,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides defaultColor.copy(alpha = alpha)
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
package com.meloda.app.fast.ui.components
|
||||
|
||||
// TODO: 26.08.2023, Danil Nikolaev: rewrite
|
||||
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.infiniteRepeatable
|
||||
import androidx.compose.animation.core.keyframes
|
||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
const val numberOfDots = 3
|
||||
val dotSize = 6.dp
|
||||
val dotColor: Color = Color.Blue
|
||||
const val delayUnit = 300
|
||||
const val duration = numberOfDots * delayUnit
|
||||
val spaceBetween = 2.dp
|
||||
|
||||
@Composable
|
||||
fun DotsPulsing() {
|
||||
|
||||
@Composable
|
||||
fun Dot(scale: Float) {
|
||||
Spacer(
|
||||
Modifier
|
||||
.size(dotSize)
|
||||
.scale(scale)
|
||||
.background(
|
||||
color = dotColor,
|
||||
shape = CircleShape
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val infiniteTransition = rememberInfiniteTransition(label = "")
|
||||
|
||||
@Composable
|
||||
fun animateScaleWithDelay(delay: Int) = infiniteTransition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = 0f,
|
||||
animationSpec = infiniteRepeatable(animation = keyframes {
|
||||
durationMillis = delayUnit * numberOfDots
|
||||
0f at delay using LinearEasing
|
||||
1f at delay + delayUnit using LinearEasing
|
||||
0f at delay + duration
|
||||
}), label = ""
|
||||
)
|
||||
|
||||
val scales = arrayListOf<State<Float>>()
|
||||
for (i in 0 until numberOfDots) {
|
||||
scales.add(animateScaleWithDelay(delay = i * delayUnit))
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
scales.forEach {
|
||||
Dot(it.value)
|
||||
Spacer(Modifier.width(spaceBetween))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun DotsElastic() {
|
||||
val minScale = 0.6f
|
||||
|
||||
@Composable
|
||||
fun Dot(scale: Float) {
|
||||
Spacer(
|
||||
Modifier
|
||||
.size(dotSize)
|
||||
.scale(scaleX = minScale, scaleY = scale)
|
||||
.background(
|
||||
color = dotColor,
|
||||
shape = CircleShape
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val infiniteTransition = rememberInfiniteTransition(label = "")
|
||||
|
||||
@Composable
|
||||
fun animateScaleWithDelay(delay: Int) = infiniteTransition.animateFloat(
|
||||
initialValue = minScale,
|
||||
targetValue = minScale,
|
||||
animationSpec = infiniteRepeatable(animation = keyframes {
|
||||
durationMillis = duration
|
||||
minScale at delay using LinearEasing
|
||||
1f at delay + delayUnit using LinearEasing
|
||||
minScale at delay + duration
|
||||
}), label = ""
|
||||
)
|
||||
|
||||
val scales = arrayListOf<State<Float>>()
|
||||
for (i in 0 until numberOfDots) {
|
||||
scales.add(animateScaleWithDelay(delay = i * delayUnit))
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
scales.forEach {
|
||||
Dot(it.value)
|
||||
Spacer(Modifier.width(spaceBetween))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DotsFlashing(
|
||||
modifier: Modifier = Modifier,
|
||||
dotSize: Dp = 6.dp,
|
||||
dotColor: Color = Color.Blue,
|
||||
spaceBetween: Dp = 2.dp,
|
||||
numberOfDots: Int = 3,
|
||||
) {
|
||||
val minAlpha = 0.1f
|
||||
|
||||
@Composable
|
||||
fun Dot(alpha: Float) = Spacer(
|
||||
Modifier
|
||||
.size(dotSize)
|
||||
.alpha(alpha)
|
||||
.background(
|
||||
color = dotColor, shape = CircleShape
|
||||
)
|
||||
)
|
||||
|
||||
val infiniteTransition = rememberInfiniteTransition(label = "")
|
||||
|
||||
@Composable
|
||||
fun animateAlphaWithDelay(delay: Int) = infiniteTransition.animateFloat(
|
||||
initialValue = minAlpha,
|
||||
targetValue = minAlpha,
|
||||
animationSpec = infiniteRepeatable(animation = keyframes {
|
||||
durationMillis = duration
|
||||
minAlpha at delay using LinearEasing
|
||||
1f at delay + delayUnit using LinearEasing
|
||||
minAlpha at delay + duration
|
||||
}), label = ""
|
||||
)
|
||||
|
||||
val alphas = arrayListOf<State<Float>>()
|
||||
for (i in 0 until numberOfDots) {
|
||||
alphas.add(animateAlphaWithDelay(delay = i * delayUnit))
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
alphas.forEach {
|
||||
Dot(it.value)
|
||||
Spacer(Modifier.width(spaceBetween))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DotsTyping(
|
||||
modifier: Modifier = Modifier,
|
||||
dotSize: Dp = 6.dp,
|
||||
dotColor: Color = Color.Blue,
|
||||
spaceBetween: Dp = 2.dp,
|
||||
numberOfDots: Int = 3,
|
||||
) {
|
||||
val maxOffset = (numberOfDots * 2).toFloat()
|
||||
|
||||
@Composable
|
||||
fun Dot(offset: Float) {
|
||||
Spacer(
|
||||
Modifier
|
||||
.size(dotSize)
|
||||
.offset(y = -offset.dp)
|
||||
.background(
|
||||
color = dotColor,
|
||||
shape = CircleShape
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val infiniteTransition = rememberInfiniteTransition(label = "")
|
||||
|
||||
@Composable
|
||||
fun animateOffsetWithDelay(delay: Int) = infiniteTransition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = 0f,
|
||||
animationSpec = infiniteRepeatable(animation = keyframes {
|
||||
durationMillis = duration
|
||||
0f at delay using LinearEasing
|
||||
maxOffset at delay + delayUnit using LinearEasing
|
||||
0f at delay + (duration / 2)
|
||||
}), label = ""
|
||||
)
|
||||
|
||||
val offsets = arrayListOf<State<Float>>()
|
||||
for (i in 0 until numberOfDots) {
|
||||
offsets.add(animateOffsetWithDelay(delay = i * delayUnit))
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = modifier.padding(top = maxOffset.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
offsets.forEach {
|
||||
Dot(it.value)
|
||||
Spacer(Modifier.width(spaceBetween))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DotsCollision() {
|
||||
val maxOffset = 30f
|
||||
val delayUnit = 500
|
||||
|
||||
@Composable
|
||||
fun Dot(offset: Float) {
|
||||
Spacer(
|
||||
Modifier
|
||||
.size(dotSize)
|
||||
.offset(x = offset.dp)
|
||||
.background(
|
||||
color = dotColor,
|
||||
shape = CircleShape
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val infiniteTransition = rememberInfiniteTransition(label = "")
|
||||
|
||||
val offsetLeft by infiniteTransition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = 0f,
|
||||
animationSpec = infiniteRepeatable(animation = keyframes {
|
||||
durationMillis = delayUnit * 3
|
||||
0f at 0 using LinearEasing
|
||||
maxOffset at delayUnit / 2 using LinearEasing
|
||||
0f at delayUnit
|
||||
}), label = ""
|
||||
)
|
||||
val offsetRight by infiniteTransition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = 0f,
|
||||
animationSpec = infiniteRepeatable(animation = keyframes {
|
||||
durationMillis = delayUnit * 3
|
||||
0f at delayUnit using LinearEasing
|
||||
maxOffset at delayUnit + delayUnit / 2 using LinearEasing
|
||||
0f at delayUnit * 2
|
||||
}), label = ""
|
||||
)
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.padding(horizontal = maxOffset.dp)
|
||||
) {
|
||||
Dot(offsetLeft)
|
||||
Spacer(Modifier.width(spaceBetween))
|
||||
for (i in 0 until numberOfDots - 2) {
|
||||
Dot(0f)
|
||||
Spacer(Modifier.width(spaceBetween))
|
||||
}
|
||||
Dot(offsetRight)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun DotsPreview() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
val spaceSize = 16.dp
|
||||
|
||||
Text(
|
||||
text = "Dots pulsing", //style = MaterialTheme.typography.h5
|
||||
)
|
||||
DotsPulsing()
|
||||
|
||||
Spacer(Modifier.height(spaceSize))
|
||||
|
||||
Text(
|
||||
text = "Dots elastic", //style = MaterialTheme.typography.h5
|
||||
)
|
||||
DotsElastic()
|
||||
|
||||
Spacer(Modifier.height(spaceSize))
|
||||
|
||||
Text(
|
||||
text = "Dots flashing", //style = MaterialTheme.typography.h5
|
||||
)
|
||||
DotsFlashing()
|
||||
|
||||
Spacer(Modifier.height(spaceSize))
|
||||
|
||||
Text(
|
||||
text = "Dots typing", //style = MaterialTheme.typography.h5
|
||||
)
|
||||
DotsTyping()
|
||||
|
||||
Spacer(Modifier.height(spaceSize))
|
||||
|
||||
Text(
|
||||
text = "Dots collision", //style = MaterialTheme.typography.h5
|
||||
)
|
||||
DotsCollision()
|
||||
}
|
||||
}
|
||||
+11
-1
@@ -1,4 +1,4 @@
|
||||
package com.meloda.app.fast.ui
|
||||
package com.meloda.app.fast.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -11,6 +11,7 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
@@ -40,3 +41,12 @@ fun ErrorView(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ErrorViewPreview() {
|
||||
ErrorView(
|
||||
text = "Some error occurred",
|
||||
buttonText = "Restart"
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.meloda.app.fast.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
||||
@Composable
|
||||
fun FullScreenLoader(modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun FullScreenLoaderPreview() {
|
||||
FullScreenLoader()
|
||||
}
|
||||
@@ -0,0 +1,527 @@
|
||||
package com.meloda.app.fast.ui.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
import androidx.compose.material3.BasicAlertDialog
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
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.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import com.meloda.app.fast.common.UiText
|
||||
import com.meloda.app.fast.common.parseString
|
||||
import com.meloda.app.fast.ui.util.ImmutableList
|
||||
import com.meloda.app.fast.ui.util.ImmutableList.Companion.toImmutableList
|
||||
import com.meloda.app.fast.ui.util.getString
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun MaterialDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
confirmText: String? = null,
|
||||
confirmAction: (() -> Unit)? = null,
|
||||
cancelText: String? = null,
|
||||
cancelAction: (() -> Unit)? = null,
|
||||
neutralText: String? = null,
|
||||
neutralAction: (() -> Unit)? = null,
|
||||
title: String? = null,
|
||||
text: String? = null,
|
||||
itemsSelectionType: ItemsSelectionType = ItemsSelectionType.None,
|
||||
items: ImmutableList<String> = ImmutableList.empty(),
|
||||
preSelectedItems: ImmutableList<Int> = ImmutableList.empty(),
|
||||
onItemClick: ((index: Int) -> Unit)? = null,
|
||||
properties: DialogProperties = DialogProperties(),
|
||||
actionInvokeDismiss: ActionInvokeDismiss = ActionInvokeDismiss.IfNoAction,
|
||||
customContent: (ColumnScope.() -> Unit)? = null
|
||||
) {
|
||||
var alertItems by remember {
|
||||
mutableStateOf(
|
||||
items.mapIndexed { index, title ->
|
||||
DialogItem(
|
||||
title,
|
||||
preSelectedItems.contains(index)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
BasicAlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
modifier = modifier,
|
||||
properties = properties
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
val canScrollBackward by remember { derivedStateOf { scrollState.value > 0 } }
|
||||
val canScrollForward by remember { derivedStateOf { scrollState.value < scrollState.maxValue } }
|
||||
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
color = AlertDialogDefaults.containerColor,
|
||||
shape = AlertDialogDefaults.shape,
|
||||
tonalElevation = AlertDialogDefaults.TonalElevation
|
||||
) {
|
||||
Column(modifier = Modifier.padding(bottom = 10.dp)) {
|
||||
if (title != null) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Row {
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = title,
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
}
|
||||
}
|
||||
|
||||
if (canScrollBackward) {
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f, fill = false)
|
||||
.verticalScroll(scrollState)
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
if (text != null && title == null) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
}
|
||||
|
||||
if (text != null) {
|
||||
Row {
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
if (alertItems.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
AlertItems(
|
||||
selectionType = itemsSelectionType,
|
||||
items = alertItems,
|
||||
onItemClick = { index ->
|
||||
onItemClick?.invoke(index)
|
||||
|
||||
if (itemsSelectionType == ItemsSelectionType.None) {
|
||||
onDismissRequest.invoke()
|
||||
} else {
|
||||
val newItems =
|
||||
alertItems.mapIndexed { itemIndex, item ->
|
||||
item.copy(isSelected = itemIndex == index)
|
||||
}
|
||||
|
||||
alertItems = newItems
|
||||
}
|
||||
},
|
||||
onItemCheckedChanged = { index ->
|
||||
val newItems = alertItems.toMutableList()
|
||||
val oldItem = newItems[index]
|
||||
newItems[index] =
|
||||
oldItem.copy(isSelected = !oldItem.isSelected)
|
||||
|
||||
alertItems = newItems.toImmutableList()
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
} else {
|
||||
if (customContent != null) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
customContent.invoke(this)
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canScrollForward) {
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
|
||||
Row {
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
if (neutralText != null) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
neutralAction?.invoke() ?: kotlin.run {
|
||||
if (actionInvokeDismiss == ActionInvokeDismiss.IfNoAction) {
|
||||
onDismissRequest()
|
||||
}
|
||||
}
|
||||
|
||||
if (actionInvokeDismiss == ActionInvokeDismiss.Always) {
|
||||
onDismissRequest()
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(text = neutralText)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
if (cancelText != null) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
cancelAction?.invoke() ?: kotlin.run {
|
||||
if (actionInvokeDismiss == ActionInvokeDismiss.IfNoAction) {
|
||||
onDismissRequest()
|
||||
}
|
||||
}
|
||||
|
||||
if (actionInvokeDismiss == ActionInvokeDismiss.Always) {
|
||||
onDismissRequest()
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(text = cancelText)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(2.dp))
|
||||
|
||||
if (confirmText != null) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
confirmAction?.invoke() ?: kotlin.run {
|
||||
if (actionInvokeDismiss == ActionInvokeDismiss.IfNoAction) {
|
||||
onDismissRequest()
|
||||
}
|
||||
}
|
||||
|
||||
if (actionInvokeDismiss == ActionInvokeDismiss.Always) {
|
||||
onDismissRequest()
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(text = confirmText)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 08.04.2023, Danil Nikolaev: remove this
|
||||
@Deprecated("need refactoring")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun MaterialDialog(
|
||||
onDismissAction: (() -> Unit),
|
||||
title: UiText? = null,
|
||||
text: UiText? = null,
|
||||
confirmText: UiText? = null,
|
||||
confirmAction: (() -> Unit)? = null,
|
||||
cancelText: UiText? = null,
|
||||
cancelAction: (() -> Unit)? = null,
|
||||
neutralText: UiText? = null,
|
||||
neutralAction: (() -> Unit)? = null,
|
||||
itemsSelectionType: ItemsSelectionType = ItemsSelectionType.None,
|
||||
preSelectedItems: ImmutableList<Int> = ImmutableList.empty(),
|
||||
items: ImmutableList<UiText> = ImmutableList.empty(),
|
||||
onItemClick: ((index: Int) -> Unit)? = null,
|
||||
buttonsInvokeDismiss: Boolean = true,
|
||||
properties: DialogProperties = DialogProperties(),
|
||||
customContent: (@Composable ColumnScope.() -> Unit)? = null,
|
||||
) {
|
||||
var isVisible by rememberSaveable {
|
||||
mutableStateOf(true)
|
||||
}
|
||||
val onDismissRequest = remember {
|
||||
{
|
||||
onDismissAction.invoke()
|
||||
isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
val stringTitles = items.mapNotNull { it.parseString(context.resources) }
|
||||
|
||||
var alertItems by remember {
|
||||
mutableStateOf(
|
||||
stringTitles.mapIndexed { index, title ->
|
||||
DialogItem(
|
||||
title,
|
||||
preSelectedItems.contains(index)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (isVisible) {
|
||||
BasicAlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
properties = properties
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
val canScrollBackward by remember { derivedStateOf { scrollState.value > 0 } }
|
||||
val canScrollForward by remember { derivedStateOf { scrollState.value < scrollState.maxValue } }
|
||||
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
color = AlertDialogDefaults.containerColor,
|
||||
shape = AlertDialogDefaults.shape,
|
||||
tonalElevation = AlertDialogDefaults.TonalElevation
|
||||
) {
|
||||
Column(modifier = Modifier.padding(bottom = 10.dp)) {
|
||||
val stringTitle = title?.getString()
|
||||
if (stringTitle != null) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
}
|
||||
|
||||
Row {
|
||||
stringTitle?.let { title ->
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = title,
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
}
|
||||
}
|
||||
|
||||
if (canScrollBackward) {
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f, fill = false)
|
||||
.verticalScroll(scrollState)
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
val stringMessage = text?.getString()
|
||||
if (stringMessage != null && stringTitle == null) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
}
|
||||
|
||||
Row {
|
||||
stringMessage?.let { message ->
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = message,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
if (alertItems.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
AlertItems(
|
||||
selectionType = itemsSelectionType,
|
||||
items = alertItems,
|
||||
onItemClick = { index ->
|
||||
onItemClick?.invoke(index)
|
||||
|
||||
if (itemsSelectionType == ItemsSelectionType.None) {
|
||||
onDismissRequest.invoke()
|
||||
} else {
|
||||
val newItems =
|
||||
alertItems.mapIndexed { itemIndex, item ->
|
||||
item.copy(isSelected = itemIndex == index)
|
||||
}
|
||||
|
||||
alertItems = newItems
|
||||
}
|
||||
},
|
||||
onItemCheckedChanged = { index ->
|
||||
val newItems = alertItems.toMutableList()
|
||||
val oldItem = newItems[index]
|
||||
newItems[index] =
|
||||
oldItem.copy(isSelected = !oldItem.isSelected)
|
||||
|
||||
alertItems = newItems.toImmutableList()
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
} else {
|
||||
customContent?.let { content ->
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
content.invoke(this)
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canScrollForward) {
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
|
||||
Row {
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
neutralText?.getString()?.let { text ->
|
||||
TextButton(
|
||||
onClick = {
|
||||
if (buttonsInvokeDismiss) {
|
||||
onDismissRequest.invoke()
|
||||
} else {
|
||||
isVisible = false
|
||||
}
|
||||
neutralAction?.invoke()
|
||||
}
|
||||
) {
|
||||
Text(text = text)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
cancelText?.getString()?.let { text ->
|
||||
TextButton(
|
||||
onClick = {
|
||||
if (buttonsInvokeDismiss) {
|
||||
onDismissRequest.invoke()
|
||||
} else {
|
||||
isVisible = false
|
||||
}
|
||||
cancelAction?.invoke()
|
||||
}
|
||||
) {
|
||||
Text(text = text)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(2.dp))
|
||||
|
||||
confirmText?.getString()?.let { text ->
|
||||
TextButton(
|
||||
onClick = {
|
||||
if (buttonsInvokeDismiss) {
|
||||
onDismissRequest.invoke()
|
||||
} else {
|
||||
isVisible = false
|
||||
}
|
||||
confirmAction?.invoke()
|
||||
}
|
||||
) {
|
||||
Text(text = text)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun AlertItems(
|
||||
selectionType: ItemsSelectionType,
|
||||
items: ImmutableList<DialogItem>,
|
||||
onItemClick: ((index: Int) -> Unit)? = null,
|
||||
onItemCheckedChanged: ((index: Int) -> Unit)? = null
|
||||
) {
|
||||
items.forEachIndexed { index, item ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(48.dp)
|
||||
.clickable {
|
||||
if (selectionType == ItemsSelectionType.Multi) {
|
||||
onItemCheckedChanged?.invoke(index)
|
||||
} else {
|
||||
onItemClick?.invoke(index)
|
||||
}
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// TODO: 29/12/2023, Danil Nikolaev: check onClick & onCheckedChange actions
|
||||
when (selectionType) {
|
||||
ItemsSelectionType.Multi -> {
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Checkbox(
|
||||
checked = item.isSelected,
|
||||
onCheckedChange = {}
|
||||
)
|
||||
}
|
||||
|
||||
ItemsSelectionType.Single -> {
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
RadioButton(
|
||||
selected = item.isSelected,
|
||||
onClick = {}
|
||||
)
|
||||
}
|
||||
|
||||
ItemsSelectionType.None -> {
|
||||
Spacer(modifier = Modifier.width(26.dp))
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = item.title,
|
||||
style = MaterialTheme.typography.bodyLarge
|
||||
)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class DialogItem(
|
||||
val title: String,
|
||||
val isSelected: Boolean
|
||||
)
|
||||
|
||||
sealed class ActionInvokeDismiss {
|
||||
data object Never : ActionInvokeDismiss()
|
||||
data object IfNoAction : ActionInvokeDismiss()
|
||||
data object Always : ActionInvokeDismiss()
|
||||
}
|
||||
|
||||
sealed class ItemsSelectionType {
|
||||
data object Single : ItemsSelectionType()
|
||||
data object Multi : ItemsSelectionType()
|
||||
data object None : ItemsSelectionType()
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.meloda.app.fast.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.meloda.app.fast.ui.R
|
||||
|
||||
@Composable
|
||||
fun NoItemsView(
|
||||
modifier: Modifier = Modifier,
|
||||
customText: String? = null
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = customText ?: stringResource(id = R.string.no_items),
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun NoItemsViewPreview() {
|
||||
NoItemsView(
|
||||
customText = "Nothing here..."
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.meloda.app.fast.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.meloda.app.fast.ui.R
|
||||
|
||||
@Composable
|
||||
fun TextFieldErrorText(
|
||||
modifier: Modifier = Modifier,
|
||||
text: String = stringResource(id = R.string.error_empty_field),
|
||||
withSpacer: Boolean = true
|
||||
) {
|
||||
Row {
|
||||
if (withSpacer) {
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
}
|
||||
Text(
|
||||
text = text,
|
||||
modifier = modifier,
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun TextFieldErrorPreview() {
|
||||
TextFieldErrorText(text = "Error")
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.meloda.app.fast.ui.model
|
||||
|
||||
data class TabItem(
|
||||
val titleResId: Int?,
|
||||
val unselectedIconResId: Int?,
|
||||
val selectedIconResId: Int?
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.meloda.app.fast.ui.model
|
||||
|
||||
data class ThemeConfig(
|
||||
val usingDarkStyle: Boolean,
|
||||
val usingDynamicColors: Boolean,
|
||||
val selectedColorScheme: Int,
|
||||
val usingAmoledBackground: Boolean,
|
||||
val usingBlur: Boolean,
|
||||
val multiline: Boolean,
|
||||
val isDeviceCompact: Boolean
|
||||
)
|
||||
@@ -0,0 +1,186 @@
|
||||
package com.meloda.app.fast.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.text.font.Font
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.view.WindowCompat
|
||||
import com.meloda.app.fast.ui.R
|
||||
import com.meloda.app.fast.ui.model.ThemeConfig
|
||||
import dev.chrisbanes.haze.HazeState
|
||||
|
||||
private val googleSansFonts = FontFamily(
|
||||
Font(resId = R.font.google_sans_regular),
|
||||
Font(
|
||||
resId = R.font.google_sans_italic,
|
||||
style = FontStyle.Italic
|
||||
),
|
||||
Font(
|
||||
resId = R.font.google_sans_medium,
|
||||
weight = FontWeight.Medium
|
||||
),
|
||||
Font(
|
||||
resId = R.font.google_sans_medium_italic,
|
||||
weight = FontWeight.Medium,
|
||||
style = FontStyle.Italic
|
||||
),
|
||||
Font(
|
||||
resId = R.font.google_sans_bold,
|
||||
weight = FontWeight.Bold
|
||||
),
|
||||
Font(
|
||||
resId = R.font.google_sans_bold_italic,
|
||||
weight = FontWeight.Bold,
|
||||
style = FontStyle.Italic
|
||||
)
|
||||
)
|
||||
|
||||
private val robotoFonts = FontFamily(
|
||||
Font(
|
||||
resId = R.font.roboto_thin,
|
||||
weight = FontWeight.Thin
|
||||
),
|
||||
Font(
|
||||
resId = R.font.roboto_thin_italic,
|
||||
weight = FontWeight.Thin,
|
||||
style = FontStyle.Italic
|
||||
),
|
||||
Font(
|
||||
resId = R.font.roboto_light,
|
||||
weight = FontWeight.Light
|
||||
),
|
||||
Font(
|
||||
resId = R.font.roboto_light_italic,
|
||||
weight = FontWeight.Light,
|
||||
style = FontStyle.Italic
|
||||
),
|
||||
Font(resId = R.font.roboto_regular),
|
||||
Font(
|
||||
resId = R.font.roboto_italic,
|
||||
style = FontStyle.Italic
|
||||
),
|
||||
Font(
|
||||
resId = R.font.roboto_medium,
|
||||
weight = FontWeight.Medium
|
||||
),
|
||||
Font(
|
||||
resId = R.font.roboto_medium_italic,
|
||||
weight = FontWeight.Medium,
|
||||
style = FontStyle.Italic
|
||||
),
|
||||
Font(
|
||||
resId = R.font.roboto_bold,
|
||||
weight = FontWeight.Bold
|
||||
),
|
||||
Font(
|
||||
resId = R.font.roboto_bold_italic,
|
||||
weight = FontWeight.Bold,
|
||||
style = FontStyle.Italic
|
||||
),
|
||||
Font(
|
||||
resId = R.font.roboto_black,
|
||||
weight = FontWeight.Black
|
||||
),
|
||||
Font(
|
||||
resId = R.font.roboto_black_italic,
|
||||
weight = FontWeight.Black,
|
||||
style = FontStyle.Italic
|
||||
)
|
||||
)
|
||||
|
||||
val LocalTheme = compositionLocalOf {
|
||||
ThemeConfig(
|
||||
usingDarkStyle = false,
|
||||
usingDynamicColors = false,
|
||||
selectedColorScheme = 0,
|
||||
usingAmoledBackground = false,
|
||||
usingBlur = false,
|
||||
multiline = false,
|
||||
isDeviceCompact = false
|
||||
)
|
||||
}
|
||||
|
||||
val LocalHazeState = compositionLocalOf {
|
||||
HazeState()
|
||||
}
|
||||
|
||||
val LocalBottomPadding = compositionLocalOf {
|
||||
0.dp
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AppTheme(
|
||||
predefinedColorScheme: ColorScheme? = null,
|
||||
useDarkTheme: Boolean = false,
|
||||
useDynamicColors: Boolean = false,
|
||||
useAmoledBackground: Boolean = false,
|
||||
selectedColorScheme: Int = 0,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme: ColorScheme = when {
|
||||
useDynamicColors && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (useDarkTheme) dynamicDarkColorScheme(context)
|
||||
else dynamicLightColorScheme(context)
|
||||
}
|
||||
|
||||
else -> {
|
||||
// TODO: 03/07/2024, Danil Nikolaev: add color picker to settings
|
||||
when (selectedColorScheme) {
|
||||
1 -> if (useDarkTheme) darkColorScheme() else lightColorScheme()
|
||||
else -> if (useDarkTheme) ClassicColorScheme.darkScheme else ClassicColorScheme.lightScheme
|
||||
}
|
||||
}
|
||||
}.let { scheme ->
|
||||
if (useDarkTheme && useAmoledBackground) {
|
||||
scheme.copy(
|
||||
background = Color.Black,
|
||||
surface = Color.Black
|
||||
)
|
||||
} else {
|
||||
scheme
|
||||
}
|
||||
}
|
||||
|
||||
val typography = MaterialTheme.typography.copy(
|
||||
displayLarge = MaterialTheme.typography.displayLarge.copy(fontFamily = googleSansFonts),
|
||||
displayMedium = MaterialTheme.typography.displayMedium.copy(fontFamily = googleSansFonts),
|
||||
displaySmall = MaterialTheme.typography.displaySmall.copy(fontFamily = googleSansFonts),
|
||||
headlineLarge = MaterialTheme.typography.headlineLarge.copy(fontFamily = googleSansFonts),
|
||||
headlineMedium = MaterialTheme.typography.headlineMedium.copy(fontFamily = googleSansFonts),
|
||||
headlineSmall = MaterialTheme.typography.headlineSmall.copy(fontFamily = googleSansFonts),
|
||||
bodyLarge = MaterialTheme.typography.bodyLarge.copy(fontFamily = robotoFonts),
|
||||
bodyMedium = MaterialTheme.typography.bodyMedium.copy(fontFamily = robotoFonts),
|
||||
bodySmall = MaterialTheme.typography.bodySmall.copy(fontFamily = robotoFonts)
|
||||
)
|
||||
|
||||
val view = LocalView.current
|
||||
if (!view.isInEditMode) {
|
||||
SideEffect {
|
||||
val window = (view.context as Activity).window
|
||||
val insetsController = WindowCompat.getInsetsController(window, view)
|
||||
insetsController.isAppearanceLightStatusBars = !useDarkTheme
|
||||
}
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = predefinedColorScheme ?: colorScheme,
|
||||
typography = typography,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.meloda.app.fast.ui.theme
|
||||
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
object ClassicColorScheme {
|
||||
private val primaryLight = Color(0xFF405F90)
|
||||
private val onPrimaryLight = Color(0xFFFFFFFF)
|
||||
private val primaryContainerLight = Color(0xFFD6E3FF)
|
||||
private val onPrimaryContainerLight = Color(0xFF001B3D)
|
||||
private val secondaryLight = Color(0xFF555F71)
|
||||
private val onSecondaryLight = Color(0xFFFFFFFF)
|
||||
private val secondaryContainerLight = Color(0xFFDAE2F9)
|
||||
private val onSecondaryContainerLight = Color(0xFF121C2B)
|
||||
private val tertiaryLight = Color(0xFF6F5575)
|
||||
private val onTertiaryLight = Color(0xFFFFFFFF)
|
||||
private val tertiaryContainerLight = Color(0xFFF9D8FD)
|
||||
private val onTertiaryContainerLight = Color(0xFF28132F)
|
||||
private val errorLight = Color(0xFFBA1A1A)
|
||||
private val onErrorLight = Color(0xFFFFFFFF)
|
||||
private val errorContainerLight = Color(0xFFFFDAD6)
|
||||
private val onErrorContainerLight = Color(0xFF410002)
|
||||
private val backgroundLight = Color(0xFFF9F9FF)
|
||||
private val onBackgroundLight = Color(0xFF191C20)
|
||||
private val surfaceLight = Color(0xFFF9F9FF)
|
||||
private val onSurfaceLight = Color(0xFF191C20)
|
||||
private val surfaceVariantLight = Color(0xFFE0E2EC)
|
||||
private val onSurfaceVariantLight = Color(0xFF44474E)
|
||||
private val outlineLight = Color(0xFF74777F)
|
||||
private val outlineVariantLight = Color(0xFFC4C6CF)
|
||||
private val scrimLight = Color(0xFF000000)
|
||||
private val inverseSurfaceLight = Color(0xFF2E3036)
|
||||
private val inverseOnSurfaceLight = Color(0xFFF0F0F7)
|
||||
private val inversePrimaryLight = Color(0xFFA9C7FF)
|
||||
private val surfaceDimLight = Color(0xFFD9D9E0)
|
||||
private val surfaceBrightLight = Color(0xFFF9F9FF)
|
||||
private val surfaceContainerLowestLight = Color(0xFFFFFFFF)
|
||||
private val surfaceContainerLowLight = Color(0xFFF3F3FA)
|
||||
private val surfaceContainerLight = Color(0xFFEDEDF4)
|
||||
private val surfaceContainerHighLight = Color(0xFFE7E8EE)
|
||||
private val surfaceContainerHighestLight = Color(0xFFE2E2E9)
|
||||
|
||||
private val primaryDark = Color(0xFFA9C7FF)
|
||||
private val onPrimaryDark = Color(0xFF08305F)
|
||||
private val primaryContainerDark = Color(0xFF274777)
|
||||
private val onPrimaryContainerDark = Color(0xFFD6E3FF)
|
||||
private val secondaryDark = Color(0xFFBDC7DC)
|
||||
private val onSecondaryDark = Color(0xFF283141)
|
||||
private val secondaryContainerDark = Color(0xFF3E4758)
|
||||
private val onSecondaryContainerDark = Color(0xFFDAE2F9)
|
||||
private val tertiaryDark = Color(0xFFDCBCE1)
|
||||
private val onTertiaryDark = Color(0xFF3F2845)
|
||||
private val tertiaryContainerDark = Color(0xFF563E5C)
|
||||
private val onTertiaryContainerDark = Color(0xFFF9D8FD)
|
||||
private val errorDark = Color(0xFFFFB4AB)
|
||||
private val onErrorDark = Color(0xFF690005)
|
||||
private val errorContainerDark = Color(0xFF93000A)
|
||||
private val onErrorContainerDark = Color(0xFFFFDAD6)
|
||||
private val backgroundDark = Color(0xFF111318)
|
||||
private val onBackgroundDark = Color(0xFFE2E2E9)
|
||||
private val surfaceDark = Color(0xFF111318)
|
||||
private val onSurfaceDark = Color(0xFFE2E2E9)
|
||||
private val surfaceVariantDark = Color(0xFF44474E)
|
||||
private val onSurfaceVariantDark = Color(0xFFC4C6CF)
|
||||
private val outlineDark = Color(0xFF8E9099)
|
||||
private val outlineVariantDark = Color(0xFF44474E)
|
||||
private val scrimDark = Color(0xFF000000)
|
||||
private val inverseSurfaceDark = Color(0xFFE2E2E9)
|
||||
private val inverseOnSurfaceDark = Color(0xFF2E3036)
|
||||
private val inversePrimaryDark = Color(0xFF405F90)
|
||||
private val surfaceDimDark = Color(0xFF111318)
|
||||
private val surfaceBrightDark = Color(0xFF37393E)
|
||||
private val surfaceContainerLowestDark = Color(0xFF0C0E13)
|
||||
private val surfaceContainerLowDark = Color(0xFF191C20)
|
||||
private val surfaceContainerDark = Color(0xFF1D2024)
|
||||
private val surfaceContainerHighDark = Color(0xFF282A2F)
|
||||
private val surfaceContainerHighestDark = Color(0xFF33353A)
|
||||
|
||||
val darkScheme = darkColorScheme(
|
||||
primary = primaryDark,
|
||||
onPrimary = onPrimaryDark,
|
||||
primaryContainer = primaryContainerDark,
|
||||
onPrimaryContainer = onPrimaryContainerDark,
|
||||
secondary = secondaryDark,
|
||||
onSecondary = onSecondaryDark,
|
||||
secondaryContainer = secondaryContainerDark,
|
||||
onSecondaryContainer = onSecondaryContainerDark,
|
||||
tertiary = tertiaryDark,
|
||||
onTertiary = onTertiaryDark,
|
||||
tertiaryContainer = tertiaryContainerDark,
|
||||
onTertiaryContainer = onTertiaryContainerDark,
|
||||
error = errorDark,
|
||||
onError = onErrorDark,
|
||||
errorContainer = errorContainerDark,
|
||||
onErrorContainer = onErrorContainerDark,
|
||||
background = backgroundDark,
|
||||
onBackground = onBackgroundDark,
|
||||
surface = surfaceDark,
|
||||
onSurface = onSurfaceDark,
|
||||
surfaceVariant = surfaceVariantDark,
|
||||
onSurfaceVariant = onSurfaceVariantDark,
|
||||
outline = outlineDark,
|
||||
outlineVariant = outlineVariantDark,
|
||||
scrim = scrimDark,
|
||||
inverseSurface = inverseSurfaceDark,
|
||||
inverseOnSurface = inverseOnSurfaceDark,
|
||||
inversePrimary = inversePrimaryDark,
|
||||
surfaceDim = surfaceDimDark,
|
||||
surfaceBright = surfaceBrightDark,
|
||||
surfaceContainerLowest = surfaceContainerLowestDark,
|
||||
surfaceContainerLow = surfaceContainerLowDark,
|
||||
surfaceContainer = surfaceContainerDark,
|
||||
surfaceContainerHigh = surfaceContainerHighDark,
|
||||
surfaceContainerHighest = surfaceContainerHighestDark,
|
||||
)
|
||||
|
||||
val lightScheme = lightColorScheme(
|
||||
primary = primaryLight,
|
||||
onPrimary = onPrimaryLight,
|
||||
primaryContainer = primaryContainerLight,
|
||||
onPrimaryContainer = onPrimaryContainerLight,
|
||||
secondary = secondaryLight,
|
||||
onSecondary = onSecondaryLight,
|
||||
secondaryContainer = secondaryContainerLight,
|
||||
onSecondaryContainer = onSecondaryContainerLight,
|
||||
tertiary = tertiaryLight,
|
||||
onTertiary = onTertiaryLight,
|
||||
tertiaryContainer = tertiaryContainerLight,
|
||||
onTertiaryContainer = onTertiaryContainerLight,
|
||||
error = errorLight,
|
||||
onError = onErrorLight,
|
||||
errorContainer = errorContainerLight,
|
||||
onErrorContainer = onErrorContainerLight,
|
||||
background = backgroundLight,
|
||||
onBackground = onBackgroundLight,
|
||||
surface = surfaceLight,
|
||||
onSurface = onSurfaceLight,
|
||||
surfaceVariant = surfaceVariantLight,
|
||||
onSurfaceVariant = onSurfaceVariantLight,
|
||||
outline = outlineLight,
|
||||
outlineVariant = outlineVariantLight,
|
||||
scrim = scrimLight,
|
||||
inverseSurface = inverseSurfaceLight,
|
||||
inverseOnSurface = inverseOnSurfaceLight,
|
||||
inversePrimary = inversePrimaryLight,
|
||||
surfaceDim = surfaceDimLight,
|
||||
surfaceBright = surfaceBrightLight,
|
||||
surfaceContainerLowest = surfaceContainerLowestLight,
|
||||
surfaceContainerLow = surfaceContainerLowLight,
|
||||
surfaceContainer = surfaceContainerLight,
|
||||
surfaceContainerHigh = surfaceContainerHighLight,
|
||||
surfaceContainerHighest = surfaceContainerHighestLight,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.meloda.app.fast.ui.util
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.view.KeyEvent
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.key.onKeyEvent
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.meloda.app.fast.common.UiText
|
||||
import com.meloda.app.fast.common.util.AndroidUtils
|
||||
|
||||
@Composable
|
||||
fun isUsingDarkTheme(): Boolean {
|
||||
// val nightThemeMode = AppCompatDelegate.MODE_NIGHT_YES
|
||||
|
||||
// SettingsController.getInt(
|
||||
// SettingsKeys.KEY_APPEARANCE_DARK_THEME,
|
||||
// SettingsKeys.DEFAULT_VALUE_APPEARANCE_DARK_THEME
|
||||
// )
|
||||
// val appForceDarkMode = nightThemeMode == AppCompatDelegate.MODE_NIGHT_YES
|
||||
// val appBatterySaver = nightThemeMode == AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
val systemUiNightMode = context.resources.configuration.uiMode
|
||||
|
||||
val isSystemBatterySaver = AndroidUtils.isBatterySaverOn(context)
|
||||
val isSystemUsingDarkTheme =
|
||||
systemUiNightMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
|
||||
|
||||
return true
|
||||
// return appForceDarkMode || (appBatterySaver && isSystemBatterySaver) || (!appBatterySaver && isSystemUsingDarkTheme && nightThemeMode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UiText?.getString(): String? {
|
||||
return when (this) {
|
||||
is UiText.Resource -> {
|
||||
stringResource(id = resId)
|
||||
}
|
||||
|
||||
is UiText.ResourceParams -> {
|
||||
val processedArgs = args.map { any ->
|
||||
when (any) {
|
||||
is UiText -> any.getString().orEmpty()
|
||||
else -> any.toString()
|
||||
}
|
||||
}.toTypedArray()
|
||||
|
||||
stringResource(id = value, *processedArgs)
|
||||
}
|
||||
|
||||
is UiText.QuantityResource -> {
|
||||
pluralStringResource(id = resId, count = quantity, quantity)
|
||||
}
|
||||
|
||||
is UiText.Simple -> text
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun Modifier.handleTabKey(
|
||||
action: () -> Boolean
|
||||
): Modifier = this.onKeyEvent { event ->
|
||||
if (event.nativeKeyEvent.keyCode == KeyEvent.KEYCODE_TAB) {
|
||||
action.invoke()
|
||||
} else false
|
||||
}
|
||||
|
||||
fun Modifier.handleEnterKey(
|
||||
action: () -> Boolean
|
||||
): Modifier = this.onKeyEvent { event ->
|
||||
if (event.nativeKeyEvent.keyCode == KeyEvent.KEYCODE_ENTER) {
|
||||
action.invoke()
|
||||
} else false
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LazyListState.isScrollingUp(): Boolean {
|
||||
var previousIndex by remember(this) { mutableIntStateOf(firstVisibleItemIndex) }
|
||||
var previousScrollOffset by remember(this) { mutableIntStateOf(firstVisibleItemScrollOffset) }
|
||||
return remember(this) {
|
||||
derivedStateOf {
|
||||
if (previousIndex != firstVisibleItemIndex) {
|
||||
previousIndex > firstVisibleItemIndex
|
||||
} else {
|
||||
previousScrollOffset >= firstVisibleItemScrollOffset
|
||||
}.also {
|
||||
previousIndex = firstVisibleItemIndex
|
||||
previousScrollOffset = firstVisibleItemScrollOffset
|
||||
}
|
||||
}
|
||||
}.value
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.meloda.app.fast.ui.util
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
class ImmutableList<T>(val values: List<T>) : Iterable<T> {
|
||||
|
||||
constructor(size: Int, init: (index: Int) -> T) : this(MutableList(size, init))
|
||||
|
||||
operator fun get(index: Int): T? {
|
||||
values.singleOrNull()
|
||||
return values[index]
|
||||
}
|
||||
|
||||
inline fun forEach(action: (T) -> Unit) {
|
||||
for (element in values) action(element)
|
||||
}
|
||||
|
||||
inline fun <R> map(transform: (T) -> R): ImmutableList<R> {
|
||||
return values.map(transform).toImmutableList()
|
||||
}
|
||||
|
||||
inline fun <R> mapNotNull(transform: (T) -> R?): ImmutableList<R> {
|
||||
return values.mapNotNull(transform).toImmutableList()
|
||||
}
|
||||
|
||||
inline fun <R> mapIndexed(transform: (index: Int, T) -> R): ImmutableList<R> {
|
||||
return values.mapIndexed(transform).toImmutableList()
|
||||
}
|
||||
|
||||
fun singleOrNull(): T? {
|
||||
return if (values.size == 1) this[0] else null
|
||||
}
|
||||
|
||||
fun isEmpty(): Boolean = values.isEmpty()
|
||||
|
||||
fun isNotEmpty(): Boolean = !isEmpty()
|
||||
|
||||
inline fun singleOrNull(predicate: (T) -> Boolean): T? {
|
||||
var single: T? = null
|
||||
var found = false
|
||||
for (element in this) {
|
||||
if (predicate(element)) {
|
||||
if (found) return null
|
||||
single = element
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if (!found) return null
|
||||
return single
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun <T> copyOf(collection: Collection<T>): ImmutableList<T> =
|
||||
ImmutableList(collection.toList())
|
||||
|
||||
fun <T> List<T>.toImmutableList(): ImmutableList<T> = ImmutableList(this)
|
||||
|
||||
fun <T> empty(): ImmutableList<T> = ImmutableList(emptyList())
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<T> = values.listIterator()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,6c1.93,0 3.5,1.57 3.5,3.5S13.93,13 12,13s-3.5,-1.57 -3.5,-3.5S10.07,6 12,6zM12,20c-2.03,0 -4.43,-0.82 -6.14,-2.88C7.55,15.8 9.68,15 12,15s4.45,0.8 6.14,2.12C16.43,19.18 14.03,20 12,20z"/>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM6,9h12v2L6,11L6,9zM14,14L6,14v-2h8v2zM18,8L6,8L6,6h12v2z"/>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:fillType="evenOdd" android:pathData="M16.67,13.13C18.04,14.06 19,15.32 19,17v3h4v-3C23,14.82 19.43,13.53 16.67,13.13z"/>
|
||||
|
||||
<path android:fillColor="@android:color/white" android:fillType="evenOdd" android:pathData="M9,8m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"/>
|
||||
|
||||
<path android:fillColor="@android:color/white" android:fillType="evenOdd" android:pathData="M15,12c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4c-0.47,0 -0.91,0.1 -1.33,0.24C14.5,5.27 15,6.58 15,8s-0.5,2.73 -1.33,3.76C14.09,11.9 14.53,12 15,12z"/>
|
||||
|
||||
<path android:fillColor="@android:color/white" android:fillType="evenOdd" android:pathData="M9,13c-2.67,0 -8,1.34 -8,4v3h16v-3C17,14.34 11.67,13 9,13z"/>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M24,0C10.7452,0 0,10.7452 0,24C0,37.2548 10.7452,48 24,48C37.2548,48 48,37.2548 48,24C48,10.7452 37.2548,0 24,0ZM32.25,13.8152C32.25,9.4191 28.7383,6 24.5,6C20.2617,6 16.75,9.4191 16.75,13.8152C16.75,18.0891 20.2617,21.6304 24.5,21.6304C28.7383,21.6304 32.25,18.0891 32.25,13.8152ZM9,34.5743C12.3906,39.5809 18.082,43 24.5,43C30.918,43 36.6094,39.5809 40,34.5743C39.8789,29.3234 29.5859,26.5149 24.5,26.5149C19.293,26.5149 9.1211,29.3234 9,34.5743Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M5,13L16.17,13l-4.88,4.88a1.008,1.008 0,0 0,-0 1.42,1 1,0 0,0 1.41,-0L19.29,12.71a1,1 0,0 0,-0 -1.41l-6.59,-6.59a1,1 0,0 0,-1.41 1.41L16.17,11L5,11a1,1 0,0 0,-0 2Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M12 3V13.55C11.41 13.21 10.73 13 10 13C7.79 13 6 14.79 6 17S7.79 21 10 21 14 19.21 14 17V7H18V3H12Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M6.62,10.79C8.06,13.62 10.38,15.94 13.21,17.38L15.41,15.18C15.69,14.9 16.08,14.82 16.43,14.93C17.55,15.3 18.75,15.5 20,15.5A1,1 0 0,1 21,16.5V20A1,1 0 0,1 20,21A17,17 0 0,1 3,4A1,1 0 0,1 4,3H7.5A1,1 0 0,1 8.5,4C8.5,5.25 8.7,6.45 9.07,7.57C9.18,7.92 9.1,8.31 8.82,8.59L6.62,10.79Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10,9V5l-7,7 7,7v-4.1c5,0 8.5,1.6 11,5.1 -1,-5 -4,-10 -11,-11z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M13,9V5L6,12L13,19V14.9C18,14.9 21.5,16.5 24,20C23,15 20,10 13,9M7,8V5L0,12L7,19V16L3,12L7,8Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M9.06,1.93C7.17,1.92 5.33,3.74 6.17,6H3A2,2 0 0,0 1,8V10A1,1 0 0,0 2,11H11V8H13V11H22A1,1 0 0,0 23,10V8A2,2 0 0,0 21,6H17.83C19,2.73 14.6,0.42 12.57,3.24L12,4L11.43,3.22C10.8,2.33 9.93,1.94 9.06,1.93M9,4C9.89,4 10.34,5.08 9.71,5.71C9.08,6.34 8,5.89 8,5A1,1 0 0,1 9,4M15,4C15.89,4 16.34,5.08 15.71,5.71C15.08,6.34 14,5.89 14,5A1,1 0 0,1 15,4M2,12V20A2,2 0 0,0 4,22H20A2,2 0 0,0 22,20V12H13V20H11V12H2Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M10,4H12V6H10V4M7,3H9V5H7V3M7,6H9V8H7V6M6,8V10H4V8H6M6,5V7H4V5H6M6,2V4H4V2H6M13,22A2,2 0 0,1 11,20V10A2,2 0 0,1 13,8V7H14V4H17V7H18V8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H13M13,10V20H18V10H13Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M20 15.5C18.75 15.5 17.55 15.3 16.43 14.93C16.08 14.82 15.69 14.9 15.41 15.17L13.21 17.37C10.38 15.93 8.06 13.62 6.62 10.79L8.82 8.58C9.1 8.31 9.18 7.92 9.07 7.57C8.7 6.45 8.5 5.25 8.5 4C8.5 3.45 8.05 3 7.5 3H4C3.45 3 3 3.45 3 4C3 13.39 10.61 21 20 21C20.55 21 21 20.55 21 20V16.5C21 15.95 20.55 15.5 20 15.5M12 3V13L15 10H21V3H12Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M16.36,14C16.44,13.34 16.5,12.68 16.5,12C16.5,11.32 16.44,10.66 16.36,10H19.74C19.9,10.64 20,11.31 20,12C20,12.69 19.9,13.36 19.74,14M14.59,19.56C15.19,18.45 15.65,17.25 15.97,16H18.92C17.96,17.65 16.43,18.93 14.59,19.56M14.34,14H9.66C9.56,13.34 9.5,12.68 9.5,12C9.5,11.32 9.56,10.65 9.66,10H14.34C14.43,10.65 14.5,11.32 14.5,12C14.5,12.68 14.43,13.34 14.34,14M12,19.96C11.17,18.76 10.5,17.43 10.09,16H13.91C13.5,17.43 12.83,18.76 12,19.96M8,8H5.08C6.03,6.34 7.57,5.06 9.4,4.44C8.8,5.55 8.35,6.75 8,8M5.08,16H8C8.35,17.25 8.8,18.45 9.4,19.56C7.57,18.93 6.03,17.65 5.08,16M4.26,14C4.1,13.36 4,12.69 4,12C4,11.31 4.1,10.64 4.26,10H7.64C7.56,10.66 7.5,11.32 7.5,12C7.5,12.68 7.56,13.34 7.64,14M12,4.03C12.83,5.23 13.5,6.57 13.91,8H10.09C10.5,6.57 11.17,5.23 12,4.03M18.92,8H15.97C15.65,6.75 15.19,5.55 14.59,4.44C16.43,5.07 17.96,6.34 18.92,8M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3M7,7V9H9V7H7M11,7V9H13V7H11M15,7V9H17V7H15M7,11V13H9V11H7M11,11V13H13V11H11M15,11V13H17V11H15M7,15V17H9V15H7M11,15V17H13V15H11M15,15V17H17V15H15Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M19 3H5C3.9 3 3 3.9 3 5V19C3 20.1 3.9 21 5 21H19C20.1 21 21 20.1 21 19V5C21 3.9 20.1 3 19 3M9 17H7V10H9V17M13 17H11V7H13V17M17 17H15V13H17V17Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M5.5,2C3.56,2 2,3.56 2,5.5V18.5C2,20.44 3.56,22 5.5,22H16L22,16V5.5C22,3.56 20.44,2 18.5,2H5.5M5.75,4H18.25A1.75,1.75 0 0,1 20,5.75V15H18.5C16.56,15 15,16.56 15,18.5V20H5.75A1.75,1.75 0 0,1 4,18.25V5.75A1.75,1.75 0 0,1 5.75,4M14.44,6.77C14.28,6.77 14.12,6.79 13.97,6.83C13.03,7.09 12.5,8.05 12.74,9C12.79,9.15 12.86,9.3 12.95,9.44L16.18,8.56C16.18,8.39 16.16,8.22 16.12,8.05C15.91,7.3 15.22,6.77 14.44,6.77M8.17,8.5C8,8.5 7.85,8.5 7.7,8.55C6.77,8.81 6.22,9.77 6.47,10.7C6.5,10.86 6.59,11 6.68,11.16L9.91,10.28C9.91,10.11 9.89,9.94 9.85,9.78C9.64,9 8.95,8.5 8.17,8.5M16.72,11.26L7.59,13.77C8.91,15.3 11,15.94 12.95,15.41C14.9,14.87 16.36,13.25 16.72,11.26Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M15.1,19.37l1,1.74c-0.96,0.44 -2.01,0.73 -3.1,0.84v-2.02C13.74,19.84 14.44,19.65 15.1,19.37zM4.07,13H2.05c0.11,1.1 0.4,2.14 0.84,3.1l1.74,-1C4.35,14.44 4.16,13.74 4.07,13zM15.1,4.63l1,-1.74C15.14,2.45 14.1,2.16 13,2.05v2.02C13.74,4.16 14.44,4.35 15.1,4.63zM19.93,11h2.02c-0.11,-1.1 -0.4,-2.14 -0.84,-3.1l-1.74,1C19.65,9.56 19.84,10.26 19.93,11zM8.9,19.37l-1,1.74c0.96,0.44 2.01,0.73 3.1,0.84v-2.02C10.26,19.84 9.56,19.65 8.9,19.37zM11,4.07V2.05c-1.1,0.11 -2.14,0.4 -3.1,0.84l1,1.74C9.56,4.35 10.26,4.16 11,4.07zM18.36,7.17l1.74,-1.01c-0.63,-0.87 -1.4,-1.64 -2.27,-2.27l-1.01,1.74C17.41,6.08 17.92,6.59 18.36,7.17zM4.63,8.9l-1.74,-1C2.45,8.86 2.16,9.9 2.05,11h2.02C4.16,10.26 4.35,9.56 4.63,8.9zM19.93,13c-0.09,0.74 -0.28,1.44 -0.56,2.1l1.74,1c0.44,-0.96 0.73,-2.01 0.84,-3.1H19.93zM16.83,18.36l1.01,1.74c0.87,-0.63 1.64,-1.4 2.27,-2.27l-1.74,-1.01C17.92,17.41 17.41,17.92 16.83,18.36zM7.17,5.64L6.17,3.89C5.29,4.53 4.53,5.29 3.9,6.17l1.74,1.01C6.08,6.59 6.59,6.08 7.17,5.64zM5.64,16.83L3.9,17.83c0.63,0.87 1.4,1.64 2.27,2.27l1.01,-1.74C6.59,17.92 6.08,17.41 5.64,16.83zM13,7h-2v5.41l4.29,4.29l1.41,-1.41L13,11.59V7z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M19 3C20.1 3 21 3.9 21 5V19C21 20.1 20.1 21 19 21H5C3.9 21 3 20.1 3 19V5C3 3.9 3.9 3 5 3H19M7 18V16H5V18H7M7 13V11H5V13H7M7 8V6H5V8H7M19 18V16H17V18H19M19 13V11H17V13H19M19 8V6H17V8H19Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#ffffff" android:pathData="M12,2A3,3 0 0,1 15,5V11A3,3 0 0,1 12,14A3,3 0 0,1 9,11V5A3,3 0 0,1 12,2M19,11C19,14.53 16.39,17.44 13,17.93V21H11V17.93C7.61,17.44 5,14.53 5,11H7A5,5 0 0,0 12,16A5,5 0 0,0 17,11H19Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M3,16H12V21H3V16M2,10H8V15H2V10M9,10H15V15H9V10M16,10H22V15H16V10M13,16H21V21H13V16M3,4H11V9H3V4M12,4H21V9H12V4Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M21.99,4c0,-1.1 -0.89,-2 -1.99,-2L4,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h14l4,4 -0.01,-18zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16.5,6v11.5c0,2.21 -1.79,4 -4,4s-4,-1.79 -4,-4V5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5v10.5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V6H10v9.5c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5V5c0,-2.21 -1.79,-4 -4,-4S7,2.79 7,5v12.5c0,3.04 2.46,5.5 5.5,5.5s5.5,-2.46 5.5,-5.5V6h-1.5z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,20 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M13.3062,5.676L10.7577,9.5805C10.5295,9.9302 10.7804,10.3936 11.198,10.3936H13.3062V5.676Z"
|
||||
android:strokeAlpha="0.7"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.7"/>
|
||||
<path
|
||||
android:pathData="M11.3743,2.4787C11.9457,1.6031 13.3062,2.0078 13.3062,3.0534V13.6065H6.0532C5.218,13.6065 4.7162,12.6797 5.1727,11.9803L11.3743,2.4787ZM10.7577,9.5805L13.3062,5.6759V10.3936H11.198C10.7804,10.3936 10.5295,9.9302 10.7577,9.5805Z"
|
||||
android:strokeAlpha="0.5"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"
|
||||
android:fillAlpha="0.5"/>
|
||||
<path
|
||||
android:pathData="M11.1981,10.3936C10.9034,10.3936 10.6918,10.1629 10.6729,9.9042V10.4785H10.6784V20.9467C10.6784,21.9923 12.0389,22.397 12.6104,21.5214L18.8119,12.0197C19.2684,11.3203 18.7666,10.3936 17.9314,10.3936H11.1981Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,25 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group android:scaleX="0.0684812"
|
||||
android:scaleY="0.0684812"
|
||||
android:translateX="31.503925"
|
||||
android:translateY="27.977142">
|
||||
<path
|
||||
android:pathData="M371.796,170.753L288.208,298.822C280.722,310.291 288.951,325.49 302.648,325.49H371.796V170.753Z"
|
||||
android:strokeAlpha="0.7"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.7"/>
|
||||
<path
|
||||
android:pathData="M308.429,65.884C327.174,37.164 371.796,50.438 371.796,84.733V430.872H133.9C106.507,430.872 90.048,400.474 105.02,377.536L308.429,65.884ZM288.208,298.822L371.796,170.753V325.49H302.648C288.951,325.49 280.722,310.291 288.208,298.822Z"
|
||||
android:strokeAlpha="0.5"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"
|
||||
android:fillAlpha="0.5"/>
|
||||
<path
|
||||
android:pathData="M302.648,325.49C292.984,325.49 286.042,317.924 285.421,309.439V328.275H285.604V671.629C285.604,705.925 330.226,719.198 348.97,690.478L552.38,378.827C567.352,355.888 550.893,325.49 523.5,325.49H302.648Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</group>
|
||||
</vector>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="134dp"
|
||||
android:height="191dp"
|
||||
android:viewportWidth="134"
|
||||
android:viewportHeight="191">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.7"
|
||||
android:pathData="M79 34.96L54.76 72.1c-2.17 3.32 0.22 7.73 4.19 7.73H79V34.96Z"/>
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillAlpha="0.5"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M60.62 4.55C66.06-3.78 79 0.07 79 10.02v100.37H10.02c-7.95 0-12.72-8.82-8.38-15.47L60.62 4.55ZM54.76 72.1L79 34.96v44.87H58.95c-3.97 0-6.36-4.4-4.19-7.73Z"/>
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M58.95 79.83c-2.8 0-4.82-2.2-5-4.66v5.47h0.06v99.56c0 9.94 12.93 13.79 18.37 5.46l58.98-90.37c4.34-6.65-0.43-15.46-8.37-15.46H58.95Z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M12,11.5A2.5,2.5 0 0,1 9.5,9A2.5,2.5 0 0,1 12,6.5A2.5,2.5 0 0,1 14.5,9A2.5,2.5 0 0,1 12,11.5M12,2A7,7 0 0,0 5,9C5,14.25 12,22 12,22C12,22 19,14.25 19,9A7,7 0 0,0 12,2Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,18 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M15.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M8.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,18c2.28,0 4.22,-1.66 5,-4H7C7.78,16.34 9.72,18 12,18z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M11.99,2C6.47,2 2,6.48 2,12c0,5.52 4.47,10 9.99,10C17.52,22 22,17.52 22,12C22,6.48 17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8c0,-4.42 3.58,-8 8,-8s8,3.58 8,8C20,16.42 16.42,20 12,20z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="28dp"
|
||||
android:height="28dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,7c-0.55,0 -1,0.45 -1,1v3L8,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h3v3c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-3h3c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3L13,8c0,-0.55 -0.45,-1 -1,-1zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,11H7.83l4.88,-4.88c0.39,-0.39 0.39,-1.03 0,-1.42 -0.39,-0.39 -1.02,-0.39 -1.41,0l-6.59,6.59c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L7.83,13H19c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17,3L7,3c-1.1,0 -2,0.9 -2,2v16l7,-3 7,3L19,5c0,-1.1 -0.9,-2 -2,-2zM17,18l-5,-2.18L7,18L7,6c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1v12z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M18.3,5.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,10.59 7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,13.41l4.89,4.89c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l4.89,-4.89c0.38,-0.38 0.38,-1.02 0,-1.4z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M9,16.2l-3.5,-3.5c-0.39,-0.39 -1.01,-0.39 -1.4,0 -0.39,0.39 -0.39,1.01 0,1.4l4.19,4.19c0.39,0.39 1.02,0.39 1.41,0L20.3,7.7c0.39,-0.39 0.39,-1.01 0,-1.4 -0.39,-0.39 -1.01,-0.39 -1.4,0L9,16.2z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,14c1.66,0 3,-1.34 3,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L11,5zM17.91,11c-0.49,0 -0.9,0.36 -0.98,0.85C16.52,14.2 14.47,16 12,16s-4.52,-1.8 -4.93,-4.15c-0.08,-0.49 -0.49,-0.85 -0.98,-0.85 -0.61,0 -1.09,0.54 -1,1.14 0.49,3 2.89,5.35 5.91,5.78L11,20c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-2.08c3.02,-0.43 5.42,-2.78 5.91,-5.78 0.1,-0.6 -0.39,-1.14 -1,-1.14z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v1c0,0.55 0.45,1 1,1h14c0.55,0 1,-0.45 1,-1v-1c0,-2.66 -5.33,-4 -8,-4z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M19,12.87c0,-0.47 -0.34,-0.85 -0.8,-0.98C16.93,11.54 16,10.38 16,9V4l1,0c0.55,0 1,-0.45 1,-1c0,-0.55 -0.45,-1 -1,-1H7C6.45,2 6,2.45 6,3c0,0.55 0.45,1 1,1l1,0v5c0,1.38 -0.93,2.54 -2.2,2.89C5.34,12.02 5,12.4 5,12.87V13c0,0.55 0.45,1 1,1h4.98L11,21c0,0.55 0.45,1 1,1c0.55,0 1,-0.45 1,-1l-0.02,-7H18c0.55,0 1,-0.45 1,-1V12.87z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM7.35,18.5C8.66,17.56 10.26,17 12,17s3.34,0.56 4.65,1.5C15.34,19.44 13.74,20 12,20S8.66,19.44 7.35,18.5zM18.14,17.12L18.14,17.12C16.45,15.8 14.32,15 12,15s-4.45,0.8 -6.14,2.12l0,0C4.7,15.73 4,13.95 4,12c0,-4.42 3.58,-8 8,-8s8,3.58 8,8C20,13.95 19.3,15.73 18.14,17.12z"/>
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,6c-1.93,0 -3.5,1.57 -3.5,3.5S10.07,13 12,13s3.5,-1.57 3.5,-3.5S13.93,6 12,6zM12,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S11.17,8 12,8s1.5,0.67 1.5,1.5S12.83,11 12,11z"/>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M4,4h16v12L5.17,16L4,17.17L4,4m0,-2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2L4,2zM6,12h8v2L6,14v-2zM6,9h12v2L6,11L6,9zM6,6h12v2L6,8L6,6z"/>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M16.67,13.13C18.04,14.06 19,15.32 19,17v3h4v-3C23,14.82 19.43,13.53 16.67,13.13z"/>
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M15,12c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4c-0.47,0 -0.91,0.1 -1.33,0.24C14.5,5.27 15,6.58 15,8s-0.5,2.73 -1.33,3.76C14.09,11.9 14.53,12 15,12z"/>
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M9,12c2.21,0 4,-1.79 4,-4c0,-2.21 -1.79,-4 -4,-4S5,5.79 5,8C5,10.21 6.79,12 9,12zM9,6c1.1,0 2,0.9 2,2c0,1.1 -0.9,2 -2,2S7,9.1 7,8C7,6.9 7.9,6 9,6z"/>
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M9,13c-2.67,0 -8,1.34 -8,4v3h16v-3C17,14.34 11.67,13 9,13zM15,18H3l0,-0.99C3.2,16.29 6.3,15 9,15s5.8,1.29 6,2V18z"/>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M8,6.2V4H7V2H17V4H16V12L18,14V16H17.8L14,12.2V4H10V8.2L8,6.2M20,20.7L18.7,22L12.8,16.1V22H11.2V16H6V14L8,12V11.3L2,5.3L3.3,4L20,20.7M8.8,14H10.6L9.7,13.1L8.8,14Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12M8.8,14L10,12.8V4H14V12.8L15.2,14H8.8Z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M16.5,6.75v10.58c0,2.09 -1.53,3.95 -3.61,4.15 -2.39,0.23 -4.39,-1.64 -4.39,-3.98V5.14c0,-1.31 0.94,-2.5 2.24,-2.63 1.5,-0.15 2.76,1.02 2.76,2.49v10.5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V6.75c0,-0.41 -0.34,-0.75 -0.75,-0.75s-0.75,0.34 -0.75,0.75v8.61c0,1.31 0.94,2.5 2.24,2.63 1.5,0.15 2.76,-1.02 2.76,-2.49V5.17c0,-2.09 -1.53,-3.95 -3.61,-4.15C9.01,0.79 7,2.66 7,5v12.27c0,2.87 2.1,5.44 4.96,5.71 3.29,0.3 6.04,-2.26 6.04,-5.48V6.75c0,-0.41 -0.34,-0.75 -0.75,-0.75s-0.75,0.34 -0.75,0.75z"/>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12.68,5.88c0.7,-0.24 1.22,-0.9 1.3,-1.64 0.05,-0.47 -0.05,-0.91 -0.28,-1.27L12.42,0.75c-0.19,-0.33 -0.67,-0.33 -0.87,0l-1.28,2.22c-0.17,0.3 -0.27,0.65 -0.27,1.03 0,1.32 1.3,2.35 2.68,1.88zM16.53,15.92l-1,-1 -1.08,1.07c-1.3,1.3 -3.58,1.31 -4.89,0l-1.07,-1.07 -1.09,1.07C6.75,16.64 5.88,17 4.96,17c-0.73,0 -1.4,-0.23 -1.96,-0.61L3,20c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-3.61c-0.75,0.51 -1.71,0.75 -2.74,0.52 -0.66,-0.14 -1.25,-0.51 -1.73,-0.99zM18,9h-5L13,8c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L6,9c-1.66,0 -3,1.34 -3,3v1.46c0,0.85 0.5,1.67 1.31,1.94 0.73,0.24 1.52,0.06 2.03,-0.46l2.14,-2.13 2.13,2.13c0.76,0.76 2.01,0.76 2.77,0l2.14,-2.13 2.13,2.13c0.43,0.43 1.03,0.63 1.65,0.55 0.99,-0.13 1.69,-1.06 1.69,-2.06v-1.42C21,10.34 19.66,9 18,9z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,9c0,-1.1 -0.9,-2 -2,-2L8,7c-1.1,0 -2,0.9 -2,2v10zM9,9h6c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1L9,19c-0.55,0 -1,-0.45 -1,-1v-8c0,-0.55 0.45,-1 1,-1zM15.5,4l-0.71,-0.71c-0.18,-0.18 -0.44,-0.29 -0.7,-0.29L9.91,3c-0.26,0 -0.52,0.11 -0.7,0.29L8.5,4L6,4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2.5z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17.3,6.3c-0.39,-0.39 -1.02,-0.39 -1.41,0l-5.64,5.64 1.41,1.41L17.3,7.7c0.38,-0.38 0.38,-1.02 0,-1.4zM21.54,6.29l-9.88,9.88 -3.48,-3.47c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l4.18,4.18c0.39,0.39 1.02,0.39 1.41,0L22.95,7.71c0.39,-0.39 0.39,-1.02 0,-1.41h-0.01c-0.38,-0.4 -1.01,-0.4 -1.4,-0.01zM1.12,14.12L5.3,18.3c0.39,0.39 1.02,0.39 1.41,0l0.7,-0.7 -4.88,-4.9c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.03 0,1.42z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16.59,9H15V4c0,-0.55 -0.45,-1 -1,-1h-4C9.45,3 9,3.45 9,4v5H7.41c-0.89,0 -1.34,1.08 -0.71,1.71l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59C17.92,10.08 17.48,9 16.59,9zM5,19c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1H6C5.45,18 5,18.45 5,19z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M18.71,13.29l3.59,-3.59c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0L19,10.17V4c0,-0.55 -0.45,-1 -1,-1h0c-0.55,0 -1,0.45 -1,1v6.17l-1.89,-1.88c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41l3.59,3.59C17.69,13.68 18.32,13.68 18.71,13.29z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17,18H7V6h7V1H7C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-5h-2V18z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,39 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M5,11h4c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2H5C3.9,3 3,3.9 3,5v4C3,10.1 3.9,11 5,11zM5,5h4v4H5V5z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M5,21h4c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v4C3,20.1 3.9,21 5,21zM5,15h4v4H5V15z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M13,5v4c0,1.1 0.9,2 2,2h4c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2h-4C13.9,3 13,3.9 13,5zM19,9h-4V5h4V9z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M21,20.5v-1c0,-0.28 -0.22,-0.5 -0.5,-0.5h-1c-0.28,0 -0.5,0.22 -0.5,0.5v1c0,0.28 0.22,0.5 0.5,0.5h1C20.78,21 21,20.78 21,20.5z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M13,13.5v1c0,0.28 0.22,0.5 0.5,0.5h1c0.28,0 0.5,-0.22 0.5,-0.5v-1c0,-0.28 -0.22,-0.5 -0.5,-0.5h-1C13.22,13 13,13.22 13,13.5z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16.5,15h-1c-0.28,0 -0.5,0.22 -0.5,0.5v1c0,0.28 0.22,0.5 0.5,0.5h1c0.28,0 0.5,-0.22 0.5,-0.5v-1C17,15.22 16.78,15 16.5,15z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M13,17.5v1c0,0.28 0.22,0.5 0.5,0.5h1c0.28,0 0.5,-0.22 0.5,-0.5v-1c0,-0.28 -0.22,-0.5 -0.5,-0.5h-1C13.22,17 13,17.22 13,17.5z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M15.5,21h1c0.28,0 0.5,-0.22 0.5,-0.5v-1c0,-0.28 -0.22,-0.5 -0.5,-0.5h-1c-0.28,0 -0.5,0.22 -0.5,0.5v1C15,20.78 15.22,21 15.5,21z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17.5,19h1c0.28,0 0.5,-0.22 0.5,-0.5v-1c0,-0.28 -0.22,-0.5 -0.5,-0.5h-1c-0.28,0 -0.5,0.22 -0.5,0.5v1C17,18.78 17.22,19 17.5,19z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M18.5,13h-1c-0.28,0 -0.5,0.22 -0.5,0.5v1c0,0.28 0.22,0.5 0.5,0.5h1c0.28,0 0.5,-0.22 0.5,-0.5v-1C19,13.22 18.78,13 18.5,13z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19.5,17h1c0.28,0 0.5,-0.22 0.5,-0.5v-1c0,-0.28 -0.22,-0.5 -0.5,-0.5h-1c-0.28,0 -0.5,0.22 -0.5,0.5v1C19,16.78 19.22,17 19.5,17z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,5V3.21c0,-0.45 -0.54,-0.67 -0.85,-0.35L8.35,5.65c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79C11.46,9.46 12,9.24 12,8.79V7c3.31,0 6,2.69 6,6c0,2.72 -1.83,5.02 -4.31,5.75C13.27,18.87 13,19.27 13,19.7v0c0,0.65 0.62,1.16 1.25,0.97C17.57,19.7 20,16.64 20,13C20,8.58 16.42,5 12,5z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M6,13c0,-1.34 0.44,-2.58 1.19,-3.59c0.3,-0.4 0.26,-0.95 -0.09,-1.31l0,0C6.68,7.68 5.96,7.72 5.6,8.2C4.6,9.54 4,11.2 4,13c0,3.64 2.43,6.7 5.75,7.67C10.38,20.86 11,20.35 11,19.7v0c0,-0.43 -0.27,-0.83 -0.69,-0.95C7.83,18.02 6,15.72 6,13z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:autoMirrored="true"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3.4,20.4l17.45,-7.48c0.81,-0.35 0.81,-1.49 0,-1.84L3.4,3.6c-0.66,-0.29 -1.39,0.2 -1.39,0.91L2,9.12c0,0.5 0.37,0.93 0.87,0.99L17,12 2.87,13.88c-0.5,0.07 -0.87,0.5 -0.87,1l0.01,4.61c0,0.71 0.73,1.2 1.39,0.91z" />
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM9,11L7,11L7,9h2v2zM13,11h-2L11,9h2v2zM17,11h-2L15,9h2v2z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,4C7,4 2.73,7.11 1,11.5 2.73,15.89 7,19 12,19s9.27,-3.11 11,-7.5C21.27,7.11 17,4 12,4zM12,16.5c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,8.5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,6.5c2.76,0 5,2.24 5,5 0,0.51 -0.1,1 -0.24,1.46l3.06,3.06c1.39,-1.23 2.49,-2.77 3.18,-4.53C21.27,7.11 17,4 12,4c-1.27,0 -2.49,0.2 -3.64,0.57l2.17,2.17c0.47,-0.14 0.96,-0.24 1.47,-0.24zM2.71,3.16c-0.39,0.39 -0.39,1.02 0,1.41l1.97,1.97C3.06,7.83 1.77,9.53 1,11.5 2.73,15.89 7,19 12,19c1.52,0 2.97,-0.3 4.31,-0.82l2.72,2.72c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L4.13,3.16c-0.39,-0.39 -1.03,-0.39 -1.42,0zM12,16.5c-2.76,0 -5,-2.24 -5,-5 0,-0.77 0.18,-1.5 0.49,-2.14l1.57,1.57c-0.03,0.18 -0.06,0.37 -0.06,0.57 0,1.66 1.34,3 3,3 0.2,0 0.38,-0.03 0.57,-0.07L14.14,16c-0.65,0.32 -1.37,0.5 -2.14,0.5zM14.97,11.17c-0.15,-1.4 -1.25,-2.49 -2.64,-2.64l2.64,2.64z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12.65,10C11.7,7.31 8.9,5.5 5.77,6.12c-2.29,0.46 -4.15,2.29 -4.63,4.58C0.32,14.57 3.26,18 7,18c2.61,0 4.83,-1.67 5.65,-4H17v2c0,1.1 0.9,2 2,2s2,-0.9 2,-2v-2c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2h-8.35zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z" />
|
||||
</vector>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 688 B |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,201 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="message_attachment">Вложение</string>
|
||||
<string name="message_attachments_many">Вложения</string>
|
||||
<string name="sign_out_confirm">При выходе из учётной записи с устройства будут удалены все связанные с ней данные. Продолжить?</string>
|
||||
<string name="yes">Да</string>
|
||||
<string name="no">Нет</string>
|
||||
<string name="message_context_action_reply">Ответить</string>
|
||||
<string name="message_context_action_mark_as_important">Пометить как важное</string>
|
||||
<string name="message_context_action_unmark_as_important">Помететить как не важное</string>
|
||||
<string name="time_format">Время: %1$s</string>
|
||||
<string name="message_context_action_pin">Закрепить</string>
|
||||
<string name="message_context_action_unpin">Открепить</string>
|
||||
<string name="message_context_action_edit">Изменить</string>
|
||||
<string name="message_context_action_delete">Удалить</string>
|
||||
<string name="confirm_delete_message">Удалить сообщение?</string>
|
||||
<string name="message_delete_for_all">Для всех</string>
|
||||
<string name="message_mark_as_spam">Пометить как спам</string>
|
||||
<string name="action_mark_as_read">Пометить как прочитанное</string>
|
||||
<string name="action_delete">Удалить</string>
|
||||
<string name="conversation_context_action_delete">Удалить</string>
|
||||
<string name="confirm_delete_conversation">Удалить чат?</string>
|
||||
<string name="action_sign_out">Выйти</string>
|
||||
<string name="sign_out_confirm_title">Выйти?</string>
|
||||
<string name="conversation_context_action_unpin">Открепить</string>
|
||||
<string name="conversation_context_action_pin">Закрепить</string>
|
||||
<string name="confirm_unpin_conversation">Открепить чат?</string>
|
||||
<string name="confirm_pin_conversation">Закрепить чат?</string>
|
||||
<string name="action_pin">Закрепить</string>
|
||||
<string name="action_unpin">Открепить</string>
|
||||
<string name="message_call_type_outgoing">Исходящий вызов</string>
|
||||
<string name="message_call_type_incoming">Входящий вызов</string>
|
||||
<string name="message_call_state_ended">Закончился</string>
|
||||
<string name="message_call_state_cancelled">Отменён</string>
|
||||
<string name="message_call_state_missed">Пропущенный</string>
|
||||
<string name="message_call_unknown">Неизвестный</string>
|
||||
<string name="confirm_pin_message">Закрепить сообщение?</string>
|
||||
<string name="confirm_unpin_message">Открепить сообщение?</string>
|
||||
<string name="title_messages">Сообщения</string>
|
||||
<string name="title_forwarded_messages">Пересланные сообщения</string>
|
||||
<string name="title_settings">Настройки</string>
|
||||
<string name="error_occurred">Произошла ошибка</string>
|
||||
<string name="error_occurred_description">Ошибка: %1$s</string>
|
||||
<string name="title_error">Ошибка</string>
|
||||
<string name="password_login_hint">Пароль</string>
|
||||
<string name="captcha_hint">Код капчи</string>
|
||||
<string name="input_captcha">Введите код с картинки</string>
|
||||
<string name="login_hint">Логин</string>
|
||||
<string name="error_empty_field">Поле не должно быть пустым</string>
|
||||
<string name="code_hint">Код</string>
|
||||
<string name="input_validation_code">Введите код из смс</string>
|
||||
<string name="you_message_prefix">Вы</string>
|
||||
<string name="message_geo">Геолокация</string>
|
||||
<string name="message_geo_point">Точка</string>
|
||||
<string name="forwarded_message">Сообщение</string>
|
||||
<string name="forwarded_messages">Сообщения</string>
|
||||
<string name="no_messages">Нет сообщений</string>
|
||||
<string name="messages_self_destructed">Сообщение самоуничтожилось</string>
|
||||
<string name="action_refresh">Обновить</string>
|
||||
<string name="message_input_hint">Сообщение…</string>
|
||||
<string name="input_login_hint">Введите логин</string>
|
||||
<string name="input_password_hint">Введите пароль</string>
|
||||
<string name="input_code_hint">Введите код</string>
|
||||
<string name="validation_required">Нужна валидация</string>
|
||||
<string name="unknown_error_occurred">Произошла неизвестная ошибка</string>
|
||||
<string name="authorization_failed">Ошибка авторизации</string>
|
||||
<string name="token_expired">Токен недействителен</string>
|
||||
<string name="message_action_chat_created">%1$s создал(-а) «%2$s»</string>
|
||||
<string name="message_action_chat_renamed">%1$s переименовал(-а) чат в «%2$s»</string>
|
||||
<string name="message_action_chat_photo_update">%1$s обновил(-а) фото беседы</string>
|
||||
<string name="message_action_chat_photo_remove">%1$s удалил(-а) фото беседы</string>
|
||||
<string name="message_action_chat_user_left">%1$s вышел(-ла) из чата</string>
|
||||
<string name="message_action_chat_user_kicked">%1$s исключил %2$s</string>
|
||||
<string name="message_action_chat_user_returned">%1$s вернулся(-лась) в беседу</string>
|
||||
<string name="message_action_chat_user_invited">%1$s пригласил(-а) %2$s</string>
|
||||
<string name="message_action_chat_user_joined_by_link">%1$s присоединился(-лась) в беседу через ссылку</string>
|
||||
<string name="message_action_chat_user_joined_by_call">%1$s присоединился(-лась) к звонку</string>
|
||||
<string name="message_action_chat_user_joined_by_call_link">%1$s присоединился(-лась) к звонку через ссылку</string>
|
||||
<string name="message_action_chat_pin_message">%1$s закрепил(-а) сообщение</string>
|
||||
<string name="message_action_chat_unpin_message">%1$s открепил(-а) сообщение</string>
|
||||
<string name="message_action_chat_screenshot">%1$s сделал(-а) скриншот беседы</string>
|
||||
<string name="message_action_chat_style_update">%1$s изменил(-а) тему беседы</string>
|
||||
<string name="message_attachments_photo_one">Фотография</string>
|
||||
<string name="message_attachments_photo_few">%1$d фотографии</string>
|
||||
<string name="message_attachments_photo_many">%1$d фотографий</string>
|
||||
<string name="message_attachments_photo_other">%1$d фотографий</string>
|
||||
<string name="message_attachments_video_one">Видеозапись</string>
|
||||
<string name="message_attachments_video_few">%1$d видеозаписи</string>
|
||||
<string name="message_attachments_video_many">%1$d видеозаписей</string>
|
||||
<string name="message_attachments_video_other">%1$d видеозаписей</string>
|
||||
<string name="message_attachments_audio_one">Аудиозапись</string>
|
||||
<string name="message_attachments_audio_few">%1$d аудиоозаписи</string>
|
||||
<string name="message_attachments_audio_many">%1$d аудиоозаписей</string>
|
||||
<string name="message_attachments_audio_other">%1$d аудиоозаписей</string>
|
||||
<string name="message_attachments_files_one">Файл</string>
|
||||
<string name="message_attachments_files_few">%1$d файла</string>
|
||||
<string name="message_attachments_files_many">%1$d файлов</string>
|
||||
<string name="message_attachments_files_other">%1$d файлов</string>
|
||||
<string name="message_attachments_audio_message">Голосовое сообщение</string>
|
||||
<string name="message_attachments_link">Ссылка</string>
|
||||
<string name="message_attachments_mini_app">Мини-приложение</string>
|
||||
<string name="message_attachments_sticker">Стикер</string>
|
||||
<string name="message_attachments_gift">Подарок</string>
|
||||
<string name="message_attachments_wall">Запись на стене</string>
|
||||
<string name="message_attachments_graffiti">Граффити</string>
|
||||
<string name="message_attachments_poll">Опрос</string>
|
||||
<string name="message_attachments_wall_reply">Комментарий</string>
|
||||
<string name="message_attachments_call">Звонок</string>
|
||||
<string name="message_attachments_call_in_progress">Текущий звонок</string>
|
||||
<string name="message_attachments_event">Событие</string>
|
||||
<string name="message_attachments_curator">Куратор</string>
|
||||
<string name="message_attachments_story">История</string>
|
||||
<string name="message_attachments_widget">Виджет</string>
|
||||
<string name="message_attachments_place">Место</string>
|
||||
<string name="message_attachments_artist">Исполнитель</string>
|
||||
<string name="message_attachments_audio_playlist">Плейлист</string>
|
||||
<string name="message_attachments_podcast">Подкаст</string>
|
||||
<string name="message_attachments_narrative">Момент</string>
|
||||
<string name="message_attachments_article">Статья</string>
|
||||
<string name="chat_interaction_uploading_file">Загрузка файла</string>
|
||||
<string name="chat_interaction_uploading_photo">Загрузка фото</string>
|
||||
<string name="chat_interaction_uploading_video">Загрузка видео</string>
|
||||
<string name="chat_interaction_typing">Печатает</string>
|
||||
<string name="chat_interaction_recording_audio_message">Записывает</string>
|
||||
<string name="chat_interaction_chat_typing">%1$s печатают</string>
|
||||
<string name="chat_interaction_chat_single_typing">%1$s печатает</string>
|
||||
<string name="file_size_in_bytes">%1$d байтов</string>
|
||||
<string name="post_type_community">Запись сообщества</string>
|
||||
<string name="post_type_user">Запись пользователя</string>
|
||||
<string name="post_type_unknown">Запись на стене</string>
|
||||
<string name="log_out">Выйти</string>
|
||||
<string name="confirm">Подтверждение</string>
|
||||
<string name="message_attachment_story_your_story">Ваша история</string>
|
||||
<string name="settings_dynamic_colors">Динамические цвета</string>
|
||||
<string name="settings_dynamic_colors_description">Цвета для приложения будут извлечены из ваших обоев на главном экране</string>
|
||||
<string name="settings_application_language">Язык приложения</string>
|
||||
<string name="settings_application_language_value">Текущий: %1$s</string>
|
||||
<string name="language_system">Системный</string>
|
||||
<string name="action_apply">Применить</string>
|
||||
<string name="open_system_language_picker">Открыть системный пикер языка</string>
|
||||
<string name="title_application_language">Язык приложения</string>
|
||||
<string name="message_attachment_story_story_from">История от</string>
|
||||
<string name="favorites">Избранное</string>
|
||||
<string name="warning">Внимание</string>
|
||||
<string name="app_crash_occurred">Произошла ошибка</string>
|
||||
<string name="app_crash_comment_prompt">Оставьте комментарий</string>
|
||||
<string name="app_crash_report">Сообщить</string>
|
||||
<string name="copy">Скопировать</string>
|
||||
<string name="share">Поделиться</string>
|
||||
<string name="pref_message_fast_text_summary">Текст, который будет вставлен в поле ввода при долгом удержании на иконке эмодзи.\nТекущее значение: %1$s</string>
|
||||
<string name="confirm_remove_chat_user">Вы действительно хотите исключить этого участника?</string>
|
||||
<string name="user_banned_error">Пользователь заблокирован</string>
|
||||
<string name="blocking_reason_title">Причина блокировки</string>
|
||||
<string name="account_temporarily_blocked">Аккаунт временно заблокирован</string>
|
||||
<string name="user_name">Имя пользователя</string>
|
||||
<string name="sign_in_to_vk">Войдите в ВК</string>
|
||||
<string name="settings_dark_theme">Тёмная тема</string>
|
||||
<string name="settings_dark_theme_value_enabled">Включена</string>
|
||||
<string name="settings_dark_theme_value_follow_system">Системная</string>
|
||||
<string name="settings_dark_theme_value_battery_saver">Энергосбережение</string>
|
||||
<string name="settings_dark_theme_value_disabled">Выключена</string>
|
||||
<string name="settings_dark_theme_current_value">Текущее значение: %1$s</string>
|
||||
<string name="settings_dark_theme_current_value_unknown">Неизвестное</string>
|
||||
<string name="settings_amoled_dark_theme">AMOLED тёмная тема</string>
|
||||
<string name="settings_amoled_dark_theme_description">Использовать AMOLED тему с чистым чёрным фоновым цветом, когда используется тёмная тема</string>
|
||||
<string name="members_count">Участники: %1$d</string>
|
||||
<string name="title_loading">Загрузка…</string>
|
||||
<string name="title_conversations">Чаты</string>
|
||||
<string name="title_friends">Друзья</string>
|
||||
<string name="title_profile">Профиль</string>
|
||||
<string name="title_friends_all">Все</string>
|
||||
<string name="title_friends_online">В сети</string>
|
||||
<string name="no_items">Нет элементов</string>
|
||||
<string name="settings_account_title">Аккаунт</string>
|
||||
<string name="settings_account_logout_title">Выйти из аккаунта</string>
|
||||
<string name="settings_account_logout_summary">Выход из аккаунта удалит все связанные с текущим аккаунтом данные</string>
|
||||
<string name="settings_general_title">Основное</string>
|
||||
<string name="settings_general_contact_names_title">Использовать имена контактов</string>
|
||||
<string name="settings_general_contact_names_summary">Приложение будет использовать доступные имена контактов для пользователей</string>
|
||||
<string name="settings_appearance_title">Внешний вид</string>
|
||||
<string name="settings_appearance_multiline_title">Многострочные заголовки и сообщения</string>
|
||||
<string name="settings_appearance_multiline_summary">Заголовок чата и текст сообщения смогут занимать несколько строчек</string>
|
||||
<string name="settings_features_title">Фичи</string>
|
||||
<string name="settings_features_fast_text_title">Fast текст</string>
|
||||
<string name="settings_features_long_poll_in_background_title">[WIP] LongPoll в фоне</string>
|
||||
<string name="settings_features_long_poll_in_background_summary">Ваши сообщения будут обновляться, даже если приложение находится в фоне</string>
|
||||
<string name="settings_activity_title">Активность</string>
|
||||
<string name="settings_activity_send_online_title">Быть «в сети»</string>
|
||||
<string name="settings_activity_send_online_summary">Статус «в сети» будет отправляться каждые 5 минут</string>
|
||||
<string name="settings_debug_title">Отладка</string>
|
||||
<string name="action_disable">Отключить</string>
|
||||
<string name="background_long_poll_rationale_text">Приложение не сможет обновлять сообщения в фоне без доступа к уведомлениям</string>
|
||||
<string name="background_long_poll_denied_text">Приложению нужен доступ к уведомлениям для обновления сообщений в фоне</string>
|
||||
<string name="action_request">Запросить</string>
|
||||
<string name="long_polling_service_notification_title">Обновление сообщений в фоне</string>
|
||||
<string name="long_polling_service_notification_content">Нажмите, чтобы скрыть</string>
|
||||
<string name="notification_channel_no_category_name">Без категории</string>
|
||||
<string name="notification_channel_no_category_description">Уведомления без категории</string>
|
||||
<string name="notification_channel_long_polling_service_name">Сервис обновления сообщений</string>
|
||||
<string name="notification_channel_long_polling_service_description">Уведомления сервиса обновлений сообщений</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#4184F5</color>
|
||||
</resources>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user