Added "File history" feature

This commit is contained in:
Abdelilah El Aissaoui 2022-05-30 01:43:44 +02:00
parent 9c1133a292
commit 969233ec99
12 changed files with 433 additions and 29 deletions

View File

@ -32,6 +32,7 @@ fun CommitChanges(
onDiffSelected: (DiffEntry) -> Unit, onDiffSelected: (DiffEntry) -> Unit,
diffSelected: DiffEntryType?, diffSelected: DiffEntryType?,
onBlame: (String) -> Unit, onBlame: (String) -> Unit,
onHistory: (String) -> Unit,
) { ) {
LaunchedEffect(selectedItem) { LaunchedEffect(selectedItem) {
commitChangesViewModel.loadChanges(selectedItem.revCommit) commitChangesViewModel.loadChanges(selectedItem.revCommit)
@ -49,7 +50,8 @@ fun CommitChanges(
commit = commitChangesStatus.commit, commit = commitChangesStatus.commit,
changes = commitChangesStatus.changes, changes = commitChangesStatus.changes,
onDiffSelected = onDiffSelected, onDiffSelected = onDiffSelected,
onBlame = onBlame onBlame = onBlame,
onHistory = onHistory,
) )
} }
} }
@ -62,6 +64,7 @@ fun CommitChangesView(
onDiffSelected: (DiffEntry) -> Unit, onDiffSelected: (DiffEntry) -> Unit,
diffSelected: DiffEntryType?, diffSelected: DiffEntryType?,
onBlame: (String) -> Unit, onBlame: (String) -> Unit,
onHistory: (String) -> Unit,
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier
@ -119,6 +122,7 @@ fun CommitChangesView(
diffEntries = changes, diffEntries = changes,
onDiffSelected = onDiffSelected, onDiffSelected = onDiffSelected,
onBlame = onBlame, onBlame = onBlame,
onHistory = onHistory,
) )
} }
} }
@ -170,7 +174,6 @@ fun Author(commit: RevCommit) {
fontSize = 13.sp, fontSize = 13.sp,
tooltipTitle = authorIdent.`when`.toSystemDateTimeString() tooltipTitle = authorIdent.`when`.toSystemDateTimeString()
) )
} }
Text( Text(
@ -190,6 +193,7 @@ fun CommitLogChanges(
onDiffSelected: (DiffEntry) -> Unit, onDiffSelected: (DiffEntry) -> Unit,
diffSelected: DiffEntryType?, diffSelected: DiffEntryType?,
onBlame: (String) -> Unit, onBlame: (String) -> Unit,
onHistory: (String) -> Unit,
) { ) {
ScrollableLazyColumn( ScrollableLazyColumn(
modifier = Modifier modifier = Modifier
@ -200,7 +204,8 @@ fun CommitLogChanges(
items = { items = {
commitedChangesEntriesContextMenuItems( commitedChangesEntriesContextMenuItems(
diffEntry, diffEntry,
onBlame = { onBlame(diffEntry.filePath) } onBlame = { onBlame(diffEntry.filePath) },
onHistory = { onHistory(diffEntry.filePath) },
) )
} }
) { ) {
@ -219,7 +224,6 @@ fun CommitLogChanges(
) { ) {
Spacer(modifier = Modifier.weight(2f)) Spacer(modifier = Modifier.weight(2f))
Row { Row {
Icon( Icon(
modifier = Modifier modifier = Modifier

View File

@ -5,6 +5,7 @@ package app.ui
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.text.selection.DisableSelection import androidx.compose.foundation.text.selection.DisableSelection
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
@ -79,12 +80,23 @@ fun Diff(
) )
if (diffResult is DiffResult.Text) { if (diffResult is DiffResult.Text) {
TextDiff(diffEntryType, diffViewModel, diffResult) val scrollState by diffViewModel.lazyListState.collectAsState()
TextDiff(
diffEntryType = diffEntryType,
scrollState = scrollState,
diffResult = diffResult,
onUnstageHunk = { entry, hunk ->
diffViewModel.unstageHunk(entry, hunk)
},
) { entry, hunk ->
diffViewModel.stageHunk(entry, hunk)
}
} else if (diffResult is DiffResult.NonText) { } else if (diffResult is DiffResult.NonText) {
NonTextDiff(diffResult) NonTextDiff(diffResult)
} }
} }
ViewDiffResult.Loading -> { ViewDiffResult.Loading, ViewDiffResult.None -> {
LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
} }
} }
@ -186,25 +198,29 @@ fun BinaryDiff() {
} }
@Composable @Composable
fun TextDiff(diffEntryType: DiffEntryType, diffViewModel: DiffViewModel, diffResult: DiffResult.Text) { fun TextDiff(
diffEntryType: DiffEntryType,
scrollState: LazyListState,
diffResult: DiffResult.Text,
onUnstageHunk: (DiffEntry, Hunk) -> Unit,
onStageHunk: (DiffEntry, Hunk) -> Unit,
) {
val hunks = diffResult.hunks val hunks = diffResult.hunks
val scrollState by diffViewModel.lazyListState.collectAsState()
SelectionContainer { SelectionContainer {
ScrollableLazyColumn( ScrollableLazyColumn(
modifier = Modifier modifier = Modifier
.fillMaxSize(), .fillMaxSize(),
state = scrollState state = scrollState
) { ) {
for (hunk in hunks) { for (hunk in hunks) {
item { item {
DisableSelection { DisableSelection {
HunkHeader( HunkHeader(
hunk = hunk, hunk = hunk,
diffViewModel = diffViewModel,
diffEntryType = diffEntryType, diffEntryType = diffEntryType,
diffEntry =diffResult.diffEntry, onUnstageHunk = { onUnstageHunk(diffResult.diffEntry, hunk) },
onStageHunk = { onStageHunk(diffResult.diffEntry, hunk) },
) )
} }
} }
@ -227,8 +243,8 @@ fun TextDiff(diffEntryType: DiffEntryType, diffViewModel: DiffViewModel, diffRes
fun HunkHeader( fun HunkHeader(
hunk: Hunk, hunk: Hunk,
diffEntryType: DiffEntryType, diffEntryType: DiffEntryType,
diffViewModel: DiffViewModel, onUnstageHunk: () -> Unit,
diffEntry: DiffEntry, onStageHunk: () -> Unit,
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
@ -266,9 +282,9 @@ fun HunkHeader(
backgroundButton = color, backgroundButton = color,
onClick = { onClick = {
if (diffEntryType is DiffEntryType.StagedDiff) { if (diffEntryType is DiffEntryType.StagedDiff) {
diffViewModel.unstageHunk(diffEntry, hunk) onUnstageHunk()
} else { } else {
diffViewModel.stageHunk(diffEntry, hunk) onStageHunk()
} }
} }
) )
@ -346,7 +362,10 @@ fun DiffHeader(
} }
@Composable @Composable
fun DiffLine(highestLineNumberLength: Int, line: Line) { fun DiffLine(
highestLineNumberLength: Int,
line: Line,
) {
val backgroundColor = when (line.lineType) { val backgroundColor = when (line.lineType) {
LineType.ADDED -> { LineType.ADDED -> {
Color(0x77a9d49b) Color(0x77a9d49b)

View File

@ -0,0 +1,222 @@
@file:OptIn(ExperimentalComposeUiApi::class, ExperimentalSplitPaneApi::class)
package app.ui
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.input.pointer.PointerIconDefaults
import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import app.extensions.handMouseClickable
import app.extensions.toSmartSystemString
import app.extensions.toSystemDateTimeString
import app.git.diff.DiffResult
import app.theme.primaryTextColor
import app.theme.secondaryTextColor
import app.ui.components.AvatarImage
import app.ui.components.ScrollableLazyColumn
import app.ui.components.TooltipText
import app.viewmodels.HistoryState
import app.viewmodels.HistoryViewModel
import app.viewmodels.ViewDiffResult
import org.eclipse.jgit.revwalk.RevCommit
import org.jetbrains.compose.splitpane.ExperimentalSplitPaneApi
@Composable
fun FileHistory(
historyViewModel: HistoryViewModel,
onClose: () -> Unit
) {
val historyState by historyViewModel.historyState.collectAsState()
Column(
modifier = Modifier
.fillMaxSize()
) {
Header(filePath = historyState.filePath, onClose = onClose)
HistoryContent(
historyViewModel,
historyState,
onCommitSelected = { historyViewModel.selectCommit(it) }
)
}
}
@Composable
private fun Header(
filePath: String,
onClose: () -> Unit,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(start = 8.dp, end = 8.dp, top = 8.dp)
.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,
modifier = Modifier
.pointerHoverIcon(PointerIconDefaults.Hand)
) {
Image(
painter = painterResource("close.svg"),
contentDescription = "Close history",
colorFilter = ColorFilter.tint(MaterialTheme.colors.primaryTextColor),
)
}
}
}
@Composable
private fun HistoryContent(
historyViewModel: HistoryViewModel,
historyState: HistoryState,
onCommitSelected: (RevCommit) -> Unit,
) {
val textScrollState by historyViewModel.lazyListState.collectAsState()
val viewDiffResult by historyViewModel.viewDiffResult.collectAsState()
when (historyState) {
is HistoryState.Loaded -> HistoryContentLoaded(
historyState = historyState,
viewDiffResult = viewDiffResult,
scrollState = textScrollState,
onCommitSelected = onCommitSelected,
)
is HistoryState.Loading -> Box { }
}
}
@Composable
fun HistoryContentLoaded(
historyState: HistoryState.Loaded,
viewDiffResult: ViewDiffResult?,
scrollState: LazyListState,
onCommitSelected: (RevCommit) -> Unit,
) {
Row(
modifier = Modifier
.fillMaxSize()
) {
ScrollableLazyColumn(
modifier = Modifier
.fillMaxHeight()
.width(300.dp)
.background(MaterialTheme.colors.surface)
) {
items(historyState.commits) { commit ->
HistoryCommit(commit, onCommitSelected = { onCommitSelected(commit) })
}
}
Column(
modifier = Modifier
.fillMaxSize()
) {
if (
viewDiffResult != null &&
viewDiffResult is ViewDiffResult.Loaded
) {
val diffResult = viewDiffResult.diffResult
if (diffResult is DiffResult.Text) {
TextDiff(
diffEntryType = viewDiffResult.diffEntryType,
scrollState = scrollState,
diffResult = diffResult,
onUnstageHunk = { _, _ -> },
onStageHunk = { _, _ -> }
)
} else {
Box(
modifier = Modifier.fillMaxSize()
.background(MaterialTheme.colors.background)
)
}
} else {
Box(
modifier = Modifier.fillMaxSize()
.background(MaterialTheme.colors.background)
)
}
}
}
}
@Composable
fun HistoryCommit(commit: RevCommit, onCommitSelected: () -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.handMouseClickable { onCommitSelected() }
.padding(vertical = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
AvatarImage(
modifier = Modifier
.padding(horizontal = 16.dp)
.size(40.dp),
personIdent = commit.authorIdent,
)
Column {
Text(
text = commit.shortMessage,
maxLines = 1,
fontSize = 14.sp,
color = MaterialTheme.colors.primaryTextColor,
)
Row {
Text(
text = commit.name.take(7),
maxLines = 1,
fontSize = 12.sp,
color = MaterialTheme.colors.secondaryTextColor,
)
Spacer(modifier = Modifier.weight(1f))
val date = remember(commit.authorIdent) {
commit.authorIdent.`when`.toSmartSystemString()
}
TooltipText(
text = date,
color = MaterialTheme.colors.secondaryTextColor,
maxLines = 1,
modifier = Modifier.padding(horizontal = 16.dp),
fontSize = 12.sp,
tooltipTitle = date
)
}
}
}
}

View File

@ -1,3 +1,5 @@
@file:OptIn(ExperimentalSplitPaneApi::class)
package app.ui package app.ui
import androidx.compose.foundation.border import androidx.compose.foundation.border
@ -31,6 +33,7 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
val diffSelected by tabViewModel.diffSelected.collectAsState() val diffSelected by tabViewModel.diffSelected.collectAsState()
val selectedItem by tabViewModel.selectedItem.collectAsState() val selectedItem by tabViewModel.selectedItem.collectAsState()
val blameState by tabViewModel.blameState.collectAsState() val blameState by tabViewModel.blameState.collectAsState()
val showHistory by tabViewModel.showHistory.collectAsState()
var showNewBranchDialog by remember { mutableStateOf(false) } var showNewBranchDialog by remember { mutableStateOf(false) }
@ -65,13 +68,12 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
onCreateBranch = { showNewBranchDialog = true } onCreateBranch = { showNewBranchDialog = true }
) )
RepoContent(tabViewModel, diffSelected, selectedItem, repositoryState, blameState) RepoContent(tabViewModel, diffSelected, selectedItem, repositoryState, blameState, showHistory)
} }
} }
} }
@OptIn(ExperimentalSplitPaneApi::class)
@Composable @Composable
fun RepoContent( fun RepoContent(
tabViewModel: TabViewModel, tabViewModel: TabViewModel,
@ -79,6 +81,39 @@ fun RepoContent(
selectedItem: SelectedItem, selectedItem: SelectedItem,
repositoryState: RepositoryState, repositoryState: RepositoryState,
blameState: BlameState, blameState: BlameState,
showHistory: Boolean,
) {
if(showHistory) {
val historyViewModel = tabViewModel.historyViewModel
if(historyViewModel != null) {
FileHistory(
historyViewModel = historyViewModel,
onClose = {
tabViewModel.closeHistory()
}
)
}
} else {
MainContentView(
tabViewModel,
diffSelected,
selectedItem,
repositoryState,
blameState,
)
}
}
@Composable
fun MainContentView(
tabViewModel: TabViewModel,
diffSelected: DiffEntryType?,
selectedItem: SelectedItem,
repositoryState: RepositoryState,
blameState: BlameState
) { ) {
Row { Row {
HorizontalSplitPane { HorizontalSplitPane {
@ -187,7 +222,8 @@ fun RepoContent(
else else
tabViewModel.newDiffSelected = DiffEntryType.UnsafeUnstagedDiff(diffEntry) tabViewModel.newDiffSelected = DiffEntryType.UnsafeUnstagedDiff(diffEntry)
}, },
onBlameFile = { tabViewModel.blameFile(it) } onBlameFile = { tabViewModel.blameFile(it) },
onHistoryFile = { tabViewModel.fileHistory(it) }
) )
} else if (safeSelectedItem is SelectedItem.CommitBasedItem) { } else if (safeSelectedItem is SelectedItem.CommitBasedItem) {
CommitChanges( CommitChanges(
@ -198,7 +234,8 @@ fun RepoContent(
tabViewModel.minimizeBlame() tabViewModel.minimizeBlame()
tabViewModel.newDiffSelected = DiffEntryType.CommitDiff(diffEntry) tabViewModel.newDiffSelected = DiffEntryType.CommitDiff(diffEntry)
}, },
onBlame = { tabViewModel.blameFile(it) } onBlame = { tabViewModel.blameFile(it) },
onHistory = { tabViewModel.fileHistory(it) },
) )
} }
} }

View File

@ -50,6 +50,7 @@ fun UncommitedChanges(
onStagedDiffEntrySelected: (StatusEntry?) -> Unit, onStagedDiffEntrySelected: (StatusEntry?) -> Unit,
onUnstagedDiffEntrySelected: (StatusEntry) -> Unit, onUnstagedDiffEntrySelected: (StatusEntry) -> Unit,
onBlameFile: (String) -> Unit, onBlameFile: (String) -> Unit,
onHistoryFile: (String) -> Unit,
) { ) {
val stageStatusState = statusViewModel.stageStatus.collectAsState() val stageStatusState = statusViewModel.stageStatus.collectAsState()
var commitMessage by remember { mutableStateOf(statusViewModel.savedCommitMessage) } var commitMessage by remember { mutableStateOf(statusViewModel.savedCommitMessage) }
@ -106,6 +107,7 @@ fun UncommitedChanges(
entryType = EntryType.STAGED, entryType = EntryType.STAGED,
onBlame = { onBlameFile(statusEntry.filePath) }, onBlame = { onBlameFile(statusEntry.filePath) },
onReset = { statusViewModel.resetStaged(statusEntry) }, onReset = { statusViewModel.resetStaged(statusEntry) },
onHistory = { onHistoryFile(statusEntry.filePath) },
) )
}, },
onAllAction = { onAllAction = {
@ -132,10 +134,11 @@ fun UncommitedChanges(
statusEntry = statusEntry, statusEntry = statusEntry,
entryType = EntryType.UNSTAGED, entryType = EntryType.UNSTAGED,
onBlame = { onBlameFile(statusEntry.filePath) }, onBlame = { onBlameFile(statusEntry.filePath) },
onHistory = { onHistoryFile(statusEntry.filePath) },
onReset = { statusViewModel.resetUnstaged(statusEntry) }, onReset = { statusViewModel.resetUnstaged(statusEntry) },
onDelete = { onDelete = {
statusViewModel.deleteFile(statusEntry) statusViewModel.deleteFile(statusEntry)
} },
) )
}, },
onAllAction = { onAllAction = {

View File

@ -9,6 +9,7 @@ import org.eclipse.jgit.diff.DiffEntry
fun commitedChangesEntriesContextMenuItems( fun commitedChangesEntriesContextMenuItems(
diffEntry: DiffEntry, diffEntry: DiffEntry,
onBlame: () -> Unit, onBlame: () -> Unit,
onHistory: () -> Unit,
): List<ContextMenuItem> { ): List<ContextMenuItem> {
return mutableListOf<ContextMenuItem>().apply { return mutableListOf<ContextMenuItem>().apply {
if (diffEntry.changeType != DiffEntry.ChangeType.ADD || if (diffEntry.changeType != DiffEntry.ChangeType.ADD ||
@ -19,6 +20,12 @@ fun commitedChangesEntriesContextMenuItems(
onClick = onBlame, onClick = onBlame,
) )
) )
add(
ContextMenuItem(
label = "File history",
onClick = onHistory,
)
)
} }
} }
} }

View File

@ -12,6 +12,7 @@ fun statusEntriesContextMenuItems(
onReset: () -> Unit, onReset: () -> Unit,
onDelete: () -> Unit = {}, onDelete: () -> Unit = {},
onBlame: () -> Unit, onBlame: () -> Unit,
onHistory: () -> Unit,
): List<ContextMenuItem> { ): List<ContextMenuItem> {
return mutableListOf<ContextMenuItem>().apply { return mutableListOf<ContextMenuItem>().apply {
if (statusEntry.statusType != StatusType.ADDED) { if (statusEntry.statusType != StatusType.ADDED) {
@ -29,6 +30,13 @@ fun statusEntriesContextMenuItems(
onClick = onBlame, onClick = onBlame,
) )
) )
add(
ContextMenuItem(
label = "File history",
onClick = onHistory,
)
)
} }
} }

View File

@ -779,7 +779,7 @@ fun CommitMessage(
) )
Text( Text(
text = commit.committerIdent.`when`.toSmartSystemString(), text = commit.authorIdent.`when`.toSmartSystemString(),
modifier = Modifier.padding(horizontal = 16.dp), modifier = Modifier.padding(horizontal = 16.dp),
fontSize = 12.sp, fontSize = 12.sp,
color = MaterialTheme.colors.secondaryTextColor, color = MaterialTheme.colors.secondaryTextColor,

View File

@ -3,7 +3,6 @@ package app.viewmodels
import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyListState
import app.exceptions.MissingDiffEntryException import app.exceptions.MissingDiffEntryException
import app.git.* import app.git.*
import app.git.diff.DiffResult
import app.git.diff.Hunk import app.git.diff.Hunk
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -87,8 +86,3 @@ class DiffViewModel @Inject constructor(
} }
sealed interface ViewDiffResult {
object Loading: ViewDiffResult
object DiffNotFound: ViewDiffResult
data class Loaded(val diffEntryType: DiffEntryType, val diffResult: DiffResult): ViewDiffResult
}

View File

@ -0,0 +1,82 @@
package app.viewmodels
import androidx.compose.foundation.lazy.LazyListState
import app.exceptions.MissingDiffEntryException
import app.extensions.filePath
import app.git.DiffEntryType
import app.git.DiffManager
import app.git.RefreshType
import app.git.TabState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.eclipse.jgit.revwalk.RevCommit
import javax.inject.Inject
class HistoryViewModel @Inject constructor(
private val tabState: TabState,
private val diffManager: DiffManager,
) {
private val _historyState = MutableStateFlow<HistoryState>(HistoryState.Loading(""))
val historyState: StateFlow<HistoryState> = _historyState
private val _viewDiffResult = MutableStateFlow<ViewDiffResult>(ViewDiffResult.None)
val viewDiffResult: StateFlow<ViewDiffResult> = _viewDiffResult
var filePath: String = ""
val lazyListState = MutableStateFlow(
LazyListState(
0,
0
)
)
fun fileHistory(filePath: String) = tabState.safeProcessing(
refreshType = RefreshType.NONE,
) { git ->
this.filePath = filePath
_historyState.value = HistoryState.Loading(filePath)
val log = git.log()
.addPath(filePath)
.call()
.toList()
_historyState.value = HistoryState.Loaded(filePath, log)
}
fun selectCommit(commit: RevCommit) = tabState.runOperation(
refreshType = RefreshType.NONE,
showError = true,
) { git ->
try {
val diffEntries = diffManager.commitDiffEntries(git, commit)
val diffEntry = diffEntries.firstOrNull {entry ->
entry.filePath == this.filePath
}
if(diffEntry == null) {
_viewDiffResult.value = ViewDiffResult.DiffNotFound
return@runOperation
}
val diffEntryType = DiffEntryType.CommitDiff(diffEntry)
val diffFormat = diffManager.diffFormat(git, diffEntryType)
_viewDiffResult.value = ViewDiffResult.Loaded(diffEntryType, diffFormat)
} catch (ex: Exception) {
if(ex is MissingDiffEntryException) {
tabState.refreshData(refreshType = RefreshType.UNCOMMITED_CHANGES)
_viewDiffResult.value = ViewDiffResult.DiffNotFound
} else
ex.printStackTrace()
}
}
}
sealed class HistoryState(val filePath: String) {
class Loading(filePath: String) : HistoryState(filePath)
class Loaded(filePath: String, val commits: List<RevCommit>) : HistoryState(filePath)
}

View File

@ -41,6 +41,7 @@ class TabViewModel @Inject constructor(
val commitChangesViewModel: CommitChangesViewModel, val commitChangesViewModel: CommitChangesViewModel,
val cloneViewModel: CloneViewModel, val cloneViewModel: CloneViewModel,
private val rebaseInteractiveViewModelProvider: Provider<RebaseInteractiveViewModel>, private val rebaseInteractiveViewModelProvider: Provider<RebaseInteractiveViewModel>,
private val historyViewModelProvider: Provider<HistoryViewModel>,
private val repositoryManager: RepositoryManager, private val repositoryManager: RepositoryManager,
private val tabState: TabState, private val tabState: TabState,
val appStateManager: AppStateManager, val appStateManager: AppStateManager,
@ -79,6 +80,12 @@ class TabViewModel @Inject constructor(
private val _blameState = MutableStateFlow<BlameState>(BlameState.None) private val _blameState = MutableStateFlow<BlameState>(BlameState.None)
val blameState: StateFlow<BlameState> = _blameState val blameState: StateFlow<BlameState> = _blameState
private val _showHistory = MutableStateFlow(false)
val showHistory: StateFlow<Boolean> = _showHistory
var historyViewModel: HistoryViewModel? = null
private set
val showError = MutableStateFlow(false) val showError = MutableStateFlow(false)
init { init {
@ -361,6 +368,17 @@ class TabViewModel @Inject constructor(
fun selectCommit(commit: RevCommit) { fun selectCommit(commit: RevCommit) {
tabState.newSelectedItem(SelectedItem.Commit(commit)) tabState.newSelectedItem(SelectedItem.Commit(commit))
} }
fun fileHistory(filePath: String) {
historyViewModel = historyViewModelProvider.get()
historyViewModel?.fileHistory(filePath)
_showHistory.value = true
}
fun closeHistory() {
_showHistory.value = false
historyViewModel = null
}
} }
@ -370,7 +388,6 @@ sealed class RepositorySelectionStatus {
data class Open(val repository: Repository) : RepositorySelectionStatus() data class Open(val repository: Repository) : RepositorySelectionStatus()
} }
sealed interface BlameState { sealed interface BlameState {
data class Loading(val filePath: String) : BlameState data class Loading(val filePath: String) : BlameState

View File

@ -0,0 +1,11 @@
package app.viewmodels
import app.git.DiffEntryType
import app.git.diff.DiffResult
sealed interface ViewDiffResult {
object None: ViewDiffResult
object Loading: ViewDiffResult
object DiffNotFound: ViewDiffResult
data class Loaded(val diffEntryType: DiffEntryType, val diffResult: DiffResult): ViewDiffResult
}