feat: implement avatar animation and enhance image sharing functionality
This commit is contained in:
@@ -17,6 +17,7 @@ import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
@@ -26,6 +27,8 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
@@ -34,7 +37,6 @@ import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material.icons.outlined.Block
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -160,12 +162,13 @@ private fun calculateAverageColor(bitmap: android.graphics.Bitmap): Color {
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun OtherProfileScreen(
|
||||
user: SearchUser,
|
||||
isDarkTheme: Boolean,
|
||||
onBack: () -> Unit,
|
||||
onSwipeBackEnabledChanged: (Boolean) -> Unit = {},
|
||||
avatarRepository: AvatarRepository? = null,
|
||||
currentUserPublicKey: String = "",
|
||||
currentUserPrivateKey: String = "",
|
||||
@@ -173,9 +176,19 @@ fun OtherProfileScreen(
|
||||
) {
|
||||
var isBlocked by remember { mutableStateOf(false) }
|
||||
var showAvatarMenu by remember { mutableStateOf(false) }
|
||||
var selectedTab by rememberSaveable { mutableStateOf(OtherProfileTab.MEDIA) }
|
||||
var showImageViewer by remember { mutableStateOf(false) }
|
||||
var imageViewerInitialIndex by remember { mutableIntStateOf(0) }
|
||||
val tabs = remember { OtherProfileTab.entries }
|
||||
val pagerState = rememberPagerState(initialPage = 0, pageCount = { tabs.size })
|
||||
val selectedTab =
|
||||
tabs.getOrElse(pagerState.currentPage.coerceIn(0, tabs.lastIndex)) {
|
||||
OtherProfileTab.MEDIA
|
||||
}
|
||||
val screenHeightDp = LocalConfiguration.current.screenHeightDp.dp
|
||||
val sharedPagerMinHeight = (screenHeightDp * 0.45f).coerceAtLeast(240.dp)
|
||||
LaunchedEffect(selectedTab) {
|
||||
onSwipeBackEnabledChanged(selectedTab == OtherProfileTab.MEDIA)
|
||||
}
|
||||
|
||||
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
||||
val avatarColors = getAvatarColor(user.publicKey, isDarkTheme)
|
||||
@@ -535,62 +548,78 @@ fun OtherProfileScreen(
|
||||
|
||||
OtherProfileSharedTabs(
|
||||
selectedTab = selectedTab,
|
||||
onTabSelected = { selectedTab = it },
|
||||
onTabSelected = { tab ->
|
||||
val targetPage = tab.ordinal
|
||||
if (pagerState.currentPage != targetPage) {
|
||||
coroutineScope.launch {
|
||||
pagerState.animateScrollToPage(targetPage)
|
||||
}
|
||||
}
|
||||
},
|
||||
isDarkTheme = isDarkTheme
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
OtherProfileSharedTabContent(
|
||||
selectedTab = selectedTab,
|
||||
sharedContent = sharedContent,
|
||||
isDarkTheme = isDarkTheme,
|
||||
accountPublicKey = activeAccountPublicKey,
|
||||
accountPrivateKey = activeAccountPrivateKey,
|
||||
onMediaClick = { index ->
|
||||
imageViewerInitialIndex = index
|
||||
showImageViewer = true
|
||||
},
|
||||
onFileClick = { file ->
|
||||
val opened = openSharedFile(context, file)
|
||||
if (!opened) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
"File is not available on this device",
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
.show()
|
||||
}
|
||||
},
|
||||
onLinkClick = { link ->
|
||||
val normalizedLink =
|
||||
if (link.startsWith("http://", ignoreCase = true) ||
|
||||
link.startsWith("https://", ignoreCase = true)
|
||||
) {
|
||||
link
|
||||
} else {
|
||||
"https://$link"
|
||||
}
|
||||
val opened =
|
||||
runCatching {
|
||||
context.startActivity(
|
||||
Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse(normalizedLink)
|
||||
)
|
||||
HorizontalPager(
|
||||
state = pagerState,
|
||||
modifier = Modifier.fillMaxWidth().heightIn(min = sharedPagerMinHeight),
|
||||
beyondBoundsPageCount = 0,
|
||||
verticalAlignment = Alignment.Top
|
||||
) { page ->
|
||||
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.TopStart) {
|
||||
OtherProfileSharedTabContent(
|
||||
selectedTab = tabs[page],
|
||||
sharedContent = sharedContent,
|
||||
isDarkTheme = isDarkTheme,
|
||||
accountPublicKey = activeAccountPublicKey,
|
||||
accountPrivateKey = activeAccountPrivateKey,
|
||||
onMediaClick = { index ->
|
||||
imageViewerInitialIndex = index
|
||||
showImageViewer = true
|
||||
},
|
||||
onFileClick = { file ->
|
||||
val opened = openSharedFile(context, file)
|
||||
if (!opened) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
"File is not available on this device",
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
.show()
|
||||
}
|
||||
},
|
||||
onLinkClick = { link ->
|
||||
val normalizedLink =
|
||||
if (link.startsWith("http://", ignoreCase = true) ||
|
||||
link.startsWith("https://", ignoreCase = true)
|
||||
) {
|
||||
link
|
||||
} else {
|
||||
"https://$link"
|
||||
}
|
||||
.isSuccess
|
||||
if (!opened) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
"Unable to open this link",
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
)
|
||||
val opened =
|
||||
runCatching {
|
||||
context.startActivity(
|
||||
Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
Uri.parse(normalizedLink)
|
||||
)
|
||||
)
|
||||
}
|
||||
.isSuccess
|
||||
if (!opened) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
"Unable to open this link",
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user