Added basic version of blame
This commit is contained in:
parent
543545d93d
commit
8e366741ac
@ -33,7 +33,7 @@ class TabState @Inject constructor(
|
||||
return git
|
||||
}
|
||||
|
||||
val mutex = Mutex()
|
||||
private val mutex = Mutex()
|
||||
|
||||
private val _refreshData = MutableSharedFlow<RefreshType>()
|
||||
val refreshData: Flow<RefreshType> = _refreshData
|
||||
|
106
src/main/kotlin/app/ui/Blame.kt
Normal file
106
src/main/kotlin/app/ui/Blame.kt
Normal file
@ -0,0 +1,106 @@
|
||||
@file:Suppress("UNUSED_PARAMETER")
|
||||
|
||||
package app.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.IconButton
|
||||
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.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import app.extensions.lineAt
|
||||
import app.theme.primaryTextColor
|
||||
import app.ui.components.ScrollableLazyColumn
|
||||
import org.eclipse.jgit.blame.BlameResult
|
||||
|
||||
@Composable
|
||||
fun Blame(
|
||||
filePath: String,
|
||||
blameResult: BlameResult,
|
||||
onClose: () -> Unit,
|
||||
) {
|
||||
Column {
|
||||
Header(filePath, onClose = onClose)
|
||||
|
||||
ScrollableLazyColumn(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
val contents = blameResult.resultContents
|
||||
items(contents.size()) { index ->
|
||||
val line = contents.lineAt(index)
|
||||
val author = blameResult.getSourceAuthor(index)
|
||||
val commit = blameResult.getSourceCommit(index)
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().background(MaterialTheme.colors.background)
|
||||
.height(IntrinsicSize.Min),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.width(200.dp).fillMaxHeight().background(MaterialTheme.colors.surface),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Text(
|
||||
text = author?.name.orEmpty(),
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
maxLines = 1,
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
fontSize = 12.sp,
|
||||
)
|
||||
Text(
|
||||
text = commit.shortMessage,
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
maxLines = 1,
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
fontSize = 10.sp,
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = line,
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp),
|
||||
fontFamily = FontFamily.Monospace,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Header(
|
||||
filePath: String,
|
||||
onClose: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().background(MaterialTheme.colors.surface),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = filePath,
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
fontSize = 13.sp,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
IconButton(
|
||||
onClick = onClose
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource("close.svg"),
|
||||
contentDescription = "Close diff",
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colors.primaryTextColor),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,10 @@
|
||||
package app.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
@ -24,6 +21,7 @@ import app.theme.*
|
||||
import app.ui.components.AvatarImage
|
||||
import app.ui.components.ScrollableLazyColumn
|
||||
import app.ui.components.TooltipText
|
||||
import app.ui.context_menu.commitedChangesEntriesContextMenuItems
|
||||
import app.viewmodels.CommitChangesStatus
|
||||
import app.viewmodels.CommitChangesViewModel
|
||||
import org.eclipse.jgit.diff.DiffEntry
|
||||
@ -34,7 +32,8 @@ fun CommitChanges(
|
||||
commitChangesViewModel: CommitChangesViewModel,
|
||||
selectedItem: SelectedItem.CommitBasedItem,
|
||||
onDiffSelected: (DiffEntry) -> Unit,
|
||||
diffSelected: DiffEntryType?
|
||||
diffSelected: DiffEntryType?,
|
||||
onBlame: (String) -> Unit,
|
||||
) {
|
||||
LaunchedEffect(selectedItem) {
|
||||
commitChangesViewModel.loadChanges(selectedItem.revCommit)
|
||||
@ -52,6 +51,7 @@ fun CommitChanges(
|
||||
commit = commitChangesStatus.commit,
|
||||
changes = commitChangesStatus.changes,
|
||||
onDiffSelected = onDiffSelected,
|
||||
onBlame = onBlame
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -62,7 +62,8 @@ fun CommitChangesView(
|
||||
commit: RevCommit,
|
||||
changes: List<DiffEntry>,
|
||||
onDiffSelected: (DiffEntry) -> Unit,
|
||||
diffSelected: DiffEntryType?
|
||||
diffSelected: DiffEntryType?,
|
||||
onBlame: (String) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@ -118,7 +119,8 @@ fun CommitChangesView(
|
||||
CommitLogChanges(
|
||||
diffSelected = diffSelected,
|
||||
diffEntries = changes,
|
||||
onDiffSelected = onDiffSelected
|
||||
onDiffSelected = onDiffSelected,
|
||||
onBlame = onBlame,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -183,67 +185,78 @@ fun Author(commit: RevCommit) {
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun CommitLogChanges(
|
||||
diffEntries: List<DiffEntry>,
|
||||
onDiffSelected: (DiffEntry) -> Unit,
|
||||
diffSelected: DiffEntryType?
|
||||
diffSelected: DiffEntryType?,
|
||||
onBlame: (String) -> Unit,
|
||||
) {
|
||||
ScrollableLazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
) {
|
||||
items(items = diffEntries) { diffEntry ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.height(40.dp)
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
onDiffSelected(diffEntry)
|
||||
}
|
||||
.backgroundIf(
|
||||
condition = diffSelected is DiffEntryType.CommitDiff && diffSelected.diffEntry == diffEntry,
|
||||
color = MaterialTheme.colors.backgroundSelected,
|
||||
),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(2f))
|
||||
|
||||
|
||||
Row {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
.size(16.dp),
|
||||
imageVector = diffEntry.icon,
|
||||
contentDescription = null,
|
||||
tint = diffEntry.iconColor,
|
||||
ContextMenuArea(
|
||||
items = {
|
||||
commitedChangesEntriesContextMenuItems(
|
||||
diffEntry,
|
||||
onBlame = { onBlame(diffEntry.filePath) }
|
||||
)
|
||||
}
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.height(40.dp)
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
onDiffSelected(diffEntry)
|
||||
}
|
||||
.backgroundIf(
|
||||
condition = diffSelected is DiffEntryType.CommitDiff && diffSelected.diffEntry == diffEntry,
|
||||
color = MaterialTheme.colors.backgroundSelected,
|
||||
),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(2f))
|
||||
|
||||
if(diffEntry.parentDirectoryPath.isNotEmpty()) {
|
||||
|
||||
Row {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
.size(16.dp),
|
||||
imageVector = diffEntry.icon,
|
||||
contentDescription = null,
|
||||
tint = diffEntry.iconColor,
|
||||
)
|
||||
|
||||
if (diffEntry.parentDirectoryPath.isNotEmpty()) {
|
||||
Text(
|
||||
text = diffEntry.parentDirectoryPath,
|
||||
modifier = Modifier.weight(1f, fill = false),
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
fontSize = 13.sp,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = MaterialTheme.colors.secondaryTextColor,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = diffEntry.parentDirectoryPath,
|
||||
text = diffEntry.fileName,
|
||||
modifier = Modifier.weight(1f, fill = false),
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
fontSize = 13.sp,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = MaterialTheme.colors.secondaryTextColor,
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = diffEntry.fileName,
|
||||
modifier = Modifier.weight(1f, fill = false),
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
fontSize = 13.sp,
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(2f))
|
||||
|
||||
Divider()
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(2f))
|
||||
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import app.theme.primaryTextColor
|
||||
import app.ui.dialogs.NewBranchDialog
|
||||
import app.ui.dialogs.RebaseInteractive
|
||||
import app.ui.log.Log
|
||||
import app.viewmodels.BlameState
|
||||
import app.viewmodels.TabViewModel
|
||||
import openRepositoryDialog
|
||||
import org.eclipse.jgit.lib.RepositoryState
|
||||
@ -29,6 +30,7 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
|
||||
val repositoryState by tabViewModel.repositoryState.collectAsState()
|
||||
val diffSelected by tabViewModel.diffSelected.collectAsState()
|
||||
val selectedItem by tabViewModel.selectedItem.collectAsState()
|
||||
val blameState by tabViewModel.blameState.collectAsState()
|
||||
|
||||
var showNewBranchDialog by remember { mutableStateOf(false) }
|
||||
|
||||
@ -63,7 +65,7 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
|
||||
onCreateBranch = { showNewBranchDialog = true }
|
||||
)
|
||||
|
||||
RepoContent(tabViewModel, diffSelected, selectedItem, repositoryState)
|
||||
RepoContent(tabViewModel, diffSelected, selectedItem, repositoryState, blameState)
|
||||
}
|
||||
|
||||
}
|
||||
@ -75,7 +77,8 @@ fun RepoContent(
|
||||
tabViewModel: TabViewModel,
|
||||
diffSelected: DiffEntryType?,
|
||||
selectedItem: SelectedItem,
|
||||
repositoryState: RepositoryState
|
||||
repositoryState: RepositoryState,
|
||||
blameState: BlameState,
|
||||
) {
|
||||
Row {
|
||||
HorizontalSplitPane {
|
||||
@ -115,18 +118,26 @@ fun RepoContent(
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
)
|
||||
) {
|
||||
when (diffSelected) {
|
||||
null -> {
|
||||
Log(
|
||||
logViewModel = tabViewModel.logViewModel,
|
||||
selectedItem = selectedItem,
|
||||
repositoryState = repositoryState,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
Diff(
|
||||
diffViewModel = tabViewModel.diffViewModel,
|
||||
onCloseDiffView = { tabViewModel.newDiffSelected = null })
|
||||
if (blameState is BlameState.Loaded) {
|
||||
Blame(
|
||||
filePath = blameState.filePath,
|
||||
blameResult = blameState.blameResult,
|
||||
onClose = { tabViewModel.resetBlameState() }
|
||||
)
|
||||
} else {
|
||||
when (diffSelected) {
|
||||
null -> {
|
||||
Log(
|
||||
logViewModel = tabViewModel.logViewModel,
|
||||
selectedItem = selectedItem,
|
||||
repositoryState = repositoryState,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
Diff(
|
||||
diffViewModel = tabViewModel.diffViewModel,
|
||||
onCloseDiffView = { tabViewModel.newDiffSelected = null })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -144,6 +155,11 @@ fun RepoContent(
|
||||
selectedEntryType = diffSelected,
|
||||
repositoryState = repositoryState,
|
||||
onStagedDiffEntrySelected = { diffEntry ->
|
||||
// TODO: Instead of resetting the state, create a new one where the blame
|
||||
// is "on hold". In this state we can show a bar at the bottom so the user
|
||||
// can click on it and return to the blame
|
||||
tabViewModel.resetBlameState()
|
||||
|
||||
tabViewModel.newDiffSelected = if (diffEntry != null) {
|
||||
if (repositoryState == RepositoryState.SAFE)
|
||||
DiffEntryType.SafeStagedDiff(diffEntry)
|
||||
@ -154,11 +170,14 @@ fun RepoContent(
|
||||
}
|
||||
},
|
||||
onUnstagedDiffEntrySelected = { diffEntry ->
|
||||
tabViewModel.resetBlameState()
|
||||
|
||||
if (repositoryState == RepositoryState.SAFE)
|
||||
tabViewModel.newDiffSelected = DiffEntryType.SafeUnstagedDiff(diffEntry)
|
||||
else
|
||||
tabViewModel.newDiffSelected = DiffEntryType.UnsafeUnstagedDiff(diffEntry)
|
||||
}
|
||||
},
|
||||
onBlameFile = { tabViewModel.blameFile(it) }
|
||||
)
|
||||
} else if (safeSelectedItem is SelectedItem.CommitBasedItem) {
|
||||
CommitChanges(
|
||||
@ -166,8 +185,10 @@ fun RepoContent(
|
||||
selectedItem = safeSelectedItem,
|
||||
diffSelected = diffSelected,
|
||||
onDiffSelected = { diffEntry ->
|
||||
tabViewModel.resetBlameState()
|
||||
tabViewModel.newDiffSelected = DiffEntryType.CommitDiff(diffEntry)
|
||||
}
|
||||
},
|
||||
onBlame = { tabViewModel.blameFile(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -40,14 +40,10 @@ import app.git.StatusEntry
|
||||
import app.theme.*
|
||||
import app.ui.components.ScrollableLazyColumn
|
||||
import app.ui.components.SecondaryButton
|
||||
import app.ui.context_menu.DropDownContent
|
||||
import app.ui.context_menu.DropDownContentData
|
||||
import app.ui.context_menu.stagedEntriesContextMenuItems
|
||||
import app.ui.context_menu.unstagedEntriesContextMenuItems
|
||||
import app.ui.context_menu.*
|
||||
import app.viewmodels.StageStatus
|
||||
import app.viewmodels.StatusViewModel
|
||||
import org.eclipse.jgit.lib.RepositoryState
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Composable
|
||||
fun UncommitedChanges(
|
||||
@ -56,6 +52,7 @@ fun UncommitedChanges(
|
||||
repositoryState: RepositoryState,
|
||||
onStagedDiffEntrySelected: (StatusEntry?) -> Unit,
|
||||
onUnstagedDiffEntrySelected: (StatusEntry) -> Unit,
|
||||
onBlameFile: (String) -> Unit,
|
||||
) {
|
||||
val stageStatusState = statusViewModel.stageStatus.collectAsState()
|
||||
var commitMessage by remember { mutableStateOf(statusViewModel.savedCommitMessage) }
|
||||
@ -106,12 +103,12 @@ fun UncommitedChanges(
|
||||
onDiffEntryOptionSelected = {
|
||||
statusViewModel.unstage(it)
|
||||
},
|
||||
onGenerateContextMenu = { diffEntry ->
|
||||
stagedEntriesContextMenuItems(
|
||||
diffEntry = diffEntry,
|
||||
onReset = {
|
||||
statusViewModel.resetStaged(diffEntry)
|
||||
},
|
||||
onGenerateContextMenu = { statusEntry ->
|
||||
statusEntriesContextMenuItems(
|
||||
statusEntry = statusEntry,
|
||||
entryType = EntryType.STAGED,
|
||||
onBlame = { onBlameFile(statusEntry.filePath) },
|
||||
onReset = { statusViewModel.resetStaged(statusEntry) },
|
||||
)
|
||||
},
|
||||
onAllAction = {
|
||||
@ -134,11 +131,11 @@ fun UncommitedChanges(
|
||||
statusViewModel.stage(it)
|
||||
},
|
||||
onGenerateContextMenu = { statusEntry ->
|
||||
unstagedEntriesContextMenuItems(
|
||||
statusEntriesContextMenuItems(
|
||||
statusEntry = statusEntry,
|
||||
onReset = {
|
||||
statusViewModel.resetUnstaged(statusEntry)
|
||||
},
|
||||
entryType = EntryType.UNSTAGED,
|
||||
onBlame = { onBlameFile(statusEntry.filePath) },
|
||||
onReset = { statusViewModel.resetUnstaged(statusEntry) },
|
||||
onDelete = {
|
||||
statusViewModel.deleteFile(statusEntry)
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
package app.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import app.git.StatusType
|
||||
import org.eclipse.jgit.diff.DiffEntry
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun commitedChangesEntriesContextMenuItems(
|
||||
diffEntry: DiffEntry,
|
||||
onBlame: () -> Unit,
|
||||
): List<ContextMenuItem> {
|
||||
return mutableListOf<ContextMenuItem>().apply {
|
||||
if (diffEntry.changeType != DiffEntry.ChangeType.ADD ||
|
||||
diffEntry.changeType != DiffEntry.ChangeType.DELETE) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
label = "Blame file",
|
||||
onClick = onBlame,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -4,13 +4,14 @@ import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import app.git.StatusEntry
|
||||
import app.git.StatusType
|
||||
import org.eclipse.jgit.diff.DiffEntry
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun unstagedEntriesContextMenuItems(
|
||||
fun statusEntriesContextMenuItems(
|
||||
statusEntry: StatusEntry,
|
||||
entryType: EntryType,
|
||||
onReset: () -> Unit,
|
||||
onDelete: () -> Unit,
|
||||
onDelete: () -> Unit = {},
|
||||
onBlame: () -> Unit,
|
||||
): List<ContextMenuItem> {
|
||||
return mutableListOf<ContextMenuItem>().apply {
|
||||
if (statusEntry.statusType != StatusType.ADDED) {
|
||||
@ -20,9 +21,21 @@ fun unstagedEntriesContextMenuItems(
|
||||
onClick = onReset,
|
||||
)
|
||||
)
|
||||
|
||||
if (statusEntry.statusType != StatusType.REMOVED) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
label = "Blame file",
|
||||
onClick = onBlame,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (statusEntry.statusType != StatusType.REMOVED) {
|
||||
if (
|
||||
entryType == EntryType.UNSTAGED &&
|
||||
statusEntry.statusType != StatusType.REMOVED
|
||||
) {
|
||||
add(
|
||||
ContextMenuItem(
|
||||
label = "Delete file",
|
||||
@ -32,3 +45,9 @@ fun unstagedEntriesContextMenuItems(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum class EntryType {
|
||||
STAGED,
|
||||
UNSTAGED,
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package app.viewmodels
|
||||
|
||||
import app.AppPreferences
|
||||
import app.AppStateManager
|
||||
import app.ErrorsManager
|
||||
import app.credentials.CredentialsState
|
||||
@ -15,6 +14,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.blame.BlameResult
|
||||
import org.eclipse.jgit.lib.Repository
|
||||
import org.eclipse.jgit.lib.RepositoryState
|
||||
import java.io.File
|
||||
@ -75,6 +75,9 @@ class TabViewModel @Inject constructor(
|
||||
private val _repositoryState = MutableStateFlow(RepositoryState.SAFE)
|
||||
val repositoryState: StateFlow<RepositoryState> = _repositoryState
|
||||
|
||||
private val _blameState = MutableStateFlow<BlameState>(BlameState.None)
|
||||
val blameState: StateFlow<BlameState> = _blameState
|
||||
|
||||
val showError = MutableStateFlow(false)
|
||||
|
||||
init {
|
||||
@ -315,6 +318,28 @@ class TabViewModel @Inject constructor(
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun blameFile(filePath: String) = tabState.safeProcessing(
|
||||
refreshType = RefreshType.NONE,
|
||||
) { git ->
|
||||
_blameState.value = BlameState.Loading(filePath)
|
||||
try {
|
||||
val result = git.blame()
|
||||
.setFilePath(filePath)
|
||||
.setFollowFileRenames(true)
|
||||
.call()
|
||||
|
||||
_blameState.value = BlameState.Loaded(filePath, result)
|
||||
} catch (ex: Exception) {
|
||||
resetBlameState()
|
||||
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
||||
fun resetBlameState() {
|
||||
_blameState.value = BlameState.None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -323,3 +348,10 @@ sealed class RepositorySelectionStatus {
|
||||
data class Opening(val path: String) : RepositorySelectionStatus()
|
||||
data class Open(val repository: Repository) : RepositorySelectionStatus()
|
||||
}
|
||||
|
||||
|
||||
sealed interface BlameState {
|
||||
data class Loading(val filePath: String) : BlameState
|
||||
data class Loaded(val filePath: String, val blameResult: BlameResult) : BlameState
|
||||
object None : BlameState
|
||||
}
|
Loading…
Reference in New Issue
Block a user