release 0.1.5 (#98)
* settings reorganization; implement long press on emoji button for fast text; some deprecations fixed; some typos fixed; etc * ability to use more animations (experimental); fix online friends loading; conversation avatar in messages history screen; test second tap on conversations item in bottom bar to scroll to top; etc * version up
This commit is contained in:
@@ -87,6 +87,7 @@ fun NavGraphBuilder.authNavGraph(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 17.12.2024, Danil Nikolaev: check clearing backstack from main screen
|
||||
fun NavController.navigateToAuth(clearBackStack: Boolean = false) {
|
||||
val navController = this
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ package dev.meloda.fast.auth.captcha.di
|
||||
import dev.meloda.fast.auth.captcha.CaptchaViewModel
|
||||
import dev.meloda.fast.auth.captcha.CaptchaViewModelImpl
|
||||
import dev.meloda.fast.auth.captcha.validation.CaptchaValidator
|
||||
import org.koin.androidx.viewmodel.dsl.viewModelOf
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
|
||||
@@ -368,7 +368,7 @@ class LoginViewModelImpl(
|
||||
|
||||
private fun startLongPoll() {
|
||||
longPollController.setStateToApply(
|
||||
if (AppSettings.Debug.longPollInBackground) {
|
||||
if (AppSettings.Experimental.longPollInBackground) {
|
||||
LongPollState.Background
|
||||
} else {
|
||||
LongPollState.InApp
|
||||
|
||||
@@ -4,8 +4,8 @@ import dev.meloda.fast.auth.login.LoginViewModelImpl
|
||||
import dev.meloda.fast.domain.OAuthUseCase
|
||||
import dev.meloda.fast.domain.OAuthUseCaseImpl
|
||||
import dev.meloda.fast.auth.login.validation.LoginValidator
|
||||
import org.koin.androidx.viewmodel.dsl.viewModelOf
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import dev.meloda.fast.domain.AuthUseCaseImpl
|
||||
import dev.meloda.fast.auth.validation.ValidationViewModel
|
||||
import dev.meloda.fast.auth.validation.ValidationViewModelImpl
|
||||
import dev.meloda.fast.auth.validation.validation.ValidationValidator
|
||||
import org.koin.androidx.viewmodel.dsl.viewModelOf
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
|
||||
-8
@@ -70,11 +70,9 @@ import dev.meloda.fast.chatmaterials.ChatMaterialsViewModel
|
||||
import dev.meloda.fast.chatmaterials.ChatMaterialsViewModelImpl
|
||||
import dev.meloda.fast.chatmaterials.model.ChatMaterialsScreenState
|
||||
import dev.meloda.fast.chatmaterials.model.UiChatMaterial
|
||||
import dev.meloda.fast.datastore.UserSettings
|
||||
import dev.meloda.fast.ui.R
|
||||
import dev.meloda.fast.ui.theme.LocalThemeConfig
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
@Composable
|
||||
fun ChatMaterialsRoute(
|
||||
@@ -82,15 +80,10 @@ fun ChatMaterialsRoute(
|
||||
onPhotoClicked: (url: String) -> Unit,
|
||||
viewModel: ChatMaterialsViewModel = koinViewModel<ChatMaterialsViewModelImpl>()
|
||||
) {
|
||||
val userSettings: UserSettings = koinInject()
|
||||
|
||||
val enablePullToRefresh by userSettings.enablePullToRefresh.collectAsStateWithLifecycle()
|
||||
|
||||
val screenState by viewModel.screenState.collectAsStateWithLifecycle()
|
||||
|
||||
ChatMaterialsScreen(
|
||||
screenState = screenState,
|
||||
enablePullToRefresh = enablePullToRefresh,
|
||||
onBack = onBack,
|
||||
onTypeChanged = viewModel::onTypeChanged,
|
||||
onRefreshDropdownItemClicked = viewModel::onRefresh,
|
||||
@@ -107,7 +100,6 @@ fun ChatMaterialsRoute(
|
||||
@Composable
|
||||
fun ChatMaterialsScreen(
|
||||
screenState: ChatMaterialsScreenState = ChatMaterialsScreenState.EMPTY,
|
||||
enablePullToRefresh: Boolean = false,
|
||||
onBack: () -> Unit = {},
|
||||
onTypeChanged: (String) -> Unit = {},
|
||||
onRefreshDropdownItemClicked: () -> Unit = {},
|
||||
|
||||
+23
@@ -26,7 +26,9 @@ import dev.meloda.fast.model.LongPollEvent
|
||||
import dev.meloda.fast.model.api.domain.VkConversation
|
||||
import dev.meloda.fast.network.VkErrorCode
|
||||
import dev.meloda.fast.ui.util.ImmutableList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -34,6 +36,7 @@ import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
interface ConversationsViewModel {
|
||||
@@ -43,6 +46,7 @@ interface ConversationsViewModel {
|
||||
val imagesToPreload: StateFlow<List<String>>
|
||||
val currentOffset: StateFlow<Int>
|
||||
val canPaginate: StateFlow<Boolean>
|
||||
val scrollToTop: StateFlow<Boolean>
|
||||
|
||||
fun onPaginationConditionsMet()
|
||||
|
||||
@@ -63,6 +67,10 @@ interface ConversationsViewModel {
|
||||
|
||||
fun setScrollIndex(index: Int)
|
||||
fun setScrollOffset(offset: Int)
|
||||
|
||||
|
||||
fun setScrollToTopFlow(scrollToTopFlow: Flow<Int>)
|
||||
fun onScrolledToTop()
|
||||
}
|
||||
|
||||
class ConversationsViewModelImpl(
|
||||
@@ -78,6 +86,7 @@ class ConversationsViewModelImpl(
|
||||
override val imagesToPreload = MutableStateFlow<List<String>>(emptyList())
|
||||
override val currentOffset = MutableStateFlow(0)
|
||||
override val canPaginate = MutableStateFlow(false)
|
||||
override val scrollToTop = MutableStateFlow(false)
|
||||
|
||||
override fun onPaginationConditionsMet() {
|
||||
currentOffset.update { screenState.value.conversations.size }
|
||||
@@ -217,6 +226,20 @@ class ConversationsViewModelImpl(
|
||||
screenState.setValue { old -> old.copy(scrollOffset = offset) }
|
||||
}
|
||||
|
||||
override fun setScrollToTopFlow(scrollToTopFlow: Flow<Int>) {
|
||||
scrollToTopFlow.listenValue(viewModelScope) { index ->
|
||||
if (index == 1) {
|
||||
scrollToTop.emit(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onScrolledToTop() {
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
scrollToTop.emit(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideOptions(conversationId: Int) {
|
||||
screenState.setValue { old ->
|
||||
old.copy(
|
||||
|
||||
+3
-3
@@ -1,14 +1,14 @@
|
||||
package dev.meloda.fast.conversations.di
|
||||
|
||||
import dev.meloda.fast.conversations.ConversationsViewModelImpl
|
||||
import dev.meloda.fast.domain.ConversationsUseCaseImpl
|
||||
import dev.meloda.fast.domain.ConversationsUseCase
|
||||
import org.koin.androidx.viewmodel.dsl.viewModelOf
|
||||
import dev.meloda.fast.domain.ConversationsUseCaseImpl
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
val conversationsModule = module {
|
||||
singleOf(::ConversationsUseCaseImpl) bind dev.meloda.fast.domain.ConversationsUseCase::class
|
||||
singleOf(::ConversationsUseCaseImpl) bind ConversationsUseCase::class
|
||||
viewModelOf(::ConversationsViewModelImpl)
|
||||
}
|
||||
|
||||
+3
@@ -8,6 +8,7 @@ import dev.meloda.fast.conversations.ConversationsViewModelImpl
|
||||
import dev.meloda.fast.conversations.presentation.ConversationsRoute
|
||||
import dev.meloda.fast.model.BaseError
|
||||
import dev.meloda.fast.ui.extensions.sharedViewModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@@ -17,11 +18,13 @@ fun NavGraphBuilder.conversationsScreen(
|
||||
onError: (BaseError) -> Unit,
|
||||
onConversationItemClicked: (id: Int) -> Unit,
|
||||
onPhotoClicked: (url: String) -> Unit,
|
||||
scrollToTopFlow: Flow<Int>,
|
||||
navController: NavController,
|
||||
) {
|
||||
composable<Conversations> {
|
||||
val viewModel: ConversationsViewModel =
|
||||
it.sharedViewModel<ConversationsViewModelImpl>(navController = navController)
|
||||
viewModel.setScrollToTopFlow(scrollToTopFlow)
|
||||
|
||||
ConversationsRoute(
|
||||
onError = onError,
|
||||
|
||||
+16
-3
@@ -101,6 +101,7 @@ fun ConversationsRoute(
|
||||
val screenState by viewModel.screenState.collectAsStateWithLifecycle()
|
||||
val baseError by viewModel.baseError.collectAsStateWithLifecycle()
|
||||
val canPaginate by viewModel.canPaginate.collectAsStateWithLifecycle()
|
||||
val isNeedToScrollToTop by viewModel.scrollToTop.collectAsStateWithLifecycle()
|
||||
|
||||
val imagesToPreload by viewModel.imagesToPreload.collectAsStateWithLifecycle()
|
||||
LaunchedEffect(imagesToPreload) {
|
||||
@@ -129,7 +130,9 @@ fun ConversationsRoute(
|
||||
onRefresh = viewModel::onRefresh,
|
||||
onConversationPhotoClicked = onConversationPhotoClicked,
|
||||
setScrollIndex = viewModel::setScrollIndex,
|
||||
setScrollOffset = viewModel::setScrollOffset
|
||||
setScrollOffset = viewModel::setScrollOffset,
|
||||
isNeedToScrollToTop = isNeedToScrollToTop,
|
||||
onScrolledToTop = viewModel::onScrolledToTop
|
||||
)
|
||||
|
||||
HandleDialogs(
|
||||
@@ -156,7 +159,9 @@ fun ConversationsScreen(
|
||||
onRefresh: () -> Unit = {},
|
||||
onConversationPhotoClicked: (url: String) -> Unit = {},
|
||||
setScrollIndex: (Int) -> Unit = {},
|
||||
setScrollOffset: (Int) -> Unit = {}
|
||||
setScrollOffset: (Int) -> Unit = {},
|
||||
isNeedToScrollToTop: Boolean = false,
|
||||
onScrolledToTop: () -> Unit = {}
|
||||
) {
|
||||
val view = LocalView.current
|
||||
val currentTheme = LocalThemeConfig.current
|
||||
@@ -170,6 +175,14 @@ fun ConversationsScreen(
|
||||
initialFirstVisibleItemScrollOffset = screenState.scrollOffset
|
||||
)
|
||||
|
||||
LaunchedEffect(isNeedToScrollToTop) {
|
||||
if (isNeedToScrollToTop) {
|
||||
listState.scrollToItem(0)
|
||||
onScrolledToTop()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(listState) {
|
||||
snapshotFlow { listState.firstVisibleItemIndex }
|
||||
.debounce(500L)
|
||||
@@ -310,7 +323,7 @@ fun ConversationsScreen(
|
||||
) {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
if (AppSettings.Debug.enableHaptic) {
|
||||
if (AppSettings.General.enableHaptic) {
|
||||
view.performHapticFeedback(HapticFeedbackConstantsCompat.REJECT)
|
||||
}
|
||||
scope.launch {
|
||||
|
||||
@@ -8,6 +8,7 @@ import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.data.processState
|
||||
import dev.meloda.fast.datastore.UserSettings
|
||||
import dev.meloda.fast.domain.FriendsUseCase
|
||||
import dev.meloda.fast.domain.LoadUsersByIdsUseCase
|
||||
import dev.meloda.fast.friends.model.FriendsScreenState
|
||||
import dev.meloda.fast.friends.util.asPresentation
|
||||
import dev.meloda.fast.model.BaseError
|
||||
@@ -42,7 +43,8 @@ interface FriendsViewModel {
|
||||
|
||||
class FriendsViewModelImpl(
|
||||
private val friendsUseCase: FriendsUseCase,
|
||||
private val userSettings: UserSettings
|
||||
private val userSettings: UserSettings,
|
||||
private val loadUsersByIdsUseCase: LoadUsersByIdsUseCase
|
||||
) : ViewModel(), FriendsViewModel {
|
||||
|
||||
override val screenState = MutableStateFlow(FriendsScreenState.EMPTY)
|
||||
@@ -94,6 +96,49 @@ class FriendsViewModelImpl(
|
||||
}
|
||||
|
||||
private fun loadFriends(offset: Int = currentOffset.value) {
|
||||
friendsUseCase.getOnlineFriends(null, null)
|
||||
.listenValue(viewModelScope) { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
if (error is State.Error.ApiError) {
|
||||
when (error.errorCode) {
|
||||
VkErrorCode.USER_AUTHORIZATION_FAILED -> {
|
||||
baseError.setValue { BaseError.SessionExpired }
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
},
|
||||
success = { userIds ->
|
||||
loadUsersByIdsUseCase(userIds = userIds)
|
||||
.listenValue(viewModelScope) { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
if (error is State.Error.ApiError) {
|
||||
when (error.errorCode) {
|
||||
VkErrorCode.USER_AUTHORIZATION_FAILED -> {
|
||||
baseError.setValue { BaseError.SessionExpired }
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
},
|
||||
success = { onlineFriends ->
|
||||
screenState.setValue { old ->
|
||||
old.copy(
|
||||
onlineFriends = onlineFriends.map {
|
||||
it.asPresentation(userSettings.useContactNames.value)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
friendsUseCase.getFriends(count = LOAD_COUNT, offset = offset)
|
||||
.listenValue(viewModelScope) { state ->
|
||||
state.processState(
|
||||
@@ -125,10 +170,6 @@ class FriendsViewModelImpl(
|
||||
it.asPresentation(userSettings.useContactNames.value)
|
||||
}
|
||||
|
||||
val loadedOnlineFriends = loadedFriends.filter {
|
||||
it.onlineStatus.isOnline()
|
||||
}
|
||||
|
||||
val newState = screenState.value.copy(
|
||||
isPaginationExhausted = paginationExhausted
|
||||
)
|
||||
@@ -136,18 +177,12 @@ class FriendsViewModelImpl(
|
||||
if (offset == 0) {
|
||||
friends.emit(response)
|
||||
screenState.setValue {
|
||||
newState.copy(
|
||||
friends = loadedFriends,
|
||||
onlineFriends = loadedOnlineFriends
|
||||
)
|
||||
newState.copy(friends = loadedFriends)
|
||||
}
|
||||
} else {
|
||||
friends.emit(friends.value.plus(response))
|
||||
screenState.setValue {
|
||||
newState.copy(
|
||||
friends = newState.friends.plus(loadedFriends),
|
||||
onlineFriends = newState.onlineFriends.plus(loadedOnlineFriends)
|
||||
)
|
||||
newState.copy(friends = newState.friends.plus(loadedFriends))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@ package dev.meloda.fast.friends.di
|
||||
import dev.meloda.fast.domain.FriendsUseCase
|
||||
import dev.meloda.fast.friends.FriendsViewModelImpl
|
||||
import dev.meloda.fast.domain.FriendsUseCaseImpl
|
||||
import org.koin.androidx.viewmodel.dsl.viewModelOf
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
val friendsModule = module {
|
||||
singleOf(::FriendsUseCaseImpl) bind dev.meloda.fast.domain.FriendsUseCase::class
|
||||
|
||||
singleOf(::FriendsUseCaseImpl) bind FriendsUseCase::class
|
||||
viewModelOf(::FriendsViewModelImpl)
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package dev.meloda.fast.languagepicker.di
|
||||
|
||||
import dev.meloda.fast.languagepicker.LanguagePickerViewModelImpl
|
||||
import org.koin.androidx.viewmodel.dsl.viewModelOf
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
val languagePickerModule = module {
|
||||
|
||||
+14
-17
@@ -1,15 +1,15 @@
|
||||
package dev.meloda.fast.messageshistory
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
import androidx.compose.ui.text.TextRange
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.core.content.edit
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.conena.nanokt.collections.indexOfFirstOrNull
|
||||
import com.conena.nanokt.collections.indexOfOrNull
|
||||
import com.conena.nanokt.text.isEmptyOrBlank
|
||||
import com.conena.nanokt.text.isNotEmptyOrBlank
|
||||
import dev.meloda.fast.common.extensions.listenValue
|
||||
import dev.meloda.fast.common.extensions.setValue
|
||||
import dev.meloda.fast.common.provider.ResourceProvider
|
||||
@@ -17,9 +17,9 @@ import dev.meloda.fast.data.UserConfig
|
||||
import dev.meloda.fast.data.VkMemoryCache
|
||||
import dev.meloda.fast.data.processState
|
||||
import dev.meloda.fast.datastore.AppSettings
|
||||
import dev.meloda.fast.datastore.SettingsKeys
|
||||
import dev.meloda.fast.datastore.UserSettings
|
||||
import dev.meloda.fast.domain.ConversationsUseCase
|
||||
import dev.meloda.fast.domain.LoadConversationsByIdUseCase
|
||||
import dev.meloda.fast.domain.LongPollUpdatesParser
|
||||
import dev.meloda.fast.domain.MessagesUseCase
|
||||
import dev.meloda.fast.messageshistory.model.ActionMode
|
||||
@@ -54,19 +54,18 @@ interface MessagesHistoryViewModel {
|
||||
fun onRefresh()
|
||||
fun onAttachmentButtonClicked()
|
||||
fun onMessageInputChanged(newText: TextFieldValue)
|
||||
fun onEmojiButtonClicked()
|
||||
fun onEmojiButtonLongClicked()
|
||||
fun onActionButtonClicked()
|
||||
|
||||
fun onPaginationConditionsMet()
|
||||
fun onToggleAnimationsDropdownItemClicked(enableAnimations: Boolean)
|
||||
}
|
||||
|
||||
class MessagesHistoryViewModelImpl(
|
||||
private val messagesUseCase: MessagesUseCase,
|
||||
private val conversationsUseCase: ConversationsUseCase,
|
||||
private val preferences: SharedPreferences,
|
||||
private val resourceProvider: ResourceProvider,
|
||||
private val userSettings: UserSettings,
|
||||
private val loadConversationsByIdUseCase: LoadConversationsByIdUseCase,
|
||||
updatesParser: LongPollUpdatesParser,
|
||||
savedStateHandle: SavedStateHandle
|
||||
) : MessagesHistoryViewModel, ViewModel() {
|
||||
@@ -123,8 +122,15 @@ class MessagesHistoryViewModelImpl(
|
||||
screenState.setValue { old -> old.copy(message = newText) }
|
||||
}
|
||||
|
||||
override fun onEmojiButtonClicked() {
|
||||
|
||||
override fun onEmojiButtonLongClicked() {
|
||||
AppSettings.Features.fastText.takeIf { it.isNotEmptyOrBlank() }?.let { text ->
|
||||
screenState.setValue { old ->
|
||||
val newText = "${old.message.text}$text"
|
||||
old.copy(
|
||||
message = TextFieldValue(text = newText, selection = TextRange(newText.length))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActionButtonClicked() {
|
||||
@@ -150,15 +156,6 @@ class MessagesHistoryViewModelImpl(
|
||||
loadMessagesHistory()
|
||||
}
|
||||
|
||||
override fun onToggleAnimationsDropdownItemClicked(enableAnimations: Boolean) {
|
||||
preferences.edit {
|
||||
putBoolean(
|
||||
SettingsKeys.KEY_ENABLE_ANIMATIONS_IN_MESSAGES,
|
||||
enableAnimations
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleNewMessage(event: LongPollEvent.VkMessageNewEvent) {
|
||||
val message = event.message
|
||||
|
||||
|
||||
+3
-3
@@ -1,17 +1,17 @@
|
||||
package dev.meloda.fast.messageshistory.di
|
||||
|
||||
import dev.meloda.fast.domain.MessagesUseCase
|
||||
import dev.meloda.fast.domain.MessagesUseCaseImpl
|
||||
import dev.meloda.fast.messageshistory.MessagesHistoryViewModel
|
||||
import dev.meloda.fast.messageshistory.MessagesHistoryViewModelImpl
|
||||
import dev.meloda.fast.domain.MessagesUseCaseImpl
|
||||
import dev.meloda.fast.messageshistory.validation.MessagesHistoryValidator
|
||||
import org.koin.androidx.viewmodel.dsl.viewModelOf
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
val messagesHistoryModule = module {
|
||||
singleOf(::MessagesUseCaseImpl) bind dev.meloda.fast.domain.MessagesUseCase::class
|
||||
singleOf(::MessagesUseCaseImpl) bind MessagesUseCase::class
|
||||
singleOf(::MessagesHistoryValidator)
|
||||
viewModelOf(::MessagesHistoryViewModelImpl) bind MessagesHistoryViewModel::class
|
||||
}
|
||||
|
||||
+2
@@ -18,6 +18,7 @@ data class MessagesHistoryScreenState(
|
||||
val isPaginating: Boolean,
|
||||
val isPaginationExhausted: Boolean,
|
||||
val actionMode: ActionMode,
|
||||
val chatImageUrl: String?
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@@ -33,6 +34,7 @@ data class MessagesHistoryScreenState(
|
||||
isPaginating = false,
|
||||
isPaginationExhausted = false,
|
||||
actionMode = ActionMode.Record,
|
||||
chatImageUrl = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+65
-46
@@ -1,10 +1,12 @@
|
||||
package dev.meloda.fast.messageshistory.presentation
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -23,9 +25,11 @@ import androidx.compose.foundation.layout.imeNestedScroll
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||
@@ -37,7 +41,6 @@ import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
@@ -60,6 +63,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
@@ -72,12 +76,12 @@ import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.view.HapticFeedbackConstantsCompat
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import coil.compose.AsyncImage
|
||||
import dev.chrisbanes.haze.HazeState
|
||||
import dev.chrisbanes.haze.hazeChild
|
||||
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
||||
import dev.chrisbanes.haze.materials.HazeMaterials
|
||||
import dev.meloda.fast.datastore.AppSettings
|
||||
import dev.meloda.fast.datastore.SettingsKeys
|
||||
import dev.meloda.fast.datastore.UserSettings
|
||||
import dev.meloda.fast.messageshistory.MessagesHistoryViewModel
|
||||
import dev.meloda.fast.messageshistory.MessagesHistoryViewModelImpl
|
||||
@@ -86,8 +90,10 @@ import dev.meloda.fast.messageshistory.model.MessagesHistoryScreenState
|
||||
import dev.meloda.fast.messageshistory.util.firstMessage
|
||||
import dev.meloda.fast.messageshistory.util.indexOfMessageByCmId
|
||||
import dev.meloda.fast.model.BaseError
|
||||
import dev.meloda.fast.ui.components.IconButton
|
||||
import dev.meloda.fast.ui.theme.LocalThemeConfig
|
||||
import dev.meloda.fast.ui.util.ImmutableList
|
||||
import dev.meloda.fast.ui.util.getImage
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
import org.koin.compose.koinInject
|
||||
@@ -115,11 +121,11 @@ fun MessagesHistoryRoute(
|
||||
onBack = onBack,
|
||||
onChatMaterialsDropdownItemClicked = onChatMaterialsDropdownItemClicked,
|
||||
onRefreshDropdownItemClicked = viewModel::onRefresh,
|
||||
onToggleAnimationsDropdownItemClicked = viewModel::onToggleAnimationsDropdownItemClicked,
|
||||
onPaginationConditionsMet = viewModel::onPaginationConditionsMet,
|
||||
onMessageInputChanged = viewModel::onMessageInputChanged,
|
||||
onAttachmentButtonClicked = viewModel::onAttachmentButtonClicked,
|
||||
onActionButtonClicked = viewModel::onActionButtonClicked
|
||||
onActionButtonClicked = viewModel::onActionButtonClicked,
|
||||
onEmojiButtonLongClicked = viewModel::onEmojiButtonLongClicked
|
||||
)
|
||||
}
|
||||
|
||||
@@ -141,7 +147,8 @@ fun MessagesHistoryScreen(
|
||||
onPaginationConditionsMet: () -> Unit = {},
|
||||
onMessageInputChanged: (TextFieldValue) -> Unit = {},
|
||||
onAttachmentButtonClicked: () -> Unit = {},
|
||||
onActionButtonClicked: () -> Unit = {}
|
||||
onActionButtonClicked: () -> Unit = {},
|
||||
onEmojiButtonLongClicked: () -> Unit = {}
|
||||
) {
|
||||
val view = LocalView.current
|
||||
|
||||
@@ -172,15 +179,6 @@ fun MessagesHistoryScreen(
|
||||
|
||||
val hazeState = remember { HazeState() }
|
||||
|
||||
var animationsEnabled by remember {
|
||||
mutableStateOf(
|
||||
preferences.getBoolean(
|
||||
SettingsKeys.KEY_ENABLE_ANIMATIONS_IN_MESSAGES,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val toolbarColorAlpha by animateFloatAsState(
|
||||
targetValue = if (!listState.canScrollForward) 1f else 0f,
|
||||
label = "toolbarColorAlpha",
|
||||
@@ -210,14 +208,42 @@ fun MessagesHistoryScreen(
|
||||
)
|
||||
.fillMaxWidth(),
|
||||
title = {
|
||||
Text(
|
||||
text =
|
||||
if (screenState.isLoading) stringResource(id = UiR.string.title_loading)
|
||||
else screenState.title,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
val avatar = screenState.avatar.getImage()
|
||||
if (avatar is Painter) {
|
||||
Image(
|
||||
painter = avatar,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.clip(CircleShape)
|
||||
)
|
||||
} else {
|
||||
AsyncImage(
|
||||
model = screenState.avatar.getImage(),
|
||||
contentDescription = "Profile Image",
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.clip(CircleShape),
|
||||
placeholder = painterResource(id = UiR.drawable.ic_account_circle_cut),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
Text(
|
||||
text =
|
||||
if (screenState.isLoading) stringResource(id = UiR.string.title_loading)
|
||||
else screenState.title,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
@@ -280,31 +306,19 @@ fun MessagesHistoryScreen(
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (preferences.getBoolean(
|
||||
SettingsKeys.KEY_SHOW_DEBUG_CATEGORY,
|
||||
false
|
||||
)
|
||||
) {
|
||||
HorizontalDivider()
|
||||
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(text = if (animationsEnabled) "Disable animations" else "Enable animations")
|
||||
},
|
||||
onClick = {
|
||||
dropDownMenuExpanded = false
|
||||
animationsEnabled = !animationsEnabled
|
||||
onToggleAnimationsDropdownItemClicked(animationsEnabled)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
if (screenState.isLoading && screenState.messages.isNotEmpty()) {
|
||||
|
||||
val showHorizontalProgressBar by remember(screenState) {
|
||||
derivedStateOf { screenState.isLoading && screenState.messages.isNotEmpty() }
|
||||
}
|
||||
if (showHorizontalProgressBar) {
|
||||
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
AnimatedVisibility(!showHorizontalProgressBar) {
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
}
|
||||
) { padding ->
|
||||
@@ -320,7 +334,6 @@ fun MessagesHistoryScreen(
|
||||
listState = listState,
|
||||
immutableMessages = ImmutableList.copyOf(screenState.messages),
|
||||
isPaginating = screenState.isPaginating,
|
||||
enableAnimations = animationsEnabled,
|
||||
messageBarHeight = messageBarHeight,
|
||||
onRequestScrollToCmId = { cmId ->
|
||||
coroutineScope.launch {
|
||||
@@ -371,7 +384,7 @@ fun MessagesHistoryScreen(
|
||||
Column(verticalArrangement = Arrangement.Bottom) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (AppSettings.Debug.enableHaptic) {
|
||||
if (AppSettings.General.enableHaptic) {
|
||||
view.performHapticFeedback(HapticFeedbackConstantsCompat.REJECT)
|
||||
}
|
||||
scope.launch {
|
||||
@@ -389,6 +402,12 @@ fun MessagesHistoryScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
onLongClick = {
|
||||
if (AppSettings.General.enableHaptic) {
|
||||
view.performHapticFeedback(HapticFeedbackConstantsCompat.LONG_PRESS)
|
||||
}
|
||||
onEmojiButtonLongClicked()
|
||||
},
|
||||
modifier = Modifier.rotate(rotation.value)
|
||||
) {
|
||||
Icon(
|
||||
@@ -427,7 +446,7 @@ fun MessagesHistoryScreen(
|
||||
Column(verticalArrangement = Arrangement.Bottom) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (AppSettings.Debug.enableHaptic) {
|
||||
if (AppSettings.General.enableHaptic) {
|
||||
view.performHapticFeedback(HapticFeedbackConstantsCompat.REJECT)
|
||||
}
|
||||
scope.launch {
|
||||
@@ -463,7 +482,7 @@ fun MessagesHistoryScreen(
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (screenState.actionMode == ActionMode.Record) {
|
||||
if (AppSettings.Debug.enableHaptic) {
|
||||
if (AppSettings.General.enableHaptic) {
|
||||
view.performHapticFeedback(HapticFeedbackConstantsCompat.REJECT)
|
||||
}
|
||||
scope.launch {
|
||||
|
||||
+8
-2
@@ -13,12 +13,14 @@ import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.chrisbanes.haze.HazeState
|
||||
import dev.chrisbanes.haze.haze
|
||||
import dev.meloda.fast.datastore.AppSettings
|
||||
import dev.meloda.fast.messageshistory.model.UiItem
|
||||
import dev.meloda.fast.ui.theme.LocalThemeConfig
|
||||
import dev.meloda.fast.ui.util.ImmutableList
|
||||
@@ -30,11 +32,15 @@ fun MessagesList(
|
||||
listState: LazyListState,
|
||||
immutableMessages: ImmutableList<UiItem>,
|
||||
isPaginating: Boolean,
|
||||
enableAnimations: Boolean,
|
||||
messageBarHeight: Dp,
|
||||
onRequestScrollToCmId: (cmId: Int) -> Unit = {}
|
||||
) {
|
||||
val messages = immutableMessages.toList()
|
||||
val enableAnimations = remember {
|
||||
AppSettings.Experimental.moreAnimations
|
||||
}
|
||||
val messages = remember(immutableMessages) {
|
||||
immutableMessages.toList()
|
||||
}
|
||||
val currentTheme = LocalThemeConfig.current
|
||||
|
||||
LazyColumn(
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.meloda.fast.photoviewer.di
|
||||
|
||||
import dev.meloda.fast.photoviewer.PhotoViewViewModel
|
||||
import dev.meloda.fast.photoviewer.PhotoViewViewModelImpl
|
||||
import org.koin.androidx.viewmodel.dsl.viewModelOf
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ fun TopBar(
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
// IconButton(
|
||||
// IconButton.kt(
|
||||
// onClick = { dropdownMenuShown = true }
|
||||
// ) {
|
||||
// Icon(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package dev.meloda.fast.profile.di
|
||||
|
||||
import dev.meloda.fast.profile.ProfileViewModelImpl
|
||||
import org.koin.androidx.viewmodel.dsl.viewModelOf
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
val profileModule = module {
|
||||
|
||||
@@ -154,13 +154,6 @@ class SettingsViewModelImpl(
|
||||
userSettings.onUseContactNamesChanged(isUsing)
|
||||
}
|
||||
|
||||
SettingsKeys.KEY_ENABLE_PULL_TO_REFRESH -> {
|
||||
val enable =
|
||||
newValue as? Boolean ?: SettingsKeys.DEFAULT_VALUE_ENABLE_PULL_TO_REFRESH
|
||||
userSettings.onEnablePullToRefreshChanged(enable)
|
||||
}
|
||||
|
||||
|
||||
SettingsKeys.KEY_APPEARANCE_MULTILINE -> {
|
||||
val isUsing = newValue as? Boolean ?: SettingsKeys.DEFAULT_VALUE_MULTILINE
|
||||
userSettings.onEnableMultilineChanged(isUsing)
|
||||
@@ -206,9 +199,9 @@ class SettingsViewModelImpl(
|
||||
userSettings.onShowAlertAfterCrashChanged(show)
|
||||
}
|
||||
|
||||
SettingsKeys.KEY_FEATURES_LONG_POLL_IN_BACKGROUND -> {
|
||||
SettingsKeys.KEY_LONG_POLL_IN_BACKGROUND -> {
|
||||
val inBackground = newValue as? Boolean
|
||||
?: SettingsKeys.DEFAULT_VALUE_FEATURES_LONG_POLL_IN_BACKGROUND
|
||||
?: SettingsKeys.DEFAULT_LONG_POLL_IN_BACKGROUND
|
||||
userSettings.onLongPollInBackgroundChanged(inBackground)
|
||||
|
||||
longPollController.setStateToApply(
|
||||
@@ -221,9 +214,9 @@ class SettingsViewModelImpl(
|
||||
)
|
||||
}
|
||||
|
||||
SettingsKeys.KEY_APPEARANCE_USE_BLUR -> {
|
||||
SettingsKeys.KEY_USE_BLUR -> {
|
||||
val isUsing =
|
||||
newValue as? Boolean ?: SettingsKeys.DEFAULT_VALUE_KEY_APPEARANCE_USE_BLUR
|
||||
newValue as? Boolean ?: SettingsKeys.DEFAULT_USE_BLUR
|
||||
userSettings.onUseBlurChanged(isUsing)
|
||||
}
|
||||
|
||||
@@ -232,14 +225,14 @@ class SettingsViewModelImpl(
|
||||
userSettings.onShowEmojiButtonChanged(show)
|
||||
}
|
||||
|
||||
SettingsKeys.KEY_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES -> {
|
||||
SettingsKeys.KEY_SHOW_TIME_IN_ACTION_MESSAGES -> {
|
||||
val show = newValue as? Boolean
|
||||
?: SettingsKeys.DEFAULT_VALUE_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES
|
||||
?: SettingsKeys.DEFAULT_SHOW_TIME_IN_ACTION_MESSAGES
|
||||
userSettings.onShowTimeInActionMessagesChanged(show)
|
||||
}
|
||||
|
||||
SettingsKeys.KEY_DEBUG_USE_SYSTEM_FONT -> {
|
||||
val use = newValue as? Boolean ?: SettingsKeys.DEFAULT_DEBUG_USE_SYSTEM_FONT
|
||||
SettingsKeys.KEY_USE_SYSTEM_FONT -> {
|
||||
val use = newValue as? Boolean ?: SettingsKeys.DEFAULT_USE_SYSTEM_FONT
|
||||
userSettings.onUseSystemFontChanged(use)
|
||||
}
|
||||
|
||||
@@ -283,10 +276,16 @@ class SettingsViewModelImpl(
|
||||
text = UiText.Resource(UiR.string.settings_general_contact_names_summary),
|
||||
defaultValue = SettingsKeys.DEFAULT_VALUE_USE_CONTACT_NAMES
|
||||
)
|
||||
val generalEnablePullToRefresh = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_ENABLE_PULL_TO_REFRESH,
|
||||
defaultValue = SettingsKeys.DEFAULT_VALUE_ENABLE_PULL_TO_REFRESH,
|
||||
title = UiText.Resource(UiR.string.settings_general_enable_pull_to_refresh_title)
|
||||
val generalShowEmojiButton = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_SHOW_EMOJI_BUTTON,
|
||||
title = UiText.Simple("Show emoji button"),
|
||||
text = UiText.Simple("Show emoji button in chat panel"),
|
||||
defaultValue = SettingsKeys.DEFAULT_VALUE_KEY_SHOW_EMOJI_BUTTON
|
||||
)
|
||||
val generalEnableHaptic = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_ENABLE_HAPTIC,
|
||||
defaultValue = SettingsKeys.DEFAULT_ENABLE_HAPTIC,
|
||||
title = UiText.Simple("Enable haptic")
|
||||
)
|
||||
|
||||
val appearanceTitle = SettingsItem.Title(
|
||||
@@ -340,7 +339,11 @@ class SettingsViewModelImpl(
|
||||
text = UiText.Resource(UiR.string.settings_dynamic_colors_description),
|
||||
defaultValue = SettingsKeys.DEFAULT_VALUE_USE_DYNAMIC_COLORS
|
||||
)
|
||||
|
||||
val appearanceUseSystemFont = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_USE_SYSTEM_FONT,
|
||||
defaultValue = SettingsKeys.DEFAULT_USE_SYSTEM_FONT,
|
||||
title = UiText.Simple("Use system font")
|
||||
)
|
||||
val appearanceLanguage = SettingsItem.TitleText(
|
||||
key = SettingsKeys.KEY_APPEARANCE_LANGUAGE,
|
||||
title = UiText.Resource(UiR.string.settings_application_language),
|
||||
@@ -374,6 +377,34 @@ class SettingsViewModelImpl(
|
||||
text = UiText.Resource(UiR.string.settings_activity_send_online_summary)
|
||||
)
|
||||
|
||||
val experimentalTitle = SettingsItem.Title(
|
||||
key = "experimental",
|
||||
title = UiText.Simple("Experimental - VERY unstable")
|
||||
)
|
||||
val experimentalLongPollBackground = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_LONG_POLL_IN_BACKGROUND,
|
||||
defaultValue = SettingsKeys.DEFAULT_LONG_POLL_IN_BACKGROUND,
|
||||
title = UiText.Resource(UiR.string.settings_features_long_poll_in_background_title),
|
||||
text = UiText.Resource(UiR.string.settings_features_long_poll_in_background_summary)
|
||||
)
|
||||
val experimentalShowTimeInActionMessages = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_SHOW_TIME_IN_ACTION_MESSAGES,
|
||||
defaultValue = SettingsKeys.DEFAULT_SHOW_TIME_IN_ACTION_MESSAGES,
|
||||
title = UiText.Simple("Show time in action messages")
|
||||
)
|
||||
val experimentalUseBlur = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_USE_BLUR,
|
||||
defaultValue = SettingsKeys.DEFAULT_USE_BLUR,
|
||||
title = UiText.Simple("Use blur"),
|
||||
text = UiText.Simple("Adds blur wherever possible\nWorks on android 12 and newer"),
|
||||
)
|
||||
val enableAnimations = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_MORE_ANIMATIONS,
|
||||
defaultValue = SettingsKeys.DEFAULT_MORE_ANIMATIONS,
|
||||
title = UiText.Simple("More animations"),
|
||||
text = UiText.Simple("Use animations wherever possible")
|
||||
)
|
||||
|
||||
val debugTitle = SettingsItem.Title(
|
||||
key = "debug",
|
||||
title = UiText.Resource(UiR.string.settings_debug_title)
|
||||
@@ -389,34 +420,6 @@ class SettingsViewModelImpl(
|
||||
title = UiText.Simple("Show alert after crash"),
|
||||
text = UiText.Simple("Shows alert dialog with stacktrace after app crashed\n(it will be not shown if you perform crash manually)")
|
||||
)
|
||||
val debugLongPollBackground = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_FEATURES_LONG_POLL_IN_BACKGROUND,
|
||||
defaultValue = SettingsKeys.DEFAULT_VALUE_FEATURES_LONG_POLL_IN_BACKGROUND,
|
||||
title = UiText.Resource(UiR.string.settings_features_long_poll_in_background_title),
|
||||
text = UiText.Resource(UiR.string.settings_features_long_poll_in_background_summary)
|
||||
)
|
||||
val debugUseBlur = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_APPEARANCE_USE_BLUR,
|
||||
defaultValue = SettingsKeys.DEFAULT_VALUE_KEY_APPEARANCE_USE_BLUR,
|
||||
title = UiText.Simple("[WIP] Use blur"),
|
||||
text = UiText.Simple("Adds blur wherever possible\nWorks on android 12 and newer"),
|
||||
)
|
||||
val debugShowEmojiButton = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_SHOW_EMOJI_BUTTON,
|
||||
title = UiText.Simple("Show emoji button"),
|
||||
text = UiText.Simple("Show emoji button in chat panel"),
|
||||
defaultValue = SettingsKeys.DEFAULT_VALUE_KEY_SHOW_EMOJI_BUTTON
|
||||
)
|
||||
val debugShowTimeInActionMessages = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES,
|
||||
defaultValue = SettingsKeys.DEFAULT_VALUE_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES,
|
||||
title = UiText.Simple("Show time in action messages")
|
||||
)
|
||||
val debugEnableHaptic = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_DEBUG_ENABLE_HAPTIC,
|
||||
defaultValue = SettingsKeys.DEFAULT_DEBUG_ENABLE_HAPTIC,
|
||||
title = UiText.Simple("Enable haptic")
|
||||
)
|
||||
|
||||
val logLevelValues = listOf(
|
||||
LogLevel.NONE to UiText.Simple("None"),
|
||||
@@ -440,12 +443,6 @@ class SettingsViewModelImpl(
|
||||
}
|
||||
}
|
||||
|
||||
val debugUseSystemFont = SettingsItem.Switch(
|
||||
key = SettingsKeys.KEY_DEBUG_USE_SYSTEM_FONT,
|
||||
defaultValue = SettingsKeys.DEFAULT_DEBUG_USE_SYSTEM_FONT,
|
||||
title = UiText.Simple("Use system font")
|
||||
)
|
||||
|
||||
val debugHideDebugList = SettingsItem.TitleText(
|
||||
key = SettingsKeys.KEY_DEBUG_HIDE_DEBUG_LIST,
|
||||
title = UiText.Simple("Hide debug list")
|
||||
@@ -458,7 +455,8 @@ class SettingsViewModelImpl(
|
||||
val generalList = listOf(
|
||||
generalTitle,
|
||||
generalUseContactNames,
|
||||
generalEnablePullToRefresh
|
||||
generalShowEmojiButton,
|
||||
generalEnableHaptic
|
||||
)
|
||||
val appearanceList = listOf(
|
||||
appearanceTitle,
|
||||
@@ -466,6 +464,7 @@ class SettingsViewModelImpl(
|
||||
appearanceDarkTheme,
|
||||
appearanceUseAmoledDarkTheme,
|
||||
appearanceUseDynamicColors,
|
||||
appearanceUseSystemFont,
|
||||
appearanceLanguage
|
||||
)
|
||||
val featuresList = listOf(
|
||||
@@ -476,18 +475,19 @@ class SettingsViewModelImpl(
|
||||
activityTitle,
|
||||
visibilitySendOnlineStatus,
|
||||
)
|
||||
val experimentalList = listOf(
|
||||
experimentalTitle,
|
||||
experimentalLongPollBackground,
|
||||
experimentalShowTimeInActionMessages,
|
||||
experimentalUseBlur,
|
||||
enableAnimations
|
||||
)
|
||||
val debugList = mutableListOf<SettingsItem<*>>()
|
||||
listOf(
|
||||
debugTitle,
|
||||
debugPerformCrash,
|
||||
debugShowCrashAlert,
|
||||
debugLongPollBackground,
|
||||
debugUseBlur,
|
||||
debugShowEmojiButton,
|
||||
debugShowTimeInActionMessages,
|
||||
debugEnableHaptic,
|
||||
debugNetworkLogLevel,
|
||||
debugUseSystemFont
|
||||
).forEach(debugList::add)
|
||||
|
||||
debugList += debugHideDebugList
|
||||
@@ -499,6 +499,7 @@ class SettingsViewModelImpl(
|
||||
appearanceList,
|
||||
featuresList,
|
||||
visibilityList,
|
||||
experimentalList,
|
||||
debugList,
|
||||
).forEach(settingsList::addAll)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.meloda.fast.settings.di
|
||||
|
||||
import dev.meloda.fast.settings.SettingsViewModel
|
||||
import dev.meloda.fast.settings.SettingsViewModelImpl
|
||||
import org.koin.androidx.viewmodel.dsl.viewModelOf
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ fun SettingsScreen(
|
||||
|
||||
LaunchedEffect(hapticType) {
|
||||
if (hapticType != null) {
|
||||
if (AppSettings.Debug.enableHaptic) {
|
||||
if (AppSettings.General.enableHaptic) {
|
||||
view.performHapticFeedback(hapticType.getHaptic())
|
||||
}
|
||||
onHapticPerformed()
|
||||
|
||||
Reference in New Issue
Block a user