Recent repositories now are unlimited, can be removed and searched
This commit is contained in:
parent
ef41e9acf0
commit
127f2158ee
@ -5,6 +5,8 @@ import com.jetpackduba.gitnuro.repositories.AppSettingsRepository
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.serialization.decodeFromString
|
||||
@ -20,26 +22,25 @@ class AppStateManager @Inject constructor(
|
||||
) {
|
||||
private val mutex = Mutex()
|
||||
|
||||
private val _latestOpenedRepositoriesPaths = mutableListOf<String>()
|
||||
val latestOpenedRepositoriesPaths: List<String>
|
||||
get() = _latestOpenedRepositoriesPaths
|
||||
private val _latestOpenedRepositoriesPaths = MutableStateFlow<List<String>>(emptyList())
|
||||
val latestOpenedRepositoriesPaths = _latestOpenedRepositoriesPaths.asStateFlow()
|
||||
|
||||
val latestOpenedRepositoryPath: String
|
||||
get() = _latestOpenedRepositoriesPaths.firstOrNull() ?: ""
|
||||
get() = _latestOpenedRepositoriesPaths.value.firstOrNull() ?: ""
|
||||
|
||||
fun repositoryTabChanged(path: String) = appScope.launch(Dispatchers.IO) {
|
||||
mutex.lock()
|
||||
try {
|
||||
val repoPaths = _latestOpenedRepositoriesPaths.value.toMutableList()
|
||||
|
||||
// Remove any previously existing path
|
||||
_latestOpenedRepositoriesPaths.removeIf { it == path }
|
||||
repoPaths.removeIf { it == path }
|
||||
|
||||
// Add the latest one to the beginning
|
||||
_latestOpenedRepositoriesPaths.add(0, path)
|
||||
repoPaths.add(0, path)
|
||||
|
||||
if (_latestOpenedRepositoriesPaths.count() > 10)
|
||||
_latestOpenedRepositoriesPaths.removeLast()
|
||||
|
||||
appSettingsRepository.latestOpenedRepositoriesPath = Json.encodeToString(_latestOpenedRepositoriesPaths)
|
||||
appSettingsRepository.latestOpenedRepositoriesPath = Json.encodeToString(repoPaths)
|
||||
_latestOpenedRepositoriesPaths.value = repoPaths
|
||||
} finally {
|
||||
mutex.unlock()
|
||||
}
|
||||
@ -49,11 +50,28 @@ class AppStateManager @Inject constructor(
|
||||
val repositoriesPathsSaved = appSettingsRepository.latestOpenedRepositoriesPath
|
||||
if (repositoriesPathsSaved.isNotEmpty()) {
|
||||
val repositories = Json.decodeFromString<List<String>>(repositoriesPathsSaved)
|
||||
_latestOpenedRepositoriesPaths.addAll(repositories)
|
||||
val repoPaths = _latestOpenedRepositoriesPaths.value.toMutableList()
|
||||
|
||||
repoPaths.addAll(repositories)
|
||||
|
||||
_latestOpenedRepositoriesPaths.value = repoPaths
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelCoroutines() {
|
||||
appScope.cancel("Closing app")
|
||||
}
|
||||
|
||||
fun removeRepositoryFromRecent(path: String) = appScope.launch {
|
||||
mutex.lock()
|
||||
try {
|
||||
val repoPaths = _latestOpenedRepositoriesPaths.value.toMutableList()
|
||||
repoPaths.removeIf { it == path }
|
||||
|
||||
appSettingsRepository.latestOpenedRepositoriesPath = Json.encodeToString(repoPaths)
|
||||
_latestOpenedRepositoriesPaths.value = repoPaths
|
||||
} finally {
|
||||
mutex.unlock()
|
||||
}
|
||||
}
|
||||
}
|
@ -21,11 +21,13 @@ import com.jetpackduba.gitnuro.git.DiffEntryType
|
||||
import com.jetpackduba.gitnuro.git.rebase.RebaseInteractiveState
|
||||
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
|
||||
import com.jetpackduba.gitnuro.keybindings.matchesBinding
|
||||
import com.jetpackduba.gitnuro.models.AuthorInfoSimple
|
||||
import com.jetpackduba.gitnuro.ui.components.SecondaryButton
|
||||
import com.jetpackduba.gitnuro.ui.components.TripleVerticalSplitPanel
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.*
|
||||
import com.jetpackduba.gitnuro.ui.diff.Diff
|
||||
import com.jetpackduba.gitnuro.ui.log.Log
|
||||
import com.jetpackduba.gitnuro.updates.Update
|
||||
import com.jetpackduba.gitnuro.viewmodels.BlameState
|
||||
import com.jetpackduba.gitnuro.viewmodels.TabViewModel
|
||||
import org.eclipse.jgit.lib.RepositoryState
|
||||
@ -160,14 +162,26 @@ fun RepositoryOpenPage(
|
||||
.background(MaterialTheme.colors.primaryVariant.copy(alpha = 0.2f))
|
||||
)
|
||||
|
||||
BottomInfoBar(tabViewModel)
|
||||
|
||||
val userInfo by tabViewModel.authorInfoSimple.collectAsState()
|
||||
val newUpdate = tabViewModel.update.collectAsState().value
|
||||
|
||||
BottomInfoBar(
|
||||
userInfo,
|
||||
newUpdate,
|
||||
onOpenUrlInBrowser = { tabViewModel.openUrlInBrowser(it) },
|
||||
onShowAuthorInfoDialog = { tabViewModel.showAuthorInfoDialog() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BottomInfoBar(tabViewModel: TabViewModel) {
|
||||
val userInfo by tabViewModel.authorInfoSimple.collectAsState()
|
||||
val newUpdate = tabViewModel.hasUpdates.collectAsState().value
|
||||
private fun BottomInfoBar(
|
||||
userInfo: AuthorInfoSimple,
|
||||
newUpdate: Update?,
|
||||
onOpenUrlInBrowser: (String) -> Unit,
|
||||
onShowAuthorInfoDialog: () -> Unit,
|
||||
) {
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@ -180,7 +194,7 @@ private fun BottomInfoBar(tabViewModel: TabViewModel) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.handMouseClickable { tabViewModel.showAuthorInfoDialog() },
|
||||
.handMouseClickable { onShowAuthorInfoDialog() },
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
@ -194,7 +208,7 @@ private fun BottomInfoBar(tabViewModel: TabViewModel) {
|
||||
if (newUpdate != null) {
|
||||
SecondaryButton(
|
||||
text = "Update ${newUpdate.appVersion} available",
|
||||
onClick = { tabViewModel.openUrlInBrowser(newUpdate.downloadUrl) },
|
||||
onClick = { onOpenUrlInBrowser(newUpdate.downloadUrl) },
|
||||
backgroundButton = MaterialTheme.colors.primary,
|
||||
modifier = Modifier.padding(end = 16.dp)
|
||||
)
|
||||
|
@ -2,11 +2,14 @@
|
||||
|
||||
package com.jetpackduba.gitnuro.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsHoveredAsState
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
@ -14,6 +17,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.BiasAlignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
@ -24,15 +28,14 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.AppConstants
|
||||
import com.jetpackduba.gitnuro.AppIcons
|
||||
import com.jetpackduba.gitnuro.extensions.dirName
|
||||
import com.jetpackduba.gitnuro.extensions.dirPath
|
||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.managers.AppStateManager
|
||||
import com.jetpackduba.gitnuro.extensions.*
|
||||
import com.jetpackduba.gitnuro.theme.AppTheme
|
||||
import com.jetpackduba.gitnuro.theme.onBackgroundSecondary
|
||||
import com.jetpackduba.gitnuro.theme.textButtonColors
|
||||
import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField
|
||||
import com.jetpackduba.gitnuro.ui.components.SecondaryButton
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.AppInfoDialog
|
||||
import com.jetpackduba.gitnuro.updates.Update
|
||||
import com.jetpackduba.gitnuro.viewmodels.TabViewModel
|
||||
|
||||
|
||||
@ -42,44 +45,113 @@ fun WelcomePage(
|
||||
onShowCloneDialog: () -> Unit,
|
||||
onShowSettings: () -> Unit,
|
||||
) {
|
||||
val appStateManager = tabViewModel.appStateManager
|
||||
var showAdditionalInfo by remember { mutableStateOf(false) }
|
||||
val recentlyOpenedRepositories by tabViewModel.appStateManager.latestOpenedRepositoriesPaths.collectAsState()
|
||||
val newUpdate by tabViewModel.update.collectAsState()
|
||||
|
||||
WelcomeView(
|
||||
recentlyOpenedRepositories,
|
||||
newUpdate,
|
||||
onShowCloneDialog = onShowCloneDialog,
|
||||
onShowSettings = onShowSettings,
|
||||
onOpenRepository = {
|
||||
val repo = tabViewModel.openDirectoryPicker()
|
||||
|
||||
if (repo != null) {
|
||||
tabViewModel.openRepository(repo)
|
||||
}
|
||||
},
|
||||
onStartRepository = {
|
||||
val dir = tabViewModel.openDirectoryPicker()
|
||||
|
||||
if (dir != null) {
|
||||
tabViewModel.initLocalRepository(dir)
|
||||
}
|
||||
},
|
||||
onOpenKnownRepository = { tabViewModel.openRepository(it) },
|
||||
onOpenUrlInBrowser = { tabViewModel.openUrlInBrowser(it) },
|
||||
onRemoveRepositoryFromRecent = { tabViewModel.removeRepositoryFromRecent(it) }
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun WelcomeViewPreview() {
|
||||
AppTheme(
|
||||
customTheme = null
|
||||
) {
|
||||
val recentRepositories = (0..10).map {
|
||||
"/home/user/sample$it"
|
||||
}
|
||||
WelcomeView(
|
||||
recentlyOpenedRepositories = recentRepositories,
|
||||
newUpdate = null,
|
||||
onShowCloneDialog = {},
|
||||
onShowSettings = {},
|
||||
onOpenRepository = {},
|
||||
onOpenKnownRepository = {},
|
||||
onStartRepository = {},
|
||||
onOpenUrlInBrowser = {},
|
||||
onRemoveRepositoryFromRecent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun WelcomeView(
|
||||
recentlyOpenedRepositories: List<String>,
|
||||
newUpdate: Update?,
|
||||
onShowCloneDialog: () -> Unit,
|
||||
onShowSettings: () -> Unit,
|
||||
onOpenRepository: () -> Unit,
|
||||
onOpenKnownRepository: (String) -> Unit,
|
||||
onStartRepository: () -> Unit,
|
||||
onOpenUrlInBrowser: (String) -> Unit,
|
||||
onRemoveRepositoryFromRecent: (String) -> Unit,
|
||||
) {
|
||||
|
||||
var showAdditionalInfo by remember { mutableStateOf(false) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(MaterialTheme.colors.surface),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = BiasAlignment.Vertical(-0.5f),
|
||||
|
||||
Column(
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||
.weight(1f),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp, BiasAlignment.Vertical(-0.5f)),
|
||||
) {
|
||||
HomeButtons(
|
||||
onOpenRepository = {
|
||||
val repo = tabViewModel.openDirectoryPicker()
|
||||
|
||||
if (repo != null) {
|
||||
tabViewModel.openRepository(repo)
|
||||
}
|
||||
},
|
||||
onStartRepository = {
|
||||
val dir = tabViewModel.openDirectoryPicker()
|
||||
|
||||
if (dir != null) {
|
||||
tabViewModel.initLocalRepository(dir)
|
||||
}
|
||||
},
|
||||
onShowCloneView = onShowCloneDialog,
|
||||
onShowAdditionalInfo = { showAdditionalInfo = true },
|
||||
onShowSettings = onShowSettings,
|
||||
onOpenUrlInBrowser = { url -> tabViewModel.openUrlInBrowser(url) }
|
||||
Text(
|
||||
text = AppConstants.APP_NAME,
|
||||
style = MaterialTheme.typography.h1,
|
||||
maxLines = 1,
|
||||
modifier = Modifier.padding(bottom = 8.dp),
|
||||
)
|
||||
|
||||
RecentRepositories(appStateManager, tabViewModel)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterHorizontally),
|
||||
) {
|
||||
HomeButtons(
|
||||
onOpenRepository = onOpenRepository,
|
||||
onStartRepository = onStartRepository,
|
||||
onShowCloneView = onShowCloneDialog,
|
||||
onShowAdditionalInfo = { showAdditionalInfo = true },
|
||||
onShowSettings = onShowSettings,
|
||||
onOpenUrlInBrowser = onOpenUrlInBrowser,
|
||||
)
|
||||
|
||||
RecentRepositories(
|
||||
recentlyOpenedRepositories,
|
||||
canRepositoriesBeRemoved = true,
|
||||
onOpenKnownRepository = onOpenKnownRepository,
|
||||
onRemoveRepositoryFromRecent = onRemoveRepositoryFromRecent,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.height(1.dp)
|
||||
@ -87,20 +159,25 @@ fun WelcomePage(
|
||||
.background(MaterialTheme.colors.primaryVariant.copy(alpha = 0.2f))
|
||||
)
|
||||
|
||||
BottomInfoBar(tabViewModel)
|
||||
BottomInfoBar(
|
||||
newUpdate = newUpdate,
|
||||
onOpenUrlInBrowser = onOpenUrlInBrowser,
|
||||
)
|
||||
}
|
||||
|
||||
if (showAdditionalInfo) {
|
||||
AppInfoDialog(
|
||||
onClose = { showAdditionalInfo = false },
|
||||
onOpenUrlInBrowser = { url -> tabViewModel.openUrlInBrowser(url) }
|
||||
onOpenUrlInBrowser = onOpenUrlInBrowser
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BottomInfoBar(tabViewModel: TabViewModel) {
|
||||
val newUpdate = tabViewModel.hasUpdates.collectAsState().value
|
||||
private fun BottomInfoBar(
|
||||
newUpdate: Update?,
|
||||
onOpenUrlInBrowser: (String) -> Unit,
|
||||
) {
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@ -115,7 +192,7 @@ private fun BottomInfoBar(tabViewModel: TabViewModel) {
|
||||
if (newUpdate != null) {
|
||||
SecondaryButton(
|
||||
text = "Update ${newUpdate.appVersion} available",
|
||||
onClick = { tabViewModel.openUrlInBrowser(newUpdate.downloadUrl) },
|
||||
onClick = { onOpenUrlInBrowser(newUpdate.downloadUrl) },
|
||||
backgroundButton = MaterialTheme.colors.primary,
|
||||
modifier = Modifier.padding(end = 16.dp)
|
||||
)
|
||||
@ -138,16 +215,7 @@ fun HomeButtons(
|
||||
onShowSettings: () -> Unit,
|
||||
onOpenUrlInBrowser: (String) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(end = 32.dp),
|
||||
) {
|
||||
Text(
|
||||
text = AppConstants.APP_NAME,
|
||||
style = MaterialTheme.typography.h1,
|
||||
maxLines = 1,
|
||||
modifier = Modifier.padding(bottom = 16.dp),
|
||||
)
|
||||
|
||||
Column {
|
||||
ButtonTile(
|
||||
modifier = Modifier.padding(bottom = 8.dp),
|
||||
title = "Open a repository",
|
||||
@ -206,19 +274,23 @@ fun HomeButtons(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RecentRepositories(appStateManager: AppStateManager, tabViewModel: TabViewModel) {
|
||||
fun RecentRepositories(
|
||||
recentlyOpenedRepositories: List<String>,
|
||||
canRepositoriesBeRemoved: Boolean,
|
||||
onRemoveRepositoryFromRecent: (String) -> Unit,
|
||||
onOpenKnownRepository: (String) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(start = 32.dp),
|
||||
.padding(start = 32.dp)
|
||||
.width(600.dp)
|
||||
.height(400.dp),
|
||||
) {
|
||||
val latestOpenedRepositoriesPaths = appStateManager.latestOpenedRepositoriesPaths
|
||||
Text(
|
||||
text = "Recent",
|
||||
style = MaterialTheme.typography.h3,
|
||||
modifier = Modifier.padding(top = 48.dp, bottom = 4.dp),
|
||||
)
|
||||
var filter by remember {
|
||||
mutableStateOf("")
|
||||
}
|
||||
|
||||
if (latestOpenedRepositoriesPaths.isEmpty()) {
|
||||
if (recentlyOpenedRepositories.isEmpty()) {
|
||||
Text(
|
||||
"Nothing to see here, open a repository first!",
|
||||
color = MaterialTheme.colors.onBackgroundSecondary,
|
||||
@ -226,47 +298,113 @@ fun RecentRepositories(appStateManager: AppStateManager, tabViewModel: TabViewMo
|
||||
modifier = Modifier.padding(top = 16.dp)
|
||||
)
|
||||
} else {
|
||||
LazyColumn {
|
||||
items(items = latestOpenedRepositoriesPaths) { repo ->
|
||||
val repoDirName = repo.dirName
|
||||
val repoDirPath = repo.dirPath
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(vertical = 4.dp)
|
||||
) {
|
||||
Box(
|
||||
AdjustableOutlinedTextField(
|
||||
value = filter,
|
||||
onValueChange = { filter = it },
|
||||
hint = "Search for recent repositories",
|
||||
trailingIcon = {
|
||||
if (filter.isNotEmpty()) {
|
||||
IconButton(
|
||||
onClick = { filter = "" },
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.handMouseClickable {
|
||||
tabViewModel.openRepository(repo)
|
||||
},
|
||||
.size(16.dp)
|
||||
.handOnHover(),
|
||||
) {
|
||||
Text(
|
||||
text = repoDirName,
|
||||
style = MaterialTheme.typography.body1,
|
||||
maxLines = 1,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colors.primaryVariant,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.widthIn(max = 600.dp),
|
||||
Icon(
|
||||
painterResource(AppIcons.CLOSE),
|
||||
contentDescription = null,
|
||||
tint = if (filter.isEmpty()) MaterialTheme.colors.onBackgroundSecondary else MaterialTheme.colors.onBackground
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = repoDirPath,
|
||||
style = MaterialTheme.typography.body1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier
|
||||
.padding(start = 4.dp)
|
||||
.widthIn(max = 600.dp),
|
||||
maxLines = 1,
|
||||
color = MaterialTheme.colors.onBackgroundSecondary
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
val filteredRepositories = remember(filter, recentlyOpenedRepositories) {
|
||||
if (filter.isBlank()) {
|
||||
recentlyOpenedRepositories
|
||||
} else {
|
||||
recentlyOpenedRepositories.filter { repository ->
|
||||
repository.lowercaseContains(filter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
Box (modifier = Modifier.padding(top = 4.dp)) {
|
||||
LazyColumn(
|
||||
state = listState,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
items(items = filteredRepositories) { repo ->
|
||||
val repoDirName = repo.dirName
|
||||
val repoDirPath = repo.dirPath
|
||||
val hoverInteraction = remember { MutableInteractionSource() }
|
||||
val isHovered by hoverInteraction.collectIsHoveredAsState()
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.fillMaxWidth()
|
||||
.hoverable(hoverInteraction)
|
||||
.handMouseClickable { onOpenKnownRepository(repo) }
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp, Alignment.CenterVertically),
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
Text(
|
||||
text = repoDirName,
|
||||
style = MaterialTheme.typography.body2,
|
||||
maxLines = 1,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colors.primaryVariant,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = repoDirPath,
|
||||
style = MaterialTheme.typography.body2,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier,
|
||||
maxLines = 1,
|
||||
color = MaterialTheme.colors.onBackgroundSecondary
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val buttonAlpha = if (canRepositoriesBeRemoved && isHovered) {
|
||||
1f
|
||||
} else {
|
||||
0f
|
||||
}
|
||||
|
||||
IconButton(
|
||||
onClick = { onRemoveRepositoryFromRecent(repo) },
|
||||
enabled = canRepositoriesBeRemoved && isHovered,
|
||||
modifier = Modifier.alpha(buttonAlpha)
|
||||
.size(24.dp)
|
||||
.handOnHover(),
|
||||
) {
|
||||
Icon(
|
||||
painterResource(AppIcons.CLOSE),
|
||||
contentDescription = "Remove repository from recent",
|
||||
modifier = Modifier.size(24.dp),
|
||||
tint = MaterialTheme.colors.onBackgroundSecondary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VerticalScrollbar(
|
||||
rememberScrollbarAdapter(listState),
|
||||
modifier = Modifier.align(Alignment.CenterEnd)
|
||||
.fillMaxHeight(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.DropdownMenuItem
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun DropDownContent(
|
||||
dropDownContentData: DropDownContentData,
|
||||
enabled: Boolean = true,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
enabled = enabled,
|
||||
onClick = {
|
||||
dropDownContentData.onClick()
|
||||
onDismiss()
|
||||
}
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (dropDownContentData.icon != null) {
|
||||
Icon(
|
||||
painter = painterResource(dropDownContentData.icon),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = dropDownContentData.label,
|
||||
style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
data class DropDownContentData(
|
||||
val label: String,
|
||||
val icon: String? = null,
|
||||
val onClick: () -> Unit,
|
||||
)
|
@ -1,17 +0,0 @@
|
||||
package com.jetpackduba.gitnuro.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import com.jetpackduba.gitnuro.AppIcons
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun repositoryAdditionalOptionsMenu(
|
||||
onOpenRepositoryOnFileExplorer: () -> Unit,
|
||||
): List<DropDownContentData> {
|
||||
return mutableListOf(
|
||||
DropDownContentData(
|
||||
label = "Open repository folder",
|
||||
icon = AppIcons.SOURCE,
|
||||
onClick = onOpenRepositoryOnFileExplorer,
|
||||
),
|
||||
)
|
||||
}
|
@ -442,7 +442,7 @@ fun SearchFilter(
|
||||
.padding(end = 4.dp),
|
||||
onClick = { logViewModel.closeSearch() }
|
||||
) {
|
||||
Icon(Icons.Default.Clear, contentDescription = null)
|
||||
Icon(painterResource(AppIcons.CLOSE), contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -348,7 +348,7 @@ class TabViewModel @Inject constructor(
|
||||
openRepository(repoDir)
|
||||
}
|
||||
|
||||
val hasUpdates: StateFlow<Update?> = updatesRepository.hasUpdatesFlow()
|
||||
val update: StateFlow<Update?> = updatesRepository.hasUpdatesFlow()
|
||||
.flowOn(Dispatchers.IO)
|
||||
.stateIn(tabScope, started = SharingStarted.Eagerly, null)
|
||||
|
||||
@ -449,6 +449,10 @@ class TabViewModel @Inject constructor(
|
||||
fun openUrlInBrowser(url: String) {
|
||||
openUrlInBrowserUseCase(url)
|
||||
}
|
||||
|
||||
fun removeRepositoryFromRecent(repository: String) {
|
||||
appStateManager.removeRepositoryFromRecent(repository)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user