diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/managers/AppStateManager.kt b/src/main/kotlin/com/jetpackduba/gitnuro/managers/AppStateManager.kt index cf331c85..35fb85ed 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/managers/AppStateManager.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/managers/AppStateManager.kt @@ -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() - val latestOpenedRepositoriesPaths: List - get() = _latestOpenedRepositoriesPaths + private val _latestOpenedRepositoriesPaths = MutableStateFlow>(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) - - if (_latestOpenedRepositoriesPaths.count() > 10) - _latestOpenedRepositoriesPaths.removeLast() + repoPaths.add(0, path) - 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>(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() + } + } } \ No newline at end of file diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt index 23239ba0..a7297405 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/RepositoryOpen.kt @@ -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) ) diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/WelcomePage.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/WelcomePage.kt index ee998f84..87841920 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/WelcomePage.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/WelcomePage.kt @@ -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, + 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, + 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 ) } + } + } + ) + + val filteredRepositories = remember(filter, recentlyOpenedRepositories) { + if (filter.isBlank()) { + recentlyOpenedRepositories + } else { + recentlyOpenedRepositories.filter { repository -> + repository.lowercaseContains(filter) + } + } + } + + val listState = rememberLazyListState() - Text( - text = repoDirPath, - style = MaterialTheme.typography.body1, - overflow = TextOverflow.Ellipsis, + 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 - .padding(start = 4.dp) - .widthIn(max = 600.dp), - maxLines = 1, - color = MaterialTheme.colors.onBackgroundSecondary - ) + .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(), + ) } } } diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/DropDownContent.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/DropDownContent.kt deleted file mode 100644 index 667e6b60..00000000 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/DropDownContent.kt +++ /dev/null @@ -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, - ) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/DropDownContentData.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/DropDownContentData.kt deleted file mode 100644 index 0d939382..00000000 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/DropDownContentData.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.jetpackduba.gitnuro.ui.context_menu - -data class DropDownContentData( - val label: String, - val icon: String? = null, - val onClick: () -> Unit, -) diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/RepositoryAdditionalOptionsMenu.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/RepositoryAdditionalOptionsMenu.kt deleted file mode 100644 index fa7e06f9..00000000 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/context_menu/RepositoryAdditionalOptionsMenu.kt +++ /dev/null @@ -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 { - return mutableListOf( - DropDownContentData( - label = "Open repository folder", - icon = AppIcons.SOURCE, - onClick = onOpenRepositoryOnFileExplorer, - ), - ) -} diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/ui/log/Log.kt b/src/main/kotlin/com/jetpackduba/gitnuro/ui/log/Log.kt index e30e47e6..63ef4455 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/ui/log/Log.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/ui/log/Log.kt @@ -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) } } } diff --git a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt index 09095fd2..2c6c34e3 100644 --- a/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt +++ b/src/main/kotlin/com/jetpackduba/gitnuro/viewmodels/TabViewModel.kt @@ -348,7 +348,7 @@ class TabViewModel @Inject constructor( openRepository(repoDir) } - val hasUpdates: StateFlow = updatesRepository.hasUpdatesFlow() + val update: StateFlow = 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) + } }