Upstream changes (#23)
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.meloda.app.fast.common
|
||||
|
||||
object AppConstants {
|
||||
|
||||
const val INSTALL_APP_MIME_TYPE = "application/vnd.android.package-archive"
|
||||
|
||||
const val API_VERSION = "5.173"
|
||||
const val URL_OAUTH = "https://oauth.vk.com"
|
||||
const val URL_API = "https://api.vk.com/method"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.meloda.app.fast.common
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import java.net.URLEncoder
|
||||
|
||||
class AuthInterceptor : Interceptor {
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val builder = chain.request().url.newBuilder()
|
||||
|
||||
val uri = builder.build().toUri().toString().toUri()
|
||||
|
||||
if (uri.getQueryParameter("v") == null) {
|
||||
builder.addQueryParameter(
|
||||
name = "v",
|
||||
value = URLEncoder.encode(AppConstants.API_VERSION, "utf-8")
|
||||
)
|
||||
}
|
||||
|
||||
if (UserConfig.accessToken.isNotBlank()) {
|
||||
builder.addQueryParameter(
|
||||
"access_token",
|
||||
URLEncoder.encode(UserConfig.accessToken, "utf-8")
|
||||
)
|
||||
}
|
||||
|
||||
return chain.proceed(chain.request().newBuilder().apply { url(builder.build()) }.build())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.meloda.app.fast.common
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import androidx.core.os.BundleCompat
|
||||
import androidx.navigation.NavType
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
inline fun <reified T : Parcelable> customNavType(
|
||||
isNullableAllowed: Boolean = false,
|
||||
json: Json = Json
|
||||
) = object : NavType<T>(isNullableAllowed = isNullableAllowed) {
|
||||
override fun get(bundle: Bundle, key: String) =
|
||||
BundleCompat.getParcelable(bundle, key, T::class.java)
|
||||
|
||||
override fun parseValue(value: String): T = json.decodeFromString(value)
|
||||
|
||||
override fun serializeAsValue(value: T): String = json.encodeToString(value)
|
||||
|
||||
override fun put(bundle: Bundle, key: String, value: T) = bundle.putParcelable(key, value)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.meloda.app.fast.common
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DrawableRes
|
||||
|
||||
sealed class UiImage {
|
||||
|
||||
data class Resource(@DrawableRes val resId: Int) : UiImage()
|
||||
|
||||
data class Simple(val drawable: Drawable) : UiImage()
|
||||
|
||||
data class Color(@ColorInt val color: Int) : UiImage()
|
||||
|
||||
data class ColorResource(@ColorRes val resId: Int) : UiImage()
|
||||
|
||||
data class Url(val url: String) : UiImage()
|
||||
|
||||
fun extractUrl(): String? = when (this) {
|
||||
is Url -> this.url
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun extractResId(): Int = when (this) {
|
||||
is Resource -> this.resId
|
||||
else -> throw IllegalStateException("this UiImage is not Resource")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.meloda.app.fast.common
|
||||
|
||||
import android.content.res.Resources
|
||||
import androidx.annotation.PluralsRes
|
||||
import androidx.annotation.StringRes
|
||||
|
||||
sealed class UiText {
|
||||
|
||||
data object Empty : UiText()
|
||||
|
||||
data class Resource(@StringRes val resId: Int) : UiText()
|
||||
|
||||
data class ResourceParams(
|
||||
@StringRes val value: Int,
|
||||
val args: List<Any?>,
|
||||
) : UiText()
|
||||
|
||||
data class Simple(val text: String) : UiText()
|
||||
|
||||
data class QuantityResource(@PluralsRes val resId: Int, val quantity: Int) : UiText()
|
||||
}
|
||||
|
||||
fun UiText?.parseString(resources: Resources): String? {
|
||||
return when (this) {
|
||||
is UiText.Resource -> resources.getString(resId)
|
||||
is UiText.ResourceParams -> {
|
||||
val processedArgs = args.map { any ->
|
||||
when (any) {
|
||||
is UiText -> any.parseString(resources)
|
||||
else -> any
|
||||
}
|
||||
}
|
||||
resources.getString(value, *processedArgs.toTypedArray())
|
||||
}
|
||||
|
||||
is UiText.QuantityResource -> resources.getQuantityString(resId, quantity, quantity)
|
||||
is UiText.Simple -> text
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.meloda.app.fast.common
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
object UserConfig {
|
||||
|
||||
private const val ARG_CURRENT_USER_ID = "current_user_id"
|
||||
|
||||
private var preferences: SharedPreferences by Delegates.notNull()
|
||||
|
||||
fun init(preferences: SharedPreferences) {
|
||||
this.preferences = preferences
|
||||
}
|
||||
|
||||
var currentUserId: Int = -1
|
||||
get() = preferences.getInt(ARG_CURRENT_USER_ID, -1)
|
||||
set(value) {
|
||||
field = value
|
||||
preferences.edit { putInt(ARG_CURRENT_USER_ID, value) }
|
||||
}
|
||||
|
||||
var userId: Int = -1
|
||||
var accessToken: String = ""
|
||||
var fastToken: String? = ""
|
||||
var trustedHash: String? = null
|
||||
|
||||
fun clear() {
|
||||
currentUserId = -1
|
||||
accessToken = ""
|
||||
fastToken = ""
|
||||
userId = -1
|
||||
}
|
||||
|
||||
fun isLoggedIn(): Boolean {
|
||||
return currentUserId > 0 && userId > 0 && accessToken.isNotBlank()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.meloda.app.fast.common
|
||||
|
||||
object VkConstants {
|
||||
|
||||
const val GROUP_FIELDS = "description,members_count,counters,status,verified"
|
||||
|
||||
const val USER_FIELDS =
|
||||
"photo_50,photo_100,photo_200,status,screen_name,online,online_mobile,last_seen,verified,sex,online_info,bdate"
|
||||
|
||||
const val ALL_FIELDS =
|
||||
"$USER_FIELDS,$GROUP_FIELDS"
|
||||
|
||||
const val LP_VERSION = 10
|
||||
|
||||
const val VK_APP_ID = "2274003"
|
||||
const val VK_SECRET = "hHbZxrka2uZ6jB1inYsH"
|
||||
|
||||
const val FAST_GROUP_ID = -119516304
|
||||
const val FAST_APP_ID = "6964679"
|
||||
|
||||
object Auth {
|
||||
const val SCOPE = "notify," +
|
||||
"friends," +
|
||||
"photos," +
|
||||
"audio," +
|
||||
"video," +
|
||||
"docs," +
|
||||
"status," +
|
||||
"notes," +
|
||||
"pages," +
|
||||
"wall," +
|
||||
"groups," +
|
||||
"messages," +
|
||||
"offline," +
|
||||
"notifications"
|
||||
|
||||
object GrantType {
|
||||
const val PASSWORD = "password"
|
||||
}
|
||||
}
|
||||
|
||||
// val restrictedToEditAttachments = listOf<Class<out VkAttachment>>(
|
||||
// VkCallDomain::class.java,
|
||||
// VkCuratorDomain::class.java,
|
||||
// VkEventDomain::class.java,
|
||||
// VkGiftDomain::class.java,
|
||||
// VkGraffitiDomain::class.java,
|
||||
// VkGroupCallDomain::class.java,
|
||||
// VkStoryDomain::class.java,
|
||||
// VkAudioMessageDomain::class.java,
|
||||
// VkWidgetDomain::class.java
|
||||
// )
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.meloda.app.fast.common.di
|
||||
|
||||
import coil.ImageLoader
|
||||
import org.koin.dsl.module
|
||||
|
||||
val commonModule = module {
|
||||
single {
|
||||
ImageLoader.Builder(get())
|
||||
.crossfade(true)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package com.meloda.app.fast.common.extensions
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
fun Context.restartApp() {
|
||||
(this as? Activity)?.let { activity ->
|
||||
activity.finishAffinity()
|
||||
activity.startActivity(
|
||||
Intent(
|
||||
this,
|
||||
Class.forName("com.meloda.app.fast.MainActivity")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> Iterable<T>.findWithIndex(predicate: (T) -> Boolean): Pair<Int, T>? {
|
||||
val value = firstOrNull(predicate) ?: return null
|
||||
return indexOf(value).let { index -> if (index == -1) null else index to value }
|
||||
}
|
||||
|
||||
fun <T> MutableList<T>.addIf(element: T, condition: () -> Boolean) {
|
||||
if (condition.invoke()) add(element)
|
||||
}
|
||||
|
||||
context(ViewModel)
|
||||
fun <T> Flow<T>.listenValue(action: suspend (T) -> Unit) = listenValue(viewModelScope, action)
|
||||
|
||||
fun <T> Flow<T>.listenValue(
|
||||
coroutineScope: CoroutineScope,
|
||||
action: suspend (T) -> Unit
|
||||
): Job = onEach(action::invoke).launchIn(coroutineScope)
|
||||
|
||||
fun createTimerFlow(
|
||||
time: Int,
|
||||
onStartAction: (suspend () -> Unit)? = null,
|
||||
onTickAction: (suspend (remainedTime: Int) -> Unit)? = null,
|
||||
onTimeoutAction: (suspend () -> Unit)? = null,
|
||||
interval: Duration = 1.seconds
|
||||
): Flow<Int> = (time downTo 0)
|
||||
.asSequence()
|
||||
.asFlow()
|
||||
.onStart { onStartAction?.invoke() }
|
||||
.onEach { timeLeft ->
|
||||
onTickAction?.invoke(timeLeft)
|
||||
if (timeLeft == 0) {
|
||||
onTimeoutAction?.invoke()
|
||||
} else {
|
||||
delay(interval)
|
||||
}
|
||||
}
|
||||
|
||||
fun createTimerFlow(
|
||||
isNeedToEndCondition: suspend () -> Boolean,
|
||||
onStartAction: (suspend () -> Unit)? = null,
|
||||
onTickAction: (suspend () -> Unit)? = null,
|
||||
onEndAction: (suspend () -> Unit)? = null,
|
||||
interval: Duration = 1.seconds
|
||||
): Flow<Boolean> = flow {
|
||||
while (true) {
|
||||
val isNeedToEnd = isNeedToEndCondition()
|
||||
emit(isNeedToEnd)
|
||||
if (isNeedToEnd) break
|
||||
}
|
||||
}
|
||||
.onStart { onStartAction?.invoke() }
|
||||
.onEach { isNeedToEnd ->
|
||||
onTickAction?.invoke()
|
||||
if (isNeedToEnd) {
|
||||
onEndAction?.invoke()
|
||||
} else {
|
||||
delay(interval)
|
||||
}
|
||||
}
|
||||
|
||||
context(ViewModel)
|
||||
fun <T> MutableSharedFlow<T>.emitOnMainScope(value: T) = emitOnScope(Dispatchers.Main) { value }
|
||||
|
||||
context(ViewModel)
|
||||
fun <T> MutableSharedFlow<T>.emitOnScope(
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
value: () -> T,
|
||||
) {
|
||||
viewModelScope.launch(coroutineContext) {
|
||||
emit(value())
|
||||
}
|
||||
}
|
||||
|
||||
context(CoroutineScope)
|
||||
suspend fun <T> MutableSharedFlow<T>.emitWithMain(value: T) {
|
||||
withContext(Dispatchers.Main) {
|
||||
emit(value)
|
||||
}
|
||||
}
|
||||
|
||||
context(ViewModel)
|
||||
fun <T> MutableStateFlow<T>.updateValue(newValue: T) = this.update { newValue }
|
||||
|
||||
fun <T> MutableStateFlow<T>.setValue(function: (T) -> T) {
|
||||
val newValue = function(value)
|
||||
update { newValue }
|
||||
}
|
||||
|
||||
fun Any.asInt(): Int {
|
||||
return when (this) {
|
||||
is Number -> this.toInt()
|
||||
|
||||
else -> throw IllegalArgumentException("Object is not numeric")
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Any.toList(mapper: (old: Any) -> T): List<T> {
|
||||
return when (this) {
|
||||
is List<*> -> this.mapNotNull { it?.run(mapper) }
|
||||
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
fun isSdkAtLeast(sdkInt: Int, action: (() -> Unit)? = null): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= sdkInt) {
|
||||
action?.invoke()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.meloda.app.fast.common.extensions
|
||||
|
||||
inline fun String?.ifEmpty(defaultValue: () -> String?): String? =
|
||||
if (this?.isEmpty() == true) defaultValue() else this
|
||||
|
||||
fun String?.orDots(count: Int = 3): String {
|
||||
return this ?: ("." * count)
|
||||
}
|
||||
|
||||
operator fun String.times(count: Int): String {
|
||||
val builder = StringBuilder()
|
||||
for (i in 0 until count) {
|
||||
builder.append(this)
|
||||
}
|
||||
|
||||
return builder.toString()
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.meloda.app.fast.common.extensions.navigation
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import androidx.navigation.NavController
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
import org.koin.androidx.compose.navigation.koinNavViewModel
|
||||
|
||||
@Composable
|
||||
inline fun <reified T : ViewModel> NavBackStackEntry.sharedViewModel(navController: NavController): T {
|
||||
val navGraphRoute = destination.parent?.route ?: return koinViewModel()
|
||||
val parentEntry = remember(this) {
|
||||
navController.getBackStackEntry(navGraphRoute)
|
||||
}
|
||||
return koinNavViewModel(viewModelStoreOwner = parentEntry)
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
package com.meloda.app.fast.common.util
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.PowerManager
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.FileProvider
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
private object BuildConfig {
|
||||
const val DEBUG = true
|
||||
const val APPLICATION_ID = "com.meloda.app.fast"
|
||||
}
|
||||
|
||||
object AndroidUtils {
|
||||
|
||||
fun copyText(
|
||||
context: Context,
|
||||
label: String? = "",
|
||||
text: String,
|
||||
withToast: Boolean = false
|
||||
) {
|
||||
val clipboardManager =
|
||||
context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
|
||||
clipboardManager.setPrimaryClip(ClipData.newPlainText(label, text))
|
||||
|
||||
if (withToast && Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
||||
Toast.makeText(context, "Copied to clipboard", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun copyImage(
|
||||
context: Context,
|
||||
label: String? = "",
|
||||
imageUri: Uri,
|
||||
withToast: Boolean = false
|
||||
) {
|
||||
val clipboardManager =
|
||||
context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
|
||||
clipboardManager.setPrimaryClip(ClipData.newRawUri(label, imageUri))
|
||||
|
||||
if (withToast && Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
||||
Toast.makeText(context, "Copied to clipboard", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun bytesToMegabytes(bytes: Double): Double {
|
||||
return bytes / 1024 / 1024
|
||||
}
|
||||
|
||||
fun bytesToHumanReadableSize(bytes: Double): String = when {
|
||||
bytes >= 1 shl 30 -> "%.1f GB".format(bytes / (1 shl 30))
|
||||
bytes >= 1 shl 20 -> "%.1f MB".format(bytes / (1 shl 20))
|
||||
bytes >= 1 shl 10 -> "%.1f KB".format(bytes / (1 shl 10))
|
||||
else -> "$bytes B"
|
||||
}
|
||||
|
||||
fun openAppNotificationsSettings(context: Context) {
|
||||
val packageName = context.packageName
|
||||
|
||||
val intent = Intent("android.settings.APP_NOTIFICATION_SETTINGS")
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
intent.putExtra("android.provider.extra.APP_PACKAGE", packageName)
|
||||
} else {
|
||||
intent.putExtra("app_package", packageName)
|
||||
intent.putExtra("app_uid", context.applicationInfo.uid)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun isCanInstallUnknownApps(context: Context): Boolean {
|
||||
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
Settings.Secure.getInt(
|
||||
context.contentResolver,
|
||||
Settings.Secure.INSTALL_NON_MARKET_APPS
|
||||
) == 1
|
||||
} else {
|
||||
context.packageManager.canRequestPackageInstalls()
|
||||
}
|
||||
}
|
||||
|
||||
fun openInstallUnknownAppsScreen(context: Context) {
|
||||
context.startActivity(Intent().apply {
|
||||
action = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
Settings.ACTION_SECURITY_SETTINGS
|
||||
} else {
|
||||
data = Uri.parse("package:${BuildConfig.APPLICATION_ID}")
|
||||
Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun getInstallPackageIntent(
|
||||
context: Context,
|
||||
providerPath: String,
|
||||
fileToRead: File,
|
||||
): Intent {
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
|
||||
intent.data = FileProvider.getUriForFile(
|
||||
context,
|
||||
BuildConfig.APPLICATION_ID + providerPath,
|
||||
fileToRead
|
||||
)
|
||||
|
||||
return intent
|
||||
}
|
||||
|
||||
fun isBatterySaverOn(context: Context): Boolean {
|
||||
return (context.getSystemService(Context.POWER_SERVICE) as? PowerManager)?.isPowerSaveMode == true
|
||||
}
|
||||
|
||||
fun getImageToShare(context: Context, existingFile: File): Uri? {
|
||||
val imageFolder = File(context.cacheDir, "images")
|
||||
|
||||
return try {
|
||||
imageFolder.mkdirs()
|
||||
|
||||
val copyToFile = File(imageFolder, "shared_image.png")
|
||||
if (copyToFile.exists()) {
|
||||
copyToFile.delete()
|
||||
}
|
||||
|
||||
val file = existingFile.copyTo(copyToFile)
|
||||
FileProvider.getUriForFile(context, "${BuildConfig.APPLICATION_ID}.provider", file)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun getImageToShare(context: Context, bitmap: Bitmap): Uri? {
|
||||
val imageFolder = File(context.cacheDir, "images")
|
||||
|
||||
return try {
|
||||
imageFolder.mkdirs()
|
||||
|
||||
val file = File(imageFolder, "shared_image.png")
|
||||
val outputStream = FileOutputStream(file)
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 90, outputStream)
|
||||
outputStream.flush()
|
||||
outputStream.close()
|
||||
FileProvider.getUriForFile(context, "${BuildConfig.APPLICATION_ID}.fileprovider", file)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun showShareSheet(context: Context, content: ShareContent) {
|
||||
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||
|
||||
type = when (content) {
|
||||
is ShareContent.Text -> {
|
||||
putExtra(Intent.EXTRA_TEXT, content.text)
|
||||
"text/plain"
|
||||
}
|
||||
|
||||
is ShareContent.Image -> {
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
putExtra(Intent.EXTRA_STREAM, content.uri)
|
||||
"image/png"
|
||||
}
|
||||
|
||||
is ShareContent.TextWithImage -> {
|
||||
putExtra(Intent.EXTRA_TEXT, content.text)
|
||||
putExtra(Intent.EXTRA_STREAM, content.imageUri)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
"image/png"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val contentType = when (content) {
|
||||
is ShareContent.Text -> "Text"
|
||||
is ShareContent.Image -> "Image"
|
||||
is ShareContent.TextWithImage -> "Text with image"
|
||||
}
|
||||
val chooserIntent = Intent.createChooser(intent, "Share $contentType")
|
||||
|
||||
|
||||
context.startActivity(chooserIntent)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ShareContent {
|
||||
data class Text(val text: String) : ShareContent()
|
||||
|
||||
data class Image(val uri: Uri) : ShareContent()
|
||||
|
||||
data class TextWithImage(val text: String, val imageUri: Uri) : ShareContent()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.meloda.app.fast.common.util
|
||||
|
||||
import android.content.res.Resources
|
||||
import com.conena.nanokt.jvm.util.dayOfMonth
|
||||
import com.conena.nanokt.jvm.util.hour
|
||||
import com.conena.nanokt.jvm.util.hourOfDay
|
||||
import com.conena.nanokt.jvm.util.millisecond
|
||||
import com.conena.nanokt.jvm.util.minute
|
||||
import com.conena.nanokt.jvm.util.month
|
||||
import com.conena.nanokt.jvm.util.second
|
||||
import com.conena.nanokt.jvm.util.year
|
||||
import com.meloda.app.fast.common.R
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
object TimeUtils {
|
||||
|
||||
fun removeTime(date: Date): Long {
|
||||
return Calendar.getInstance().apply {
|
||||
time = date
|
||||
hourOfDay = 0
|
||||
minute = 0
|
||||
second = 0
|
||||
millisecond = 0
|
||||
}.timeInMillis
|
||||
}
|
||||
|
||||
fun getLocalizedDate(resources: Resources, date: Long): String {
|
||||
val now = Calendar.getInstance()
|
||||
val then = Calendar.getInstance().also { it.timeInMillis = date }
|
||||
|
||||
val pattern = when {
|
||||
now.year != then.year -> "dd MMM yyyy"
|
||||
now.month != then.month -> "dd MMMM"
|
||||
now.dayOfMonth != then.dayOfMonth -> {
|
||||
if (now.dayOfMonth - then.dayOfMonth == 1) {
|
||||
return resources.getString(R.string.yesterday)
|
||||
} else {
|
||||
"dd MMMM"
|
||||
}
|
||||
}
|
||||
|
||||
else -> return resources.getString(R.string.today)
|
||||
}
|
||||
|
||||
return SimpleDateFormat(pattern, Locale.getDefault()).format(date)
|
||||
}
|
||||
|
||||
fun getLocalizedTime(resources: Resources, date: Long): String {
|
||||
val now = Calendar.getInstance()
|
||||
val then = Calendar.getInstance().also { it.timeInMillis = date }
|
||||
|
||||
return when {
|
||||
now.year != then.year -> {
|
||||
"${now.year - then.year}${resources.getString(R.string.year_short).lowercase()}"
|
||||
}
|
||||
|
||||
now.month != then.month -> {
|
||||
"${now.month - then.month}${resources.getString(R.string.month_short).lowercase()}"
|
||||
}
|
||||
|
||||
now.dayOfMonth != then.dayOfMonth -> {
|
||||
val change = now.dayOfMonth - then.dayOfMonth
|
||||
|
||||
if (change % 7 == 0) {
|
||||
"${change / 7}${resources.getString(R.string.week_short).lowercase()}"
|
||||
} else {
|
||||
"$change${resources.getString(R.string.day_short).lowercase()}"
|
||||
}
|
||||
}
|
||||
|
||||
now.hour == then.hour && now.minute == then.minute -> {
|
||||
resources.getString(R.string.time_now).lowercase()
|
||||
}
|
||||
|
||||
else -> {
|
||||
SimpleDateFormat("HH:mm", Locale.getDefault()).format(date)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,721 @@
|
||||
package com.meloda.app.fast.common.util
|
||||
|
||||
//import android.content.Context
|
||||
//import androidx.compose.ui.graphics.Color
|
||||
//import androidx.compose.ui.text.AnnotatedString
|
||||
//import androidx.compose.ui.text.SpanStyle
|
||||
//import androidx.compose.ui.text.buildAnnotatedString
|
||||
//import androidx.compose.ui.text.font.FontWeight
|
||||
//import androidx.compose.ui.text.withStyle
|
||||
//import com.meloda.app.fast.common.UiImage
|
||||
//import com.meloda.app.fast.common.UiText
|
||||
//import com.meloda.app.fast.common.extensions.orDots
|
||||
//import com.meloda.app.fast.common.parseString
|
||||
//
|
||||
//
|
||||
//@Suppress("MemberVisibilityCanBePrivate")
|
||||
//object VkUtils {
|
||||
//
|
||||
// fun prepareMessageText(text: String, forConversations: Boolean = false): String {
|
||||
// return text.apply {
|
||||
// if (forConversations) {
|
||||
// replace("\n", " ")
|
||||
// }
|
||||
//
|
||||
// replace("&", "&")
|
||||
// replace(""", "\"")
|
||||
// replace("<br>", "\n")
|
||||
// replace(">", ">")
|
||||
// replace("<", "<")
|
||||
// replace("<br/>", "\n")
|
||||
// replace("–", "-")
|
||||
// trim()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun parseAttachments(baseAttachments: List<VkAttachmentItemData>?): List<VkAttachment>? {
|
||||
// if (baseAttachments.isNullOrEmpty()) return null
|
||||
//
|
||||
// val attachments = mutableListOf<VkAttachment>()
|
||||
//
|
||||
// for (baseAttachment in baseAttachments) {
|
||||
// when (baseAttachment.getPreparedType()) {
|
||||
// AttachmentType.UNKNOWN -> continue
|
||||
//
|
||||
// AttachmentType.PHOTO -> {
|
||||
// val photo = baseAttachment.photo ?: continue
|
||||
// attachments += photo.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.VIDEO -> {
|
||||
// val video = baseAttachment.video ?: continue
|
||||
// attachments += video.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.AUDIO -> {
|
||||
// val audio = baseAttachment.audio ?: continue
|
||||
// attachments += audio.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.FILE -> {
|
||||
// val file = baseAttachment.file ?: continue
|
||||
// attachments += file.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.LINK -> {
|
||||
// val link = baseAttachment.link ?: continue
|
||||
// attachments += link.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.MINI_APP -> {
|
||||
// val miniApp = baseAttachment.miniApp ?: continue
|
||||
// attachments += miniApp.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.AUDIO_MESSAGE -> {
|
||||
// val voiceMessage = baseAttachment.voiceMessage ?: continue
|
||||
// attachments += voiceMessage.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.STICKER -> {
|
||||
// val sticker = baseAttachment.sticker ?: continue
|
||||
// attachments += sticker.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.GIFT -> {
|
||||
// val gift = baseAttachment.gift ?: continue
|
||||
// attachments += gift.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.WALL -> {
|
||||
// val wall = baseAttachment.wall ?: continue
|
||||
// attachments += wall.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.GRAFFITI -> {
|
||||
// val graffiti = baseAttachment.graffiti ?: continue
|
||||
// attachments += graffiti.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.POLL -> {
|
||||
// val poll = baseAttachment.poll ?: continue
|
||||
// attachments += poll.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.WALL_REPLY -> {
|
||||
// val wallReply = baseAttachment.wallReply ?: continue
|
||||
// attachments += wallReply.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.CALL -> {
|
||||
// val call = baseAttachment.call ?: continue
|
||||
// attachments += call.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.GROUP_CALL_IN_PROGRESS -> {
|
||||
// val groupCall = baseAttachment.groupCall ?: continue
|
||||
// attachments += groupCall.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.CURATOR -> {
|
||||
// val curator = baseAttachment.curator ?: continue
|
||||
// attachments += curator.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.EVENT -> {
|
||||
// val event = baseAttachment.event ?: continue
|
||||
// attachments += event.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.STORY -> {
|
||||
// val story = baseAttachment.story ?: continue
|
||||
// attachments += story.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.WIDGET -> {
|
||||
// val widget = baseAttachment.widget ?: continue
|
||||
// attachments += widget.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.ARTIST -> {
|
||||
// val artist = baseAttachment.artist ?: continue
|
||||
// attachments += artist.toDomain()
|
||||
//
|
||||
// val audios = baseAttachment.audios ?: continue
|
||||
// audios.map(VkAudioData::toDomain).let(attachments::addAll)
|
||||
// }
|
||||
//
|
||||
// AttachmentType.AUDIO_PLAYLIST -> {
|
||||
// val audioPlaylist = baseAttachment.audioPlaylist ?: continue
|
||||
// attachments += audioPlaylist.toDomain()
|
||||
// }
|
||||
//
|
||||
// AttachmentType.PODCAST -> {
|
||||
// val podcast = baseAttachment.podcast ?: continue
|
||||
// attachments += podcast.toDomain()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return attachments
|
||||
// }
|
||||
//
|
||||
// fun getActionMessageText(
|
||||
// context: Context,
|
||||
// message: VkMessage?,
|
||||
// youPrefix: String,
|
||||
// messageUser: VkUserDomain?,
|
||||
// messageGroup: VkGroupDomain?,
|
||||
// action: VkMessage.Action?,
|
||||
// actionUser: VkUserDomain?,
|
||||
// actionGroup: VkGroupDomain?,
|
||||
// ): AnnotatedString? {
|
||||
// return when {
|
||||
// message == null -> null
|
||||
// action == null -> null
|
||||
//
|
||||
// else -> buildAnnotatedString {
|
||||
// when (action) {
|
||||
// VkMessage.Action.CHAT_CREATE -> {
|
||||
// val text = message.actionText ?: return null
|
||||
//
|
||||
// val prefix = when {
|
||||
// message.fromId == UserConfig.userId -> youPrefix
|
||||
// message.isGroup() -> messageGroup?.name
|
||||
// message.isUser() -> messageUser?.toString()
|
||||
// else -> return null
|
||||
// } ?: return null
|
||||
//
|
||||
// val string = UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_created,
|
||||
// listOf(prefix, text)
|
||||
// ).parseString(context).orEmpty()
|
||||
//
|
||||
// append(string)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
//
|
||||
// val textStartIndex = string.indexOf(text)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = textStartIndex,
|
||||
// end = textStartIndex + text.length
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_TITLE_UPDATE -> {
|
||||
// val text = message.actionText ?: return null
|
||||
//
|
||||
// val prefix = when {
|
||||
// message.fromId == UserConfig.userId -> youPrefix
|
||||
// message.isGroup() -> messageGroup?.name
|
||||
// message.isUser() -> messageUser?.toString()
|
||||
// else -> return null
|
||||
// } ?: return null
|
||||
//
|
||||
// val string = UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_renamed,
|
||||
// listOf(prefix, text)
|
||||
// ).parseString(context).orEmpty()
|
||||
//
|
||||
// append(string)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
//
|
||||
// val textStartIndex = string.indexOf(text)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = textStartIndex,
|
||||
// end = textStartIndex + text.length
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_PHOTO_UPDATE -> {
|
||||
// val prefix = when {
|
||||
// message.fromId == UserConfig.userId -> youPrefix
|
||||
// message.isGroup() -> messageGroup?.name
|
||||
// message.isUser() -> messageUser?.toString()
|
||||
// else -> return null
|
||||
// } ?: return null
|
||||
//
|
||||
// UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_photo_update,
|
||||
// listOf(prefix)
|
||||
// ).parseString(context).orEmpty().let(::append)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_PHOTO_REMOVE -> {
|
||||
// val prefix = when {
|
||||
// message.fromId == UserConfig.userId -> youPrefix
|
||||
// message.isGroup() -> messageGroup?.name
|
||||
// message.isUser() -> messageUser?.toString()
|
||||
// else -> return null
|
||||
// } ?: return null
|
||||
//
|
||||
// UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_photo_remove,
|
||||
// listOf(prefix)
|
||||
// ).parseString(context).orEmpty().let(::append)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_KICK_USER -> {
|
||||
// val memberId = message.actionMemberId ?: return null
|
||||
// val isUser = memberId > 0
|
||||
// val isGroup = memberId < 0
|
||||
//
|
||||
// if (isUser && actionUser == null) return null
|
||||
// if (isGroup && actionGroup == null) return null
|
||||
//
|
||||
// if (memberId == message.fromId) {
|
||||
// val prefix =
|
||||
// if (memberId == UserConfig.userId) youPrefix
|
||||
// else actionUser.toString()
|
||||
//
|
||||
// UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_user_left,
|
||||
// listOf(prefix)
|
||||
// ).parseString(context).orEmpty().let(::append)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
// } else {
|
||||
// val prefix =
|
||||
// if (message.fromId == UserConfig.userId) youPrefix
|
||||
// else messageUser?.toString() ?: messageGroup?.toString().orDots()
|
||||
//
|
||||
// val postfix =
|
||||
// if (memberId == UserConfig.userId) youPrefix.lowercase()
|
||||
// else actionUser.toString()
|
||||
//
|
||||
// val string = UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_user_kicked,
|
||||
// listOf(prefix, postfix)
|
||||
// ).parseString(context).orEmpty()
|
||||
//
|
||||
// append(string)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
//
|
||||
// val postfixStartIndex = string.indexOf(postfix)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = postfixStartIndex,
|
||||
// end = postfixStartIndex + postfix.length
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_INVITE_USER -> {
|
||||
// val memberId = message.actionMemberId ?: 0
|
||||
// val isUser = memberId > 0
|
||||
// val isGroup = memberId < 0
|
||||
//
|
||||
// if (isUser && actionUser == null) return null
|
||||
// if (isGroup && actionGroup == null) return null
|
||||
//
|
||||
// if (memberId == message.fromId) {
|
||||
// val prefix =
|
||||
// if (memberId == UserConfig.userId) youPrefix
|
||||
// else actionUser.toString()
|
||||
//
|
||||
// UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_user_returned,
|
||||
// listOf(prefix)
|
||||
// ).parseString(context).orEmpty().let(::append)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
// } else {
|
||||
// val prefix =
|
||||
// if (message.fromId == UserConfig.userId) youPrefix
|
||||
// else messageUser?.toString() ?: messageGroup?.toString().orDots()
|
||||
//
|
||||
// val postfix =
|
||||
// if (memberId == UserConfig.userId) youPrefix.lowercase()
|
||||
// else actionUser.toString()
|
||||
//
|
||||
// val string = UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_user_invited,
|
||||
// listOf(prefix, postfix)
|
||||
// ).parseString(context).orEmpty()
|
||||
//
|
||||
// append(string)
|
||||
//
|
||||
// val postfixStartIndex = string.indexOf(postfix)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = postfixStartIndex,
|
||||
// end = postfixStartIndex + postfix.length
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_INVITE_USER_BY_LINK -> {
|
||||
// val prefix = when {
|
||||
// message.fromId == UserConfig.userId -> youPrefix
|
||||
// message.isUser() -> messageUser?.toString()
|
||||
// else -> return null
|
||||
// } ?: return null
|
||||
//
|
||||
// UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_user_joined_by_link,
|
||||
// listOf(prefix)
|
||||
// ).parseString(context).orEmpty().let(::append)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_INVITE_USER_BY_CALL -> {
|
||||
// val prefix = when {
|
||||
// message.fromId == UserConfig.userId -> youPrefix
|
||||
// message.isUser() -> messageUser?.toString()
|
||||
// else -> return null
|
||||
// } ?: return null
|
||||
//
|
||||
// UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_user_joined_by_call,
|
||||
// listOf(prefix)
|
||||
// ).parseString(context).orEmpty().let(::append)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_INVITE_USER_BY_CALL_LINK -> {
|
||||
// val prefix = when {
|
||||
// message.fromId == UserConfig.userId -> youPrefix
|
||||
// message.isUser() -> messageUser?.toString()
|
||||
// else -> return null
|
||||
// } ?: return null
|
||||
//
|
||||
// UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_user_joined_by_call_link,
|
||||
// listOf(prefix)
|
||||
// ).parseString(context).orEmpty().let(::append)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_PIN_MESSAGE -> {
|
||||
// val prefix = when {
|
||||
// message.fromId == UserConfig.userId -> youPrefix
|
||||
// message.isGroup() -> messageGroup?.name
|
||||
// message.isUser() -> messageUser?.toString()
|
||||
// else -> return null
|
||||
// } ?: return null
|
||||
//
|
||||
// UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_pin_message,
|
||||
// listOf(prefix)
|
||||
// ).parseString(context).orEmpty().let(::append)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_UNPIN_MESSAGE -> {
|
||||
// val prefix = when {
|
||||
// message.fromId == UserConfig.userId -> youPrefix
|
||||
// message.isGroup() -> messageGroup?.name
|
||||
// message.isUser() -> messageUser?.toString()
|
||||
// else -> return null
|
||||
// } ?: return null
|
||||
//
|
||||
// UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_unpin_message,
|
||||
// listOf(prefix)
|
||||
// ).parseString(context).orEmpty().let(::append)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_SCREENSHOT -> {
|
||||
// val prefix = when {
|
||||
// message.fromId == UserConfig.userId -> youPrefix
|
||||
// message.isGroup() -> messageGroup?.name
|
||||
// message.isUser() -> messageUser?.toString()
|
||||
// else -> return null
|
||||
// } ?: return null
|
||||
//
|
||||
// UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_screenshot,
|
||||
// listOf(prefix)
|
||||
// ).parseString(context).orEmpty().let(::append)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// VkMessage.Action.CHAT_STYLE_UPDATE -> {
|
||||
// val prefix = when {
|
||||
// message.fromId == UserConfig.userId -> youPrefix
|
||||
// message.isUser() -> messageUser?.toString()
|
||||
// else -> return null
|
||||
// } ?: return null
|
||||
//
|
||||
// UiText.ResourceParams(
|
||||
// UiR.string.message_action_chat_style_update,
|
||||
// listOf(prefix)
|
||||
// ).parseString(context).orEmpty().let(::append)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.SemiBold),
|
||||
// start = 0,
|
||||
// end = prefix.length
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun getForwardsText(context: Context, message: VkMessage?): AnnotatedString? {
|
||||
// return when {
|
||||
// message == null -> null
|
||||
//
|
||||
// message.hasForwards() -> buildAnnotatedString {
|
||||
// val forwards = message.forwards.orEmpty()
|
||||
//
|
||||
// withStyle(style = SpanStyle(fontWeight = FontWeight.SemiBold)) {
|
||||
// append(
|
||||
// UiText.Resource(
|
||||
// if (forwards.size == 1) UiR.string.forwarded_message
|
||||
// else UiR.string.forwarded_messages
|
||||
// ).parseString(context)
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// else -> null
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun getAttachmentText(
|
||||
// getText: (UiText) -> String,
|
||||
// message: VkMessage?
|
||||
// ): AnnotatedString? {
|
||||
// return when {
|
||||
// message == null -> null
|
||||
//
|
||||
// message.geoType != null -> buildAnnotatedString {
|
||||
// withStyle(style = SpanStyle(fontWeight = FontWeight.SemiBold)) {
|
||||
// when (message.geoType) {
|
||||
// "point" -> getText(UiText.Resource(UiR.string.message_geo_point))
|
||||
// .let(::append)
|
||||
//
|
||||
// else -> getText(UiText.Resource(UiR.string.message_geo))
|
||||
// .let(::append)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// message.hasAttachments() -> buildAnnotatedString {
|
||||
// val attachments = message.attachments.orEmpty()
|
||||
//
|
||||
// withStyle(style = SpanStyle(fontWeight = FontWeight.SemiBold)) {
|
||||
// if (attachments.size == 1) {
|
||||
// getText(getAttachmentUiText(attachments.first())).let(::append)
|
||||
// } else {
|
||||
// when {
|
||||
// isAttachmentsHaveOneType(attachments) -> {
|
||||
// getText(getAttachmentUiText(attachments.first(), attachments.size))
|
||||
// .let(::append)
|
||||
// }
|
||||
//
|
||||
// attachments.any { it.type == AttachmentType.ARTIST } -> {
|
||||
// getText(
|
||||
// getAttachmentUiText(attachments.first { it.type == AttachmentType.ARTIST })
|
||||
// ).let(::append)
|
||||
// }
|
||||
//
|
||||
// else -> {
|
||||
// getText(UiText.Resource(UiR.string.message_attachments_many))
|
||||
// .let(::append)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// else -> null
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun getAttachmentConversationIcon(message: VkMessage?): UiImage? {
|
||||
// return message?.attachments?.let { attachments ->
|
||||
// if (attachments.isEmpty()) return null
|
||||
// if (attachments.size == 1 || isAttachmentsHaveOneType(attachments)) {
|
||||
// message.geoType?.let {
|
||||
// return UiImage.Resource(UiR.drawable.ic_map_marker)
|
||||
// }
|
||||
//
|
||||
// getAttachmentIconByType(attachments.first().type)
|
||||
// } else {
|
||||
// UiImage.Resource(UiR.drawable.ic_baseline_attach_file_24)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// fun getAttachmentUiText(
|
||||
// attachment: VkAttachment,
|
||||
// size: Int = 1,
|
||||
// ): UiText {
|
||||
// if (attachment.type.isMultiple()) {
|
||||
// return when (attachment.type) {
|
||||
// AttachmentType.PHOTO -> UiR.plurals.attachment_photos
|
||||
// AttachmentType.VIDEO -> UiR.plurals.attachment_videos
|
||||
// AttachmentType.AUDIO -> UiR.plurals.attachment_audios
|
||||
// AttachmentType.FILE -> UiR.plurals.attachment_files
|
||||
// else -> throw IllegalArgumentException("Unknown multiple type: ${attachment.type}")
|
||||
// }.let { resId -> UiText.QuantityResource(resId, size) }
|
||||
// }
|
||||
//
|
||||
// return when (attachment.type) {
|
||||
// AttachmentType.UNKNOWN,
|
||||
// AttachmentType.PHOTO,
|
||||
// AttachmentType.VIDEO,
|
||||
// AttachmentType.AUDIO,
|
||||
// AttachmentType.FILE -> {
|
||||
// throw IllegalArgumentException("Unknown multiple type: ${attachment.type}")
|
||||
// }
|
||||
//
|
||||
// AttachmentType.LINK -> UiR.string.message_attachments_link
|
||||
// AttachmentType.AUDIO_MESSAGE -> UiR.string.message_attachments_audio_message
|
||||
// AttachmentType.MINI_APP -> UiR.string.message_attachments_mini_app
|
||||
// AttachmentType.STICKER -> UiR.string.message_attachments_sticker
|
||||
// AttachmentType.GIFT -> UiR.string.message_attachments_gift
|
||||
// AttachmentType.WALL -> UiR.string.message_attachments_wall
|
||||
// AttachmentType.GRAFFITI -> UiR.string.message_attachments_graffiti
|
||||
// AttachmentType.POLL -> UiR.string.message_attachments_poll
|
||||
// AttachmentType.WALL_REPLY -> UiR.string.message_attachments_wall_reply
|
||||
// AttachmentType.CALL -> UiR.string.message_attachments_call
|
||||
// AttachmentType.GROUP_CALL_IN_PROGRESS -> UiR.string.message_attachments_call_in_progress
|
||||
// AttachmentType.CURATOR -> UiR.string.message_attachments_curator
|
||||
// AttachmentType.EVENT -> UiR.string.message_attachments_event
|
||||
// AttachmentType.STORY -> UiR.string.message_attachments_story
|
||||
// AttachmentType.WIDGET -> UiR.string.message_attachments_widget
|
||||
// AttachmentType.ARTIST -> UiR.string.message_attachments_artist
|
||||
// AttachmentType.AUDIO_PLAYLIST -> UiR.string.message_attachments_audio_playlist
|
||||
// AttachmentType.PODCAST -> UiR.string.message_attachments_podcast
|
||||
// }.let(UiText::Resource)
|
||||
// }
|
||||
//
|
||||
// fun getTextWithVisualizedMentions(
|
||||
// originalText: String,
|
||||
// mentionColor: Color,
|
||||
// ): AnnotatedString = buildAnnotatedString {
|
||||
// val regex = """\[(id|club)(\d+)\|([^]]+)]""".toRegex()
|
||||
//
|
||||
// val mentions = mutableListOf<MentionIndex>()
|
||||
//
|
||||
// var currentIndex = 0
|
||||
// val replacements = mutableListOf<Pair<IntRange, String>>()
|
||||
//
|
||||
// // TODO: 25/04/2024, Danil Nikolaev: check why not working ([id279494346|@iworld2rist] да убери ты Елену Шлипс от меня)
|
||||
// val result = regex.replace(originalText) { matchResult ->
|
||||
// val idPrefix = matchResult.groups[1]?.value.orEmpty()
|
||||
// val startIndex = matchResult.range.first
|
||||
// val endIndex = matchResult.range.last
|
||||
//
|
||||
// val id = matchResult.groups[2]?.value ?: ""
|
||||
// val text = matchResult.groups[3]?.value ?: ""
|
||||
//
|
||||
// val replaced =
|
||||
// text.substring(startIndex, endIndex + 1)
|
||||
// .replace("[$idPrefix$id|$text]", text)
|
||||
//
|
||||
// val indexRange =
|
||||
// (startIndex + currentIndex)..startIndex + currentIndex + replaced.length
|
||||
//
|
||||
// replacements.add(indexRange to replaced)
|
||||
//
|
||||
// mentions += MentionIndex(
|
||||
// id = id.toIntOrNull() ?: -1,
|
||||
// idPrefix = idPrefix,
|
||||
// indexRange = indexRange
|
||||
// )
|
||||
//
|
||||
// currentIndex += replaced.length - (endIndex - startIndex + 1)
|
||||
//
|
||||
// replaced
|
||||
// }
|
||||
//
|
||||
// append(result)
|
||||
//
|
||||
// mentions.forEach { mention ->
|
||||
// val startIndex = mention.indexRange.first
|
||||
// val endIndex = mention.indexRange.last
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(color = mentionColor),
|
||||
// start = startIndex,
|
||||
// end = endIndex
|
||||
// )
|
||||
// addStringAnnotation(
|
||||
// tag = mention.idPrefix,
|
||||
// annotation = mention.id.toString(),
|
||||
// start = startIndex,
|
||||
// end = endIndex
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="yesterday">Yesterday</string>
|
||||
<string name="today">Today</string>
|
||||
<string name="year_short">Y</string>
|
||||
<string name="month_short">M</string>
|
||||
<string name="week_short">W</string>
|
||||
<string name="day_short">D</string>
|
||||
<string name="time_now">Now</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user