mirror of
https://github.com/fromchat-messenger/app.git
synced 2026-09-22 19:15:05 +03:00
@@ -19,6 +19,7 @@
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:theme="@style/Theme.FromChat.SplashScreen"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
package ru.fromchat.ui
|
||||
|
||||
import android.view.HapticFeedbackConstants
|
||||
import androidx.activity.compose.BackHandler as AndroidBackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
|
||||
@Composable
|
||||
actual fun BackHandler(enabled: Boolean, onBack: () -> Unit) {
|
||||
AndroidBackHandler(enabled = enabled, onBack = onBack)
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun rememberHapticFeedbackInternal(): (Int) -> Unit {
|
||||
val view = LocalView.current
|
||||
return remember(view) {
|
||||
{ ordinal ->
|
||||
val constant = when (ordinal) {
|
||||
HapticFeedbackEvent.ProfileOpened.ordinal -> HapticFeedbackConstants.CLOCK_TICK
|
||||
HapticFeedbackEvent.ProfileClosed.ordinal -> HapticFeedbackConstants.CLOCK_TICK
|
||||
HapticFeedbackEvent.MessageSent.ordinal -> HapticFeedbackConstants.CONFIRM
|
||||
else -> HapticFeedbackConstants.CLOCK_TICK
|
||||
}
|
||||
view.performHapticFeedback(constant)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,3 +9,6 @@ import androidx.compose.runtime.Composable
|
||||
*/
|
||||
@Composable
|
||||
expect fun BackHandler(enabled: Boolean, onBack: () -> Unit)
|
||||
|
||||
@Composable
|
||||
expect fun rememberHapticFeedbackInternal(): (Int) -> Unit
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package ru.fromchat.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
|
||||
@Composable
|
||||
fun rememberHapticFeedback(): (HapticFeedbackEvent) -> Unit {
|
||||
val h = rememberHapticFeedbackInternal()
|
||||
return remember(h) { { event: HapticFeedbackEvent -> h(event.ordinal) } }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package ru.fromchat.ui
|
||||
|
||||
enum class HapticFeedbackEvent {
|
||||
ProfileOpened,
|
||||
ProfileClosed,
|
||||
MessageSent
|
||||
}
|
||||
@@ -72,7 +72,9 @@ import ru.fromchat.api.WebSocketMessage
|
||||
import ru.fromchat.api.WebSocketUpdatesData
|
||||
import ru.fromchat.back
|
||||
import ru.fromchat.core.Logger
|
||||
import ru.fromchat.ui.HapticFeedbackEvent
|
||||
import ru.fromchat.ui.LocalNavController
|
||||
import ru.fromchat.ui.rememberHapticFeedback
|
||||
import ru.fromchat.ui.scaleOnPress
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalHazeMaterialsApi::class)
|
||||
@@ -116,6 +118,7 @@ fun ChatScreen(
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val listState = rememberLazyListState()
|
||||
val scope = rememberCoroutineScope()
|
||||
val haptic = rememberHapticFeedback()
|
||||
val navController = LocalNavController.current
|
||||
val profileUserId = panelState.profileUserId
|
||||
val hazeState = rememberHazeState(blurEnabled = true)
|
||||
@@ -389,6 +392,7 @@ fun ChatScreen(
|
||||
scope.launch {
|
||||
panel.sendMessageWithImmediateDisplay(text, replyTo?.id)
|
||||
replyTo = null
|
||||
haptic(HapticFeedbackEvent.MessageSent)
|
||||
}
|
||||
}
|
||||
inputText = ""
|
||||
|
||||
@@ -15,6 +15,8 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import ru.fromchat.ui.BackHandler
|
||||
import ru.fromchat.ui.HapticFeedbackEvent
|
||||
import ru.fromchat.ui.rememberHapticFeedback
|
||||
import ru.fromchat.ui.profile.ProfileScreen
|
||||
|
||||
private const val TRANSITION_MS = 320
|
||||
@@ -27,11 +29,13 @@ fun DmContainerScreen(
|
||||
) {
|
||||
var showProfile by remember { mutableStateOf(false) }
|
||||
val scope = rememberCoroutineScope()
|
||||
val haptic = rememberHapticFeedback()
|
||||
val panel = remember(otherUserId) {
|
||||
DmPanelCache.getOrCreate(otherUserId, scope)
|
||||
}
|
||||
|
||||
BackHandler(enabled = showProfile) {
|
||||
haptic(HapticFeedbackEvent.ProfileClosed)
|
||||
showProfile = false
|
||||
}
|
||||
|
||||
@@ -51,7 +55,10 @@ fun DmContainerScreen(
|
||||
DmScreen(
|
||||
panel = panel,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
onTitleClick = { showProfile = true },
|
||||
onTitleClick = {
|
||||
haptic(HapticFeedbackEvent.ProfileOpened)
|
||||
showProfile = true
|
||||
},
|
||||
sharedTransitionScope = this@SharedTransitionLayout,
|
||||
animatedVisibilityScope = this@AnimatedContent,
|
||||
sharedAvatarKey = sharedAvatarKey
|
||||
@@ -59,8 +66,14 @@ fun DmContainerScreen(
|
||||
} else {
|
||||
ProfileScreen(
|
||||
userId = otherUserId,
|
||||
onBack = { showProfile = false },
|
||||
onChat = { _ -> showProfile = false },
|
||||
onBack = {
|
||||
haptic(HapticFeedbackEvent.ProfileClosed)
|
||||
showProfile = false
|
||||
},
|
||||
onChat = { _ ->
|
||||
haptic(HapticFeedbackEvent.ProfileClosed)
|
||||
showProfile = false
|
||||
},
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
sharedTransitionScope = this@SharedTransitionLayout,
|
||||
animatedVisibilityScope = this@AnimatedContent,
|
||||
|
||||
@@ -6,3 +6,6 @@ import androidx.compose.runtime.Composable
|
||||
actual fun BackHandler(enabled: Boolean, onBack: () -> Unit) {
|
||||
// iOS has no system back button; back is handled by navigation.
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun rememberHapticFeedbackInternal(): (Int) -> Unit = { }
|
||||
|
||||
Reference in New Issue
Block a user