Added log loading screen
This commit is contained in:
parent
594e41eda2
commit
0c3ced89b4
@ -26,9 +26,7 @@ import androidx.compose.ui.geometry.Offset
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.drawscope.clipRect
|
import androidx.compose.ui.graphics.drawscope.clipRect
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.input.key.KeyEventType
|
|
||||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||||
import androidx.compose.ui.input.key.type
|
|
||||||
import androidx.compose.ui.input.pointer.PointerIcon
|
import androidx.compose.ui.input.pointer.PointerIcon
|
||||||
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
@ -94,184 +92,211 @@ fun Log(
|
|||||||
selectedItem: SelectedItem,
|
selectedItem: SelectedItem,
|
||||||
repositoryState: RepositoryState,
|
repositoryState: RepositoryState,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val logStatusState = logViewModel.logStatus.collectAsState()
|
val logStatusState = logViewModel.logStatus.collectAsState()
|
||||||
val logStatus = logStatusState.value
|
val logStatus = logStatusState.value
|
||||||
val showLogDialog by logViewModel.logDialog.collectAsState()
|
val showLogDialog by logViewModel.logDialog.collectAsState()
|
||||||
|
|
||||||
|
when (logStatus) {
|
||||||
|
is LogStatus.Loaded -> LogLoaded(logViewModel, logStatus, showLogDialog, selectedItem, repositoryState)
|
||||||
|
LogStatus.Loading -> LogLoading()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun LogLoading() {
|
||||||
|
Column (
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(MaterialTheme.colors.background),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
Text(
|
||||||
|
text = "Loading commits history...",
|
||||||
|
style = MaterialTheme.typography.h4,
|
||||||
|
modifier = Modifier.padding(top = 8.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun LogLoaded(
|
||||||
|
logViewModel: LogViewModel,
|
||||||
|
logStatus: LogStatus.Loaded,
|
||||||
|
showLogDialog: LogDialog,
|
||||||
|
selectedItem: SelectedItem,
|
||||||
|
repositoryState: RepositoryState
|
||||||
|
) {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val hasUncommitedChanges = logStatus.hasUncommittedChanges
|
||||||
|
val commitList = logStatus.plotCommitList
|
||||||
|
val verticalScrollState by logViewModel.verticalListState.collectAsState()
|
||||||
|
val horizontalScrollState by logViewModel.horizontalListState.collectAsState()
|
||||||
|
val searchFilter = logViewModel.logSearchFilterResults.collectAsState()
|
||||||
|
val searchFilterValue = searchFilter.value
|
||||||
|
|
||||||
val selectedCommit = if (selectedItem is SelectedItem.CommitBasedItem) {
|
val selectedCommit = if (selectedItem is SelectedItem.CommitBasedItem) {
|
||||||
selectedItem.revCommit
|
selectedItem.revCommit
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logStatus is LogStatus.Loaded) {
|
LaunchedEffect(verticalScrollState, commitList) {
|
||||||
val hasUncommitedChanges = logStatus.hasUncommitedChanges
|
launch {
|
||||||
val commitList = logStatus.plotCommitList
|
logViewModel.focusCommit.collect { commit ->
|
||||||
val verticalScrollState by logViewModel.verticalListState.collectAsState()
|
scrollToCommit(verticalScrollState, commitList, commit)
|
||||||
val horizontalScrollState by logViewModel.horizontalListState.collectAsState()
|
|
||||||
val searchFilter = logViewModel.logSearchFilterResults.collectAsState()
|
|
||||||
val searchFilterValue = searchFilter.value
|
|
||||||
// With this method, whenever the scroll changes, the log is recomposed and the graph list is updated with
|
|
||||||
// the proper scroll position
|
|
||||||
verticalScrollState.observeScrollChanges()
|
|
||||||
|
|
||||||
LaunchedEffect(verticalScrollState, commitList) {
|
|
||||||
launch {
|
|
||||||
logViewModel.focusCommit.collect { commit ->
|
|
||||||
scrollToCommit(verticalScrollState, commitList, commit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch {
|
|
||||||
logViewModel.scrollToUncommitedChanges.collect {
|
|
||||||
scrollToUncommitedChanges(verticalScrollState, commitList)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
launch {
|
||||||
|
logViewModel.scrollToUncommitedChanges.collect {
|
||||||
|
scrollToUncommitedChanges(verticalScrollState, commitList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LogDialogs(
|
LogDialogs(
|
||||||
logViewModel,
|
logViewModel,
|
||||||
onResetShowLogDialog = { logViewModel.showDialog(LogDialog.None) },
|
onResetShowLogDialog = { logViewModel.showDialog(LogDialog.None) },
|
||||||
showLogDialog = showLogDialog,
|
showLogDialog = showLogDialog,
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(MaterialTheme.colors.background)
|
||||||
|
.fillMaxSize()
|
||||||
|
) {
|
||||||
|
var graphPadding by remember(logViewModel) { mutableStateOf(logViewModel.graphPadding) }
|
||||||
|
var graphWidth = (CANVAS_DEFAULT_WIDTH + graphPadding).dp
|
||||||
|
|
||||||
|
if (graphWidth.value < CANVAS_MIN_WIDTH) graphWidth = CANVAS_MIN_WIDTH.dp
|
||||||
|
|
||||||
|
val maxLinePosition = if (commitList.isNotEmpty())
|
||||||
|
commitList.maxLine
|
||||||
|
else
|
||||||
|
MIN_GRAPH_LANES
|
||||||
|
|
||||||
|
var graphRealWidth = ((maxLinePosition + MARGIN_GRAPH_LANES) * LANE_WIDTH).dp
|
||||||
|
|
||||||
|
// Using remember(graphRealWidth, graphWidth) makes the selected background color glitch when changing tabs
|
||||||
|
if (graphRealWidth < graphWidth) {
|
||||||
|
graphRealWidth = graphWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (searchFilterValue is LogSearch.SearchResults) {
|
||||||
|
SearchFilter(logViewModel, searchFilterValue)
|
||||||
|
}
|
||||||
|
GraphHeader(
|
||||||
|
graphWidth = graphWidth,
|
||||||
|
onPaddingChange = {
|
||||||
|
graphPadding += it
|
||||||
|
logViewModel.graphPadding = graphPadding
|
||||||
|
},
|
||||||
|
onShowSearch = { scope.launch { logViewModel.onSearchValueChanged("") } }
|
||||||
)
|
)
|
||||||
|
|
||||||
Column(
|
Box {
|
||||||
modifier = Modifier
|
Box(
|
||||||
.background(MaterialTheme.colors.background)
|
Modifier
|
||||||
.fillMaxSize()
|
.width(graphWidth)
|
||||||
) {
|
.fillMaxHeight()
|
||||||
var graphPadding by remember(logViewModel) { mutableStateOf(logViewModel.graphPadding) }
|
) {
|
||||||
var graphWidth = (CANVAS_DEFAULT_WIDTH + graphPadding).dp
|
|
||||||
|
|
||||||
if (graphWidth.value < CANVAS_MIN_WIDTH) graphWidth = CANVAS_MIN_WIDTH.dp
|
|
||||||
|
|
||||||
val maxLinePosition = if (commitList.isNotEmpty())
|
|
||||||
commitList.maxLine
|
|
||||||
else
|
|
||||||
MIN_GRAPH_LANES
|
|
||||||
|
|
||||||
var graphRealWidth = ((maxLinePosition + MARGIN_GRAPH_LANES) * LANE_WIDTH).dp
|
|
||||||
|
|
||||||
// Using remember(graphRealWidth, graphWidth) makes the selected background color glitch when changing tabs
|
|
||||||
if (graphRealWidth < graphWidth) {
|
|
||||||
graphRealWidth = graphWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (searchFilterValue is LogSearch.SearchResults) {
|
|
||||||
SearchFilter(logViewModel, searchFilterValue)
|
|
||||||
}
|
|
||||||
GraphHeader(
|
|
||||||
graphWidth = graphWidth,
|
|
||||||
onPaddingChange = {
|
|
||||||
graphPadding += it
|
|
||||||
logViewModel.graphPadding = graphPadding
|
|
||||||
},
|
|
||||||
onShowSearch = { scope.launch { logViewModel.onSearchValueChanged("") } }
|
|
||||||
)
|
|
||||||
|
|
||||||
Box {
|
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
modifier = Modifier
|
||||||
.width(graphWidth)
|
.fillMaxSize()
|
||||||
.fillMaxHeight()
|
.horizontalScroll(horizontalScrollState)
|
||||||
|
.padding(bottom = 8.dp)
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier.width(graphRealWidth)
|
||||||
.fillMaxSize()
|
)
|
||||||
.horizontalScroll(horizontalScrollState)
|
|
||||||
.padding(bottom = 8.dp)
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.width(graphRealWidth)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The commits' messages list overlaps with the graph list to catch all the click events but leaves
|
// The commits' messages list overlaps with the graph list to catch all the click events but leaves
|
||||||
// a padding, so it doesn't cover the graph
|
// a padding, so it doesn't cover the graph
|
||||||
MessagesList(
|
MessagesList(
|
||||||
scrollState = verticalScrollState,
|
scrollState = verticalScrollState,
|
||||||
horizontalScrollState = horizontalScrollState,
|
horizontalScrollState = horizontalScrollState,
|
||||||
hasUncommitedChanges = hasUncommitedChanges,
|
hasUncommitedChanges = hasUncommitedChanges,
|
||||||
searchFilter = if (searchFilterValue is LogSearch.SearchResults) searchFilterValue.commits else null,
|
searchFilter = if (searchFilterValue is LogSearch.SearchResults) searchFilterValue.commits else null,
|
||||||
selectedCommit = selectedCommit,
|
selectedCommit = selectedCommit,
|
||||||
logStatus = logStatus,
|
logStatus = logStatus,
|
||||||
repositoryState = repositoryState,
|
repositoryState = repositoryState,
|
||||||
selectedItem = selectedItem,
|
selectedItem = selectedItem,
|
||||||
commitList = commitList,
|
commitList = commitList,
|
||||||
logViewModel = logViewModel,
|
logViewModel = logViewModel,
|
||||||
graphWidth = graphWidth,
|
graphWidth = graphWidth,
|
||||||
commitsLimit = logStatus.commitsLimit,
|
commitsLimit = logStatus.commitsLimit,
|
||||||
onMerge = { ref ->
|
onMerge = { ref ->
|
||||||
logViewModel.mergeBranch(ref)
|
logViewModel.mergeBranch(ref)
|
||||||
},
|
},
|
||||||
onRebase = { ref ->
|
onRebase = { ref ->
|
||||||
logViewModel.rebaseBranch(ref)
|
logViewModel.rebaseBranch(ref)
|
||||||
},
|
},
|
||||||
onShowLogDialog = { dialog ->
|
onShowLogDialog = { dialog ->
|
||||||
logViewModel.showDialog(dialog)
|
logViewModel.showDialog(dialog)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val density = LocalDensity.current.density
|
val density = LocalDensity.current.density
|
||||||
DividerLog(
|
DividerLog(
|
||||||
modifier = Modifier.draggable(
|
modifier = Modifier.draggable(
|
||||||
rememberDraggableState {
|
rememberDraggableState {
|
||||||
graphPadding += it / density
|
graphPadding += it / density
|
||||||
logViewModel.graphPadding = graphPadding
|
logViewModel.graphPadding = graphPadding
|
||||||
}, Orientation.Horizontal
|
}, Orientation.Horizontal
|
||||||
),
|
),
|
||||||
graphWidth = graphWidth,
|
graphWidth = graphWidth,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// Scrollbar used to scroll horizontally the graph nodes
|
// Scrollbar used to scroll horizontally the graph nodes
|
||||||
// Added after every component to have the highest priority when clicking
|
// Added after every component to have the highest priority when clicking
|
||||||
HorizontalScrollbar(
|
HorizontalScrollbar(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomStart)
|
||||||
|
.width(graphWidth)
|
||||||
|
.padding(start = 4.dp, bottom = 4.dp), style = LocalScrollbarStyle.current.copy(
|
||||||
|
unhoverColor = MaterialTheme.colors.scrollbarNormal,
|
||||||
|
hoverColor = MaterialTheme.colors.scrollbarHover,
|
||||||
|
),
|
||||||
|
adapter = rememberScrollbarAdapter(horizontalScrollState)
|
||||||
|
)
|
||||||
|
|
||||||
|
val isFirstItemVisible by remember {
|
||||||
|
derivedStateOf { verticalScrollState.firstVisibleItemIndex > 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFirstItemVisible) {
|
||||||
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.BottomStart)
|
.align(Alignment.TopCenter)
|
||||||
.width(graphWidth)
|
.padding(top = 16.dp)
|
||||||
.padding(start = 4.dp, bottom = 4.dp), style = LocalScrollbarStyle.current.copy(
|
.clip(RoundedCornerShape(50))
|
||||||
unhoverColor = MaterialTheme.colors.scrollbarNormal,
|
.handMouseClickable {
|
||||||
hoverColor = MaterialTheme.colors.scrollbarHover,
|
scope.launch {
|
||||||
),
|
verticalScrollState.scrollToItem(0)
|
||||||
adapter = rememberScrollbarAdapter(horizontalScrollState)
|
|
||||||
)
|
|
||||||
|
|
||||||
val isFirstItemVisible by remember {
|
|
||||||
derivedStateOf { verticalScrollState.firstVisibleItemIndex > 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isFirstItemVisible) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.TopCenter)
|
|
||||||
.padding(top = 16.dp)
|
|
||||||
.clip(RoundedCornerShape(50))
|
|
||||||
.handMouseClickable {
|
|
||||||
scope.launch {
|
|
||||||
verticalScrollState.scrollToItem(0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.background(MaterialTheme.colors.primary)
|
|
||||||
.padding(vertical = 4.dp, horizontal = 8.dp),
|
|
||||||
) {
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
||||||
Icon(
|
|
||||||
painterResource(AppIcons.ALIGN_TOP),
|
|
||||||
contentDescription = null,
|
|
||||||
tint = MaterialTheme.colors.onPrimary,
|
|
||||||
modifier = Modifier.size(20.dp),
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = "Scroll to top",
|
|
||||||
modifier = Modifier.padding(start = 8.dp),
|
|
||||||
color = MaterialTheme.colors.onPrimary,
|
|
||||||
style = MaterialTheme.typography.body2,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
.background(MaterialTheme.colors.primary)
|
||||||
|
.padding(vertical = 4.dp, horizontal = 8.dp),
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Icon(
|
||||||
|
painterResource(AppIcons.ALIGN_TOP),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colors.onPrimary,
|
||||||
|
modifier = Modifier.size(20.dp),
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Scroll to top",
|
||||||
|
modifier = Modifier.padding(start = 8.dp),
|
||||||
|
color = MaterialTheme.colors.onPrimary,
|
||||||
|
style = MaterialTheme.typography.body2,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user