diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 88369a88..93a2c2d1 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,5 +1,6 @@ @file:OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class) +import androidx.compose.animation.animateContentSize import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ExperimentalFoundationApi @@ -59,7 +60,6 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -226,8 +226,10 @@ val CONTACT_COLUMN_WIDTH = 230.dp const val CONTACT_COLUMN_CONTACTNAME_LEN_THRESHOLD = 13 const val PUSHURL_SHOW_LEN_THRESHOLD = 60 val GROUPS_COLUMN_WIDTH = 190.dp +val GROUPS_COLLAPSED_COLUMN_WIDTH = 50.dp const val GROUPS_COLUMN_GROUPNAME_LEN_THRESHOLD = 13 val GROUP_PEER_COLUMN_WIDTH = 165.dp +val GROUP_COLLAPSED_PEER_COLUMN_WIDTH = 45.dp const val GROUP_PEER_COLUMN_PEERNAME_LEN_THRESHOLD = 12 val MESSAGE_INPUT_LINE_HEIGHT = 58.dp val MAIN_TOP_TAB_HEIGHT = 160.dp @@ -1229,8 +1231,11 @@ fun App() val groupfocusRequester = remember { FocusRequester() } val groups by groupstore.stateFlow.collectAsState() val grouppeers by grouppeerstore.stateFlow.collectAsState() + val globalstore__ by globalstore.stateFlow.collectAsState() Row(modifier = Modifier.fillMaxWidth().randomDebugBorder()) { - GroupList(groupList = groups) + Box(modifier = Modifier.animateContentSize()) { + GroupList(groupList = groups, peercollapsed = globalstore__.peerListCollapse) + } VerticalDivider() val groupsettings by groupsettingsstore.stateFlow.collectAsState() if ((groupsettings.visible) && (groups.selectedGroupId != null)) // show group settings @@ -1245,7 +1250,9 @@ fun App() load_grouppeers(groups.selectedGroupId!!) } val GroupPeerListScope = rememberCoroutineScope() - GroupPeerList(grouppeerList = grouppeers) + Box(modifier = Modifier.animateContentSize()) { + GroupPeerList(grouppeerList = grouppeers, peercollapsed = globalstore__.peerListCollapse) + } VerticalDivider() if (groups.selectedGroupId == null) { diff --git a/src/main/kotlin/com/zoffcc/applications/trifa/savepathenabled_state.kt b/src/main/kotlin/com/zoffcc/applications/trifa/savepathenabled_state.kt index fd017ecd..94b84425 100644 --- a/src/main/kotlin/com/zoffcc/applications/trifa/savepathenabled_state.kt +++ b/src/main/kotlin/com/zoffcc/applications/trifa/savepathenabled_state.kt @@ -22,6 +22,7 @@ data class globalstore_state( val contacts_unread_message_count: Int = 0, val contacts_unread_group_message_count: Int = 0, val firstRun: Boolean = false, + val peerListCollapse: Boolean = false, val startupSelfname: String = "", val ui_scale: Float = 1.0f, val ui_density: Float = 1.0f, @@ -38,6 +39,7 @@ interface GlobalStore { fun updateFirstRun(value: Boolean) fun updateStartupSelfname(value: String) fun updateUiScale(value: Float) + fun updatePeerListCollapse(value: Boolean) fun updateUiDensity(value: Float) fun setDefaultDensity(value: Float) fun isMinimized(): Boolean @@ -46,6 +48,7 @@ interface GlobalStore { fun getStartupSelfname(): String fun loadUiScale() fun getUiScale(): Float + fun isPeerListCollapse(): Boolean fun loadUiDensity() fun getUiDensity(): Float fun setToxRunning(value: Boolean) @@ -86,6 +89,11 @@ fun CoroutineScope.createGlobalStore(): GlobalStore { mutableStateFlow.value = state.copy(firstRun = value) } + override fun updatePeerListCollapse(value: Boolean) + { + mutableStateFlow.value = state.copy(peerListCollapse = value) + } + override fun updateStartupSelfname(value: String) { mutableStateFlow.value = state.copy(startupSelfname = value) @@ -139,6 +147,11 @@ fun CoroutineScope.createGlobalStore(): GlobalStore { return state.firstRun } + override fun isPeerListCollapse(): Boolean + { + return state.peerListCollapse + } + override fun getStartupSelfname(): String { return state.startupSelfname diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupItemView.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupItemView.kt index 5c49fad5..b58f716e 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupItemView.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupItemView.kt @@ -32,7 +32,6 @@ import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.LockPerson import androidx.compose.material.icons.filled.Public -import androidx.compose.material.icons.filled.Videocam import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -49,12 +48,9 @@ import androidx.compose.ui.text.style.TextOverflow.Companion.Ellipsis import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.zoffcc.applications.trifa.HelperGroup.tox_group_by_groupid__wrapper -import com.zoffcc.applications.trifa.Log import com.zoffcc.applications.trifa.MainActivity.Companion.tox_group_offline_peer_count -import com.zoffcc.applications.trifa.TAG import com.zoffcc.applications.trifa.ToxVars import com.zoffcc.applications.trifa.ToxVars.TOX_GROUP_PRIVACY_STATE -import com.zoffcc.applications.trifa.TrifaToxService.Companion.orma import globalgrpstoreunreadmsgs import org.briarproject.briar.desktop.ui.NumberBadge import org.briarproject.briar.desktop.ui.Tooltip @@ -63,7 +59,8 @@ import randomDebugBorder @Composable @Preview fun test__peercount_circle() = Row() { - PeerCountCircle(peerCount = 236) + val peercollapsed = false + PeerCountCircle(peercollapsed = peercollapsed, peerCount = 236) } @OptIn(ExperimentalFoundationApi::class) @@ -71,8 +68,9 @@ fun test__peercount_circle() = Row() { fun GroupItemView( groupItem: GroupItem, modifier: Modifier = Modifier, + peercollapsed: Boolean, ) = Row( - horizontalArrangement = spacedBy(8.dp), + horizontalArrangement = spacedBy(if(peercollapsed) 0.dp else 8.dp), verticalAlignment = CenterVertically, modifier = modifier.height(IntrinsicSize.Min) ) { @@ -89,14 +87,16 @@ fun GroupItemView( description = "Private Group" } Tooltip(text = description) { - Icon(imageVector = icon, modifier = Modifier.height(20.dp), contentDescription = description) + Icon(imageVector = icon, modifier = Modifier.height(if(peercollapsed) 8.dp else 20.dp), + contentDescription = description) } - Spacer(modifier = Modifier.randomDebugBorder().width(2.dp)) + if(!peercollapsed) { Spacer(modifier = Modifier.randomDebugBorder().width(2.dp)) } Box() { Column(Modifier.align(BottomStart).randomDebugBorder()) { Spacer(modifier = Modifier.randomDebugBorder().height(16.dp)) GroupItemViewInfo( groupItem = groupItem, + peercollapsed = peercollapsed ) } val current_groupstorerunreadmessagesstore by globalgrpstoreunreadmsgs.stateFlow.collectAsState() @@ -107,35 +107,40 @@ fun GroupItemView( ) } } - ConnectionIndicator( - modifier = Modifier.padding(end = 1.dp).requiredSize(16.dp), - isConnected = if (groupItem.isConnected == 0) 0 else 2 - ) + if(!peercollapsed) + { + ConnectionIndicator( + modifier = Modifier.padding(end = 1.dp).requiredSize(16.dp), + isConnected = if (groupItem.isConnected == 0) 0 else 2 + ) + } PeerCountCircle( - modifier = Modifier.padding(end = 1.dp).requiredSize(28.dp), - peerCount = groupItem.numPeers.toLong() + peercollapsed = peercollapsed, + peerCount = groupItem.numPeers.toLong(), + modifier = Modifier.padding(end = 1.dp).requiredSize(if(peercollapsed) 13.dp else 28.dp) ) } @Composable fun PeerCountCircle( - modifier: Modifier = Modifier.size(25.dp), + peercollapsed: Boolean, peerCount: Long, + modifier: Modifier = Modifier.size(if (peercollapsed) 12.dp else 25.dp), ) = Box( modifier = modifier - .border(1.dp, Color.Black, CircleShape) + .border(if(peercollapsed) 0.dp else 1.dp, Color.Black, CircleShape) .background(Color.LightGray, CircleShape) ) { Text(text = "" + peerCount, modifier = Modifier.align(Alignment.Center), - style = TextStyle(fontSize = 12.sp) + style = TextStyle(fontSize = if(peercollapsed) 8.sp else 12.sp) ) } @OptIn(ExperimentalFoundationApi::class) @Composable -private fun GroupItemViewInfo(groupItem: GroupItem) = Column( +private fun GroupItemViewInfo(groupItem: GroupItem, peercollapsed: Boolean) = Column( horizontalAlignment = Start, modifier = Modifier.padding(start = 0.dp).randomDebugBorder() ) { @@ -151,8 +156,8 @@ private fun GroupItemViewInfo(groupItem: GroupItem) = Column( + "Offline Peers: " + offline_num_peers + "\n" ) { Text( - text = groupItem.name, - style = if (groupItem.name.length > GROUPS_COLUMN_GROUPNAME_LEN_THRESHOLD) + text = if(peercollapsed) groupItem.name.take(2) else groupItem.name, + style = if ((groupItem.name.length > GROUPS_COLUMN_GROUPNAME_LEN_THRESHOLD) && (!peercollapsed)) MaterialTheme.typography.body1.copy(fontSize = 13.sp) else MaterialTheme.typography.body1, maxLines = 1, overflow = Ellipsis, diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupList.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupList.kt index c19edf2c..a80de3c8 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupList.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupList.kt @@ -1,6 +1,7 @@ package org.briarproject.briar.desktop.contact import GROUPITEM_HEIGHT +import GROUPS_COLLAPSED_COLUMN_WIDTH import GROUPS_COLUMN_WIDTH import androidx.compose.foundation.ContextMenuArea import androidx.compose.foundation.ContextMenuItem @@ -10,8 +11,6 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.selection.selectableGroup import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -36,8 +35,9 @@ import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n @Composable fun GroupList( groupList: StateGroups, + peercollapsed: Boolean, ) = Column( - modifier = Modifier.fillMaxHeight().width(GROUPS_COLUMN_WIDTH).background(Color.Transparent), + modifier = Modifier.fillMaxHeight().width(if(peercollapsed) GROUPS_COLLAPSED_COLUMN_WIDTH else GROUPS_COLUMN_WIDTH).background(Color.Transparent), ) { VerticallyScrollableArea(modifier = Modifier.fillMaxSize()) { scrollState -> LazyColumn( @@ -69,7 +69,7 @@ fun GroupList( .heightIn(min = GROUPITEM_HEIGHT) .fillMaxWidth() .padding(vertical = 8.dp) - .padding(start = 3.dp, end = 3.dp) + .padding(start = if(peercollapsed) 2.dp else 3.dp, end = if(peercollapsed) 0.dp else 3.dp) ContextMenuArea(items = { listOf( ContextMenuItem("delete") { @@ -83,7 +83,8 @@ fun GroupList( }) { GroupItemView( groupItem = item, - modifier = modifier + modifier = modifier, + peercollapsed = peercollapsed ) } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupPeerList.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupPeerList.kt index a82a717d..650adf70 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupPeerList.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/GroupPeerList.kt @@ -1,7 +1,10 @@ package org.briarproject.briar.desktop.contact +import GROUP_COLLAPSED_PEER_COLUMN_WIDTH import GROUP_PEER_COLUMN_WIDTH import GROUP_PEER_HEIGHT +import androidx.compose.animation.animateContentSize +import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn @@ -16,7 +19,6 @@ import androidx.compose.ui.unit.dp import com.zoffcc.applications.trifa.HelperGroup import com.zoffcc.applications.trifa.MainActivity.Companion.tox_group_self_get_public_key import com.zoffcc.applications.trifa.StateGroupPeers -import grouppeerstore import org.briarproject.briar.desktop.ui.ListItemView import org.briarproject.briar.desktop.ui.VerticallyScrollableArea import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n @@ -27,8 +29,11 @@ import kotlin.math.min @Composable fun GroupPeerList( grouppeerList: StateGroupPeers, + peercollapsed: Boolean, ) = Column( - modifier = Modifier.fillMaxHeight().width(GROUP_PEER_COLUMN_WIDTH).background(Color.Transparent), + modifier = Modifier.fillMaxHeight(). + width(if(peercollapsed) GROUP_COLLAPSED_PEER_COLUMN_WIDTH else GROUP_PEER_COLUMN_WIDTH). + background(Color.Transparent) ) { VerticallyScrollableArea(modifier = Modifier.randomDebugBorder().fillMaxSize()) { scrollState -> LazyColumn( @@ -55,10 +60,11 @@ fun GroupPeerList( .fillMaxWidth() .background(GroupPeerListBgColor(item)) .padding(vertical = 8.dp) - .padding(start = 3.dp, end = 3.dp) + .padding(start = if(peercollapsed) 2.dp else 3.dp, end = if(peercollapsed) 0.dp else 3.dp) GrouppeerItemView( grouppeerItem = item, - modifier = modifier + modifier = modifier, + peercollapsed = peercollapsed ) } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/contact/GrouppeerItemView.kt b/src/main/kotlin/org/briarproject/briar/desktop/contact/GrouppeerItemView.kt index 393f760e..7a513f8b 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/contact/GrouppeerItemView.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/contact/GrouppeerItemView.kt @@ -20,7 +20,6 @@ package org.briarproject.briar.desktop.contact import DefaultFont import GROUP_PEER_COLUMN_PEERNAME_LEN_THRESHOLD -import NotoEmojiFont import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -47,8 +46,9 @@ import org.briarproject.briar.desktop.ui.Tooltip fun GrouppeerItemView( grouppeerItem: GroupPeerItem, modifier: Modifier = Modifier, + peercollapsed: Boolean, ) = Row( - horizontalArrangement = spacedBy(8.dp), + horizontalArrangement = spacedBy(if(peercollapsed) 0.dp else 8.dp), verticalAlignment = CenterVertically, modifier = modifier // allows content to be bottom-aligned @@ -60,36 +60,41 @@ fun GrouppeerItemView( modifier = Modifier.weight(1f, fill = true), ) { Box(Modifier.align(Top).padding(vertical = 8.dp)) { - GroupPeerItemRoleCircle(Modifier.size(15.dp), grouppeerItem) + GroupPeerItemRoleCircle(peercollapsed, grouppeerItem, Modifier.size(if(peercollapsed) 8.dp else 15.dp)) //NumberBadge( // num = contactItem.unread, // modifier = Modifier.align(TopEnd).offset(6.dp, (-6).dp) //) } - Spacer(Modifier.width(2.dp)) + if (!peercollapsed) { Spacer(Modifier.width(2.dp)) } GrouppeerItemViewInfo( grouppeerItem = grouppeerItem, + peercollapsed = peercollapsed + ) + } + if (!peercollapsed) + { + ConnectionIndicator( + modifier = Modifier.padding(end = 5.dp).requiredSize(16.dp), + isConnected = grouppeerItem.connectionStatus ) } - ConnectionIndicator( - modifier = Modifier.padding(end = 5.dp).requiredSize(16.dp), - isConnected = grouppeerItem.connectionStatus - ) } @Composable fun GroupPeerItemRoleCircle( - modifier: Modifier = Modifier.size(10.dp), + peercollapsed: Boolean, grouppeerItem: GroupPeerItem, + modifier: Modifier = Modifier.size(if (peercollapsed) 3.dp else 10.dp), ) = Box( modifier = modifier - .border(1.dp, Color.Black, CircleShape) + .border(if (peercollapsed) 0.dp else 1.dp, Color.Black, CircleShape) .background(GroupPeerRoleAsBgColor(grouppeerItem.peerRole), CircleShape) ) { Text(text = "" + GroupPeerRoleAsStringShort(grouppeerItem.peerRole), modifier = Modifier.align(Alignment.Center), - style = TextStyle(fontSize = 10.sp) + style = TextStyle(fontSize = if (peercollapsed) 5.sp else 10.sp) ) } @@ -155,19 +160,28 @@ fun GroupPeerRoleAsBgColor(peerRole: Int) : Color @OptIn(ExperimentalFoundationApi::class) @Composable -private fun GrouppeerItemViewInfo(grouppeerItem: GroupPeerItem) = Column( +private fun GrouppeerItemViewInfo(grouppeerItem: GroupPeerItem, peercollapsed: Boolean) = Column( horizontalAlignment = Start, modifier = Modifier.padding(start = 0.dp) ) { var show_peer_name = if (grouppeerItem.name.isEmpty()) grouppeerItem.pubkey.toUpperCase().take(6) else grouppeerItem.name val tooltip_name = if (grouppeerItem.name.isEmpty()) "" else grouppeerItem.name - var name_style = if (grouppeerItem.name.length > GROUP_PEER_COLUMN_PEERNAME_LEN_THRESHOLD) - MaterialTheme.typography.body1.copy(fontSize = 12.sp, lineHeight = TextUnit.Unspecified) else MaterialTheme.typography.body1.copy(lineHeight = TextUnit.Unspecified) + var name_style = if ((grouppeerItem.name.length > GROUP_PEER_COLUMN_PEERNAME_LEN_THRESHOLD) && (!peercollapsed)) + MaterialTheme.typography.body1.copy( + fontSize = 12.sp, + lineHeight = TextUnit.Unspecified + ) else MaterialTheme.typography.body1.copy(lineHeight = TextUnit.Unspecified) val ip_addr_str = grouppeerItem.ip_addr // Log.i(TAG, "GrouppeerItemViewInfo: ip_addr_str=" + ip_addr_str + " name=" + show_peer_name) - if (ip_addr_str.length > 0) { - show_peer_name = show_peer_name + "\n" + ip_addr_str - name_style = name_style.copy(fontSize = (name_style.fontSize.value - 4).sp) + if (peercollapsed) { + show_peer_name = show_peer_name.take(2) + } else + { + if (ip_addr_str.length > 0) + { + show_peer_name = show_peer_name + "\n" + ip_addr_str + name_style = name_style.copy(fontSize = (name_style.fontSize.value - 4).sp) + } } Tooltip(text = "Peer Name: " + tooltip_name + "\n" + "Peer Role: " + GroupPeerRoleAsStringLong(grouppeerItem.peerRole) + "\n" @@ -177,7 +191,7 @@ private fun GrouppeerItemViewInfo(grouppeerItem: GroupPeerItem) = Column( text = show_peer_name, fontFamily = DefaultFont, style = name_style, - maxLines = 2, + maxLines = if (peercollapsed) 1 else 2, overflow = Ellipsis, ) } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt b/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt index d515d51a..5aa19c88 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/navigation/BriarSidebar.kt @@ -35,6 +35,9 @@ import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Contacts import androidx.compose.material.icons.filled.Error import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -44,6 +47,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp +import com.zoffcc.applications.trifa.Log +import com.zoffcc.applications.trifa.TAG import globalstore import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope @@ -100,6 +105,20 @@ fun BriarSidebar( BriarSidebarButton(UiMode.ADDFRIEND) BriarSidebarButton(UiMode.ADDGROUP) BriarSidebarButton(UiMode.ABOUT) + val global_store by globalstore.stateFlow.collectAsState() + if (global_store.toxRunning) + { + BriarSidebarButton( + selected = false, + onClick = { + globalstore.updatePeerListCollapse(!globalstore.isPeerListCollapse()) + Log.i(TAG, "PeerListCollapse=" + globalstore.isPeerListCollapse()) + }, + icon = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "", + sideBarButtonState = None + ) + } } }