forked from melod1n/fast-messenger
Update API version (#147)
* Bump VK Api version to 5.238 * Implemented new authorization flow (at the moment, without auto re-requesting token) * Add support for sticker pack preview attachments * Bump LongPoll to version 19 * Improved messages handling * Fixed coloring issues * Cache improvements * Archive screen with full functionality * Recomposition fixes * Markdown support for messages bubbles * Adjust app name font size based on screen width * Navigation related improvements * Add logout functionality
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
package dev.meloda.fast.ui.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import dev.meloda.fast.model.BaseError
|
||||
import dev.meloda.fast.ui.R
|
||||
|
||||
@Composable
|
||||
fun VkErrorView(
|
||||
modifier: Modifier = Modifier,
|
||||
baseError: BaseError,
|
||||
onButtonClick: () -> Unit = {}
|
||||
) {
|
||||
when (baseError) {
|
||||
is BaseError.SessionExpired -> {
|
||||
ErrorView(
|
||||
modifier = modifier,
|
||||
text = stringResource(R.string.session_expired),
|
||||
buttonText = stringResource(R.string.action_log_out),
|
||||
onButtonClick = onButtonClick
|
||||
)
|
||||
}
|
||||
|
||||
is BaseError.SimpleError -> {
|
||||
ErrorView(
|
||||
modifier = modifier,
|
||||
text = baseError.message,
|
||||
buttonText = stringResource(R.string.try_again),
|
||||
onButtonClick = onButtonClick
|
||||
)
|
||||
}
|
||||
|
||||
BaseError.AccountBlocked -> {
|
||||
ErrorView(
|
||||
modifier = modifier,
|
||||
text = "Account blocked",
|
||||
buttonText = stringResource(R.string.action_log_out),
|
||||
onButtonClick = onButtonClick
|
||||
)
|
||||
}
|
||||
|
||||
BaseError.ConnectionError -> {
|
||||
ErrorView(
|
||||
modifier = modifier,
|
||||
text = "Connection error",
|
||||
buttonText = stringResource(R.string.try_again),
|
||||
onButtonClick = onButtonClick
|
||||
)
|
||||
}
|
||||
|
||||
BaseError.InternalError -> {
|
||||
ErrorView(
|
||||
modifier = modifier,
|
||||
text = "Internal error",
|
||||
buttonText = stringResource(R.string.try_again),
|
||||
onButtonClick = onButtonClick
|
||||
)
|
||||
}
|
||||
|
||||
BaseError.UnknownError -> {
|
||||
ErrorView(
|
||||
modifier = modifier,
|
||||
text = "Unknown error",
|
||||
buttonText = stringResource(R.string.try_again),
|
||||
onButtonClick = onButtonClick
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,13 +6,27 @@ 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
|
||||
import org.koin.core.parameter.ParametersDefinition
|
||||
import org.koin.core.qualifier.Qualifier
|
||||
|
||||
@Composable
|
||||
inline fun <reified T : ViewModel> NavBackStackEntry.sharedViewModel(navController: NavController): T {
|
||||
val navGraphRoute = destination.parent?.route ?: return koinViewModel()
|
||||
inline fun <reified T : ViewModel> NavBackStackEntry.sharedViewModel(
|
||||
navController: NavController,
|
||||
route: String? = null,
|
||||
qualifier: Qualifier? = null,
|
||||
noinline parameters: ParametersDefinition? = null,
|
||||
): T {
|
||||
val navGraphRoute = route ?: destination.parent?.route ?: return koinViewModel(
|
||||
qualifier = qualifier,
|
||||
parameters = parameters
|
||||
)
|
||||
val parentEntry = remember(this) {
|
||||
navController.getBackStackEntry(navGraphRoute)
|
||||
}
|
||||
return koinNavViewModel(viewModelStoreOwner = parentEntry)
|
||||
|
||||
return koinViewModel(
|
||||
viewModelStoreOwner = parentEntry,
|
||||
qualifier = qualifier,
|
||||
parameters = parameters
|
||||
)
|
||||
}
|
||||
|
||||
@@ -28,4 +28,14 @@ sealed class ConversationOption(
|
||||
title = UiText.Resource(R.string.action_delete),
|
||||
icon = UiImage.Resource(R.drawable.round_delete_outline_24)
|
||||
)
|
||||
|
||||
data object Archive : ConversationOption(
|
||||
title = UiText.Resource(R.string.conversation_context_action_archive),
|
||||
icon = UiImage.Resource(R.drawable.outline_archive_24)
|
||||
)
|
||||
|
||||
data object Unarchive : ConversationOption(
|
||||
title = UiText.Resource(R.string.conversation_context_action_unarchive),
|
||||
icon = UiImage.Resource(R.drawable.outline_unarchive_24)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package dev.meloda.fast.ui.model.api
|
||||
|
||||
data class ConversationsShowOptions(
|
||||
val showDeleteDialog: Int?,
|
||||
val showPinDialog: UiConversation?
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val EMPTY: ConversationsShowOptions = ConversationsShowOptions(
|
||||
showDeleteDialog = null,
|
||||
showPinDialog = null
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@ import dev.meloda.fast.ui.util.ImmutableList
|
||||
|
||||
@Immutable
|
||||
data class UiConversation(
|
||||
val id: Int,
|
||||
val lastMessageId: Int?,
|
||||
val id: Long,
|
||||
val lastMessageId: Long?,
|
||||
val avatar: UiImage?,
|
||||
val title: String,
|
||||
val unreadCount: String?,
|
||||
@@ -27,5 +27,6 @@ data class UiConversation(
|
||||
val peerType: PeerType,
|
||||
val interactionText: String?,
|
||||
val isExpanded: Boolean,
|
||||
val isArchived: Boolean,
|
||||
val options: ImmutableList<ConversationOption>,
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ import dev.meloda.fast.model.api.domain.OnlineStatus
|
||||
|
||||
@Immutable
|
||||
data class UiFriend(
|
||||
val userId: Int,
|
||||
val userId: Long,
|
||||
val avatar: UiImage?,
|
||||
val firstName: String,
|
||||
val lastName: String,
|
||||
|
||||
@@ -2,6 +2,7 @@ package dev.meloda.fast.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
@@ -9,8 +10,10 @@ import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ProvidableCompositionLocal
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
@@ -20,6 +23,7 @@ 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 androidx.navigation.NavController
|
||||
import dev.chrisbanes.haze.HazeState
|
||||
import dev.meloda.fast.model.api.domain.VkUser
|
||||
import dev.meloda.fast.ui.R
|
||||
@@ -129,7 +133,14 @@ val LocalSizeConfig = compositionLocalOf {
|
||||
val LocalHazeState = compositionLocalOf { HazeState() }
|
||||
val LocalBottomPadding = compositionLocalOf { 0.dp }
|
||||
val LocalUser = compositionLocalOf<VkUser?> { null }
|
||||
val LocalScrollToTop = compositionLocalOf { mapOf<Any, Boolean>() }
|
||||
val LocalReselectedTab = compositionLocalOf { mapOf<Any, Boolean>() }
|
||||
val LocalNavRootController = compositionLocalOf<NavController?> { null }
|
||||
val LocalNavController = compositionLocalOf<NavController?> { null }
|
||||
|
||||
@Composable
|
||||
fun <T: NavController> ProvidableCompositionLocal<T?>.getOrThrow(): T {
|
||||
return requireNotNull(current)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AppTheme(
|
||||
@@ -141,9 +152,10 @@ fun AppTheme(
|
||||
selectedColorScheme: Int = 0,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val colorScheme: ColorScheme = when {
|
||||
useDynamicColors && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (useDarkTheme) dynamicDarkColorScheme(context)
|
||||
else dynamicLightColorScheme(context)
|
||||
}
|
||||
@@ -166,6 +178,10 @@ fun AppTheme(
|
||||
}
|
||||
}
|
||||
|
||||
val colorPrimary by animateColorAsState(colorScheme.primary)
|
||||
val colorSurface by animateColorAsState(colorScheme.surface)
|
||||
val colorBackground by animateColorAsState(colorScheme.background)
|
||||
|
||||
val typography = if (useSystemFont) {
|
||||
MaterialTheme.typography
|
||||
} else {
|
||||
@@ -198,7 +214,12 @@ fun AppTheme(
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = predefinedColorScheme ?: colorScheme,
|
||||
colorScheme = (predefinedColorScheme ?: colorScheme)
|
||||
.copy(
|
||||
primary = colorPrimary,
|
||||
background = colorBackground,
|
||||
surface = colorSurface
|
||||
),
|
||||
typography = typography,
|
||||
content = content
|
||||
)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<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.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3L6,3c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5L3,19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM6.24,5h11.52l0.81,0.97L5.44,5.97l0.8,-0.97zM5,19L5,8h14v11L5,19zM13.45,10h-2.9v3L8,13l4,4 4,-4h-2.55z" />
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<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.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3L6,3c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5L3,19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM6.24,5h11.52l0.83,1L5.42,6l0.82,-1zM5,19L5,8h14v11L5,19zM8,14h2.55v3h2.9v-3L16,14l-4,-4z" />
|
||||
|
||||
</vector>
|
||||
@@ -24,6 +24,7 @@
|
||||
<string name="message_mark_as_spam">Пометить как спам</string>
|
||||
<string name="action_mark_as_read">Прочитать</string>
|
||||
<string name="action_delete">Удалить</string>
|
||||
<string name="conversation_context_action_unarchive">Из архива</string>
|
||||
<string name="conversation_context_action_delete">Удалить</string>
|
||||
<string name="confirm_delete_conversation">Удалить чат?</string>
|
||||
<string name="action_sign_out">Выйти</string>
|
||||
@@ -32,10 +33,12 @@
|
||||
<string name="conversation_context_action_pin">Закрепить</string>
|
||||
<string name="confirm_unpin_conversation">Открепить чат?</string>
|
||||
<string name="confirm_pin_conversation">Закрепить чат?</string>
|
||||
<string name="confirm_unarchive_conversation">Разархивировать чат?</string>
|
||||
<string name="action_pin">Закрепить</string>
|
||||
<string name="action_unpin">Открепить</string>
|
||||
<string name="action_mark">Пометить</string>
|
||||
<string name="action_unmark">Убрать пометку</string>
|
||||
<string name="action_unarchive">Из архива</string>
|
||||
<string name="message_call_type_outgoing">Исходящий вызов</string>
|
||||
<string name="message_call_type_incoming">Входящий вызов</string>
|
||||
<string name="message_call_state_ended">Закончился</string>
|
||||
@@ -125,10 +128,13 @@
|
||||
<string name="message_attachments_podcast">Подкаст</string>
|
||||
<string name="message_attachments_narrative">Момент</string>
|
||||
<string name="message_attachments_article">Статья</string>
|
||||
<string name="message_attachments_video_message">Видеосообщение</string>
|
||||
<string name="message_attachments_group_sticker">Стикер группы</string>
|
||||
<string name="message_attachments_sticker_pack_preview">Превью стикерпака</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_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>
|
||||
@@ -175,6 +181,7 @@
|
||||
<string name="members_count">Участники: %1$d</string>
|
||||
<string name="title_loading">Загрузка…</string>
|
||||
<string name="title_conversations">Чаты</string>
|
||||
<string name="title_archive">Архив</string>
|
||||
<string name="title_friends">Друзья</string>
|
||||
<string name="title_profile">Профиль</string>
|
||||
<string name="title_friends_all">Все</string>
|
||||
@@ -253,4 +260,7 @@
|
||||
<string name="unspam_message_text">Вы уверены, что хотите убрать пометку спама у этого сообщения?</string>
|
||||
<string name="pin_message_title">Закрепить сообщение</string>
|
||||
<string name="copied_to_clipboard">Скопировано в буфер обмена</string>
|
||||
<string name="conversation_context_action_archive">В архив</string>
|
||||
<string name="confirm_archive_conversation">Архивировать чат?</string>
|
||||
<string name="action_archive">В архив</string>
|
||||
</resources>
|
||||
|
||||
@@ -104,11 +104,14 @@
|
||||
<string name="message_attachments_podcast">Podcast</string>
|
||||
<string name="message_attachments_narrative">Narrative</string>
|
||||
<string name="message_attachments_article">Article</string>
|
||||
<string name="message_attachments_video_message">Video message</string>
|
||||
<string name="message_attachments_group_sticker">Group sticker</string>
|
||||
<string name="message_attachments_sticker_pack_preview">Sticker pack preview</string>
|
||||
|
||||
<string name="chat_interaction_uploading_file">Uploading file</string>
|
||||
<string name="chat_interaction_uploading_photo">Uploading photo</string>
|
||||
<string name="chat_interaction_uploading_video">Uploading video</string>
|
||||
<string name="chat_interaction_typing">Typing</string>
|
||||
<string name="chat_interaction_typing">typing</string>
|
||||
<string name="chat_interaction_recording_audio_message">Recording</string>
|
||||
|
||||
<string name="chat_interaction_chat_typing">%1$s are typing</string>
|
||||
@@ -149,6 +152,8 @@
|
||||
<string name="action_mark_as_read">Read</string>
|
||||
|
||||
<string name="action_delete">Delete</string>
|
||||
<string name="conversation_context_action_archive">Archive</string>
|
||||
<string name="conversation_context_action_unarchive">Unarchive</string>
|
||||
<string name="conversation_context_action_delete">Delete</string>
|
||||
<string name="confirm_delete_conversation">Delete the conversation?</string>
|
||||
<string name="action_sign_out">Sign out</string>
|
||||
@@ -157,10 +162,14 @@
|
||||
<string name="conversation_context_action_pin">Pin</string>
|
||||
<string name="confirm_unpin_conversation">Unpin the conversation?</string>
|
||||
<string name="confirm_pin_conversation">Pin the conversation?</string>
|
||||
<string name="confirm_archive_conversation">Archive the conversation?</string>
|
||||
<string name="confirm_unarchive_conversation">Unarchive the conversation?</string>
|
||||
<string name="action_pin">Pin</string>
|
||||
<string name="action_unpin">Unpin</string>
|
||||
<string name="action_mark">Mark</string>
|
||||
<string name="action_unmark">Unmark</string>
|
||||
<string name="action_archive">Archive</string>
|
||||
<string name="action_unarchive">Unarchive</string>
|
||||
<string name="message_call_type_outgoing">Outgoing call</string>
|
||||
<string name="message_call_type_incoming">Incoming call</string>
|
||||
<string name="message_call_state_ended">Ended</string>
|
||||
@@ -236,6 +245,7 @@
|
||||
<string name="members_count">Members: %1$d</string>
|
||||
<string name="title_loading">Loading…</string>
|
||||
<string name="title_conversations">Conversations</string>
|
||||
<string name="title_archive">Archive</string>
|
||||
<string name="title_friends">Friends</string>
|
||||
<string name="title_profile">Profile</string>
|
||||
<string name="title_friends_all">All</string>
|
||||
|
||||
Reference in New Issue
Block a user