Added dialog to edit author info
This commit is contained in:
parent
43330eb3c4
commit
ab8e8c7dbe
@ -40,3 +40,6 @@ val String.lineDelimiter: String?
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
val String.nullIfEmpty: String?
|
||||
get() = this.ifBlank { null }
|
61
src/main/kotlin/app/git/AuthorManager.kt
Normal file
61
src/main/kotlin/app/git/AuthorManager.kt
Normal file
@ -0,0 +1,61 @@
|
||||
package app.git
|
||||
|
||||
import app.models.AuthorInfo
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.storage.file.FileBasedConfig
|
||||
import javax.inject.Inject
|
||||
|
||||
class AuthorManager @Inject constructor() {
|
||||
suspend fun loadAuthor(git: Git) = withContext(Dispatchers.IO) {
|
||||
val config = git.repository.config
|
||||
val globalConfig = git.repository.config.baseConfig
|
||||
|
||||
val repoConfig = FileBasedConfig((config as FileBasedConfig).file, git.repository.fs)
|
||||
repoConfig.load()
|
||||
|
||||
val globalName = globalConfig.getString("user", null, "name")
|
||||
val globalEmail = globalConfig.getString("user", null, "email")
|
||||
|
||||
val name = repoConfig.getString("user", null, "name")
|
||||
val email = repoConfig.getString("user", null, "email")
|
||||
|
||||
return@withContext AuthorInfo(
|
||||
globalName,
|
||||
globalEmail,
|
||||
name,
|
||||
email,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun saveAuthorInfo(git: Git, newAuthorInfo: AuthorInfo) = withContext(Dispatchers.IO) {
|
||||
val config = git.repository.config
|
||||
val globalConfig = git.repository.config.baseConfig
|
||||
val repoConfig = FileBasedConfig((config as FileBasedConfig).file, git.repository.fs)
|
||||
repoConfig.load()
|
||||
|
||||
if (globalConfig is FileBasedConfig) {
|
||||
globalConfig.setStringProperty("user", null, "name", newAuthorInfo.globalName)
|
||||
globalConfig.setStringProperty("user", null, "email", newAuthorInfo.globalEmail)
|
||||
globalConfig.save()
|
||||
}
|
||||
|
||||
config.setStringProperty("user", null, "name", newAuthorInfo.name)
|
||||
config.setStringProperty("user", null, "email", newAuthorInfo.email)
|
||||
config.save()
|
||||
}
|
||||
|
||||
private fun FileBasedConfig.setStringProperty(
|
||||
section: String,
|
||||
subsection: String?,
|
||||
name: String,
|
||||
value: String?,
|
||||
) {
|
||||
if(value == null) {
|
||||
unset(section, subsection, name)
|
||||
} else {
|
||||
setString(section, subsection, name, value)
|
||||
}
|
||||
}
|
||||
}
|
8
src/main/kotlin/app/models/AuthorInfo.kt
Normal file
8
src/main/kotlin/app/models/AuthorInfo.kt
Normal file
@ -0,0 +1,8 @@
|
||||
package app.models
|
||||
|
||||
data class AuthorInfo(
|
||||
val globalName: String?,
|
||||
val globalEmail: String?,
|
||||
val name: String?,
|
||||
val email: String?,
|
||||
)
|
@ -1,6 +1,6 @@
|
||||
package app.git
|
||||
package app.models
|
||||
|
||||
data class UserInfo(
|
||||
data class AuthorInfoSimple(
|
||||
val name: String?,
|
||||
val email: String?,
|
||||
)
|
@ -12,10 +12,13 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.PointerIcon
|
||||
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import app.extensions.handMouseClickable
|
||||
import app.git.DiffEntryType
|
||||
import app.theme.*
|
||||
import app.ui.dialogs.AuthorDialog
|
||||
import app.ui.dialogs.NewBranchDialog
|
||||
import app.ui.dialogs.RebaseInteractive
|
||||
import app.ui.dialogs.StashWithMessageDialog
|
||||
@ -39,7 +42,8 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
|
||||
val selectedItem by tabViewModel.selectedItem.collectAsState()
|
||||
val blameState by tabViewModel.blameState.collectAsState()
|
||||
val showHistory by tabViewModel.showHistory.collectAsState()
|
||||
val userInfo by tabViewModel.userInfo.collectAsState()
|
||||
val userInfo by tabViewModel.authorInfoSimple.collectAsState()
|
||||
val showAuthorInfo by tabViewModel.showAuthorInfo.collectAsState()
|
||||
|
||||
var showNewBranchDialog by remember { mutableStateOf(false) }
|
||||
var showStashWithMessageDialog by remember { mutableStateOf(false) }
|
||||
@ -64,6 +68,16 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
|
||||
showStashWithMessageDialog = false
|
||||
}
|
||||
)
|
||||
} else if (showAuthorInfo) {
|
||||
val authorViewModel = tabViewModel.authorViewModel
|
||||
if (authorViewModel != null) {
|
||||
AuthorDialog(
|
||||
authorViewModel = authorViewModel,
|
||||
onClose = {
|
||||
tabViewModel.closeAuthorInfoDialog()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
@ -107,13 +121,20 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
|
||||
.background(MaterialTheme.colors.surface)
|
||||
.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.handMouseClickable { tabViewModel.showAuthorInfoDialog() },
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
text = "${userInfo.name ?: "Name not set"} <${userInfo.email?: "Email not set"}>",
|
||||
text = "${userInfo.name ?: "Name not set"} <${userInfo.email ?: "Email not set"}>",
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
fontSize = 12.sp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
150
src/main/kotlin/app/ui/dialogs/AuthorDialog.kt
Normal file
150
src/main/kotlin/app/ui/dialogs/AuthorDialog.kt
Normal file
@ -0,0 +1,150 @@
|
||||
package app.ui.dialogs
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.mouseClickable
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.isPrimaryPressed
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import app.theme.outlinedTextFieldColors
|
||||
import app.theme.primaryTextColor
|
||||
import app.theme.textButtonColors
|
||||
import app.ui.components.PrimaryButton
|
||||
import app.viewmodels.AuthorViewModel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun AuthorDialog(
|
||||
authorViewModel: AuthorViewModel,
|
||||
onClose: () -> Unit,
|
||||
) {
|
||||
val authorInfo by authorViewModel.authorInfo.collectAsState()
|
||||
|
||||
var globalName by remember(authorInfo) { mutableStateOf(authorInfo.globalName.orEmpty()) }
|
||||
var globalEmail by remember(authorInfo) { mutableStateOf(authorInfo.globalEmail.orEmpty()) }
|
||||
var name by remember(authorInfo) { mutableStateOf(authorInfo.name.orEmpty()) }
|
||||
var email by remember(authorInfo) { mutableStateOf(authorInfo.email.orEmpty()) }
|
||||
|
||||
MaterialDialog(onCloseRequested = onClose) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colors.background)
|
||||
.padding(horizontal = 8.dp),
|
||||
) {
|
||||
|
||||
Text(
|
||||
text = "Global settings",
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
fontSize = 18.sp,
|
||||
)
|
||||
|
||||
TextInput(
|
||||
title = "Name",
|
||||
value = globalName,
|
||||
onValueChange = { globalName = it },
|
||||
)
|
||||
TextInput(
|
||||
title = "Email",
|
||||
value = globalEmail,
|
||||
onValueChange = { globalEmail = it },
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "Repository settings",
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
fontSize = 18.sp,
|
||||
modifier = Modifier.padding(top = 16.dp),
|
||||
)
|
||||
|
||||
TextInput(
|
||||
title = "Name",
|
||||
value = name,
|
||||
onValueChange = { name = it },
|
||||
)
|
||||
TextInput(
|
||||
title = "Email",
|
||||
value = email,
|
||||
onValueChange = { email = it },
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "Repository-level values will override global values",
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
fontSize = 14.sp,
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 16.dp)
|
||||
.align(Alignment.End)
|
||||
) {
|
||||
TextButton(
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
colors = textButtonColors(),
|
||||
onClick = {
|
||||
onClose()
|
||||
}
|
||||
) {
|
||||
Text("Cancel")
|
||||
}
|
||||
PrimaryButton(
|
||||
onClick = {
|
||||
authorViewModel.saveAuthorInfo(
|
||||
globalName,
|
||||
globalEmail,
|
||||
name,
|
||||
email,
|
||||
)
|
||||
onClose()
|
||||
},
|
||||
text = "Save"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun TextInput(
|
||||
title: String,
|
||||
value: String,
|
||||
enabled: Boolean = true,
|
||||
onValueChange: (String) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.width(400.dp)
|
||||
.padding(vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
color = MaterialTheme.colors.primaryTextColor,
|
||||
fontSize = 16.sp,
|
||||
modifier = Modifier
|
||||
.width(100.dp)
|
||||
.padding(end = 16.dp),
|
||||
)
|
||||
|
||||
|
||||
OutlinedTextField(
|
||||
value = value,
|
||||
modifier = Modifier
|
||||
.weight(1f),
|
||||
enabled = enabled,
|
||||
onValueChange = onValueChange,
|
||||
colors = outlinedTextFieldColors(),
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
40
src/main/kotlin/app/viewmodels/AuthorViewModel.kt
Normal file
40
src/main/kotlin/app/viewmodels/AuthorViewModel.kt
Normal file
@ -0,0 +1,40 @@
|
||||
package app.viewmodels
|
||||
|
||||
import app.extensions.nullIfEmpty
|
||||
import app.git.AuthorManager
|
||||
import app.git.RefreshType
|
||||
import app.git.TabState
|
||||
import app.models.AuthorInfo
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
class AuthorViewModel @Inject constructor(
|
||||
private val tabState: TabState,
|
||||
private val authorManager: AuthorManager,
|
||||
) {
|
||||
|
||||
private val _authorInfo = MutableStateFlow(AuthorInfo(null, null, null, null))
|
||||
val authorInfo: StateFlow<AuthorInfo> = _authorInfo
|
||||
|
||||
fun loadAuthorInfo() = tabState.runOperation(
|
||||
refreshType = RefreshType.NONE,
|
||||
showError = true,
|
||||
) { git ->
|
||||
_authorInfo.value = authorManager.loadAuthor(git)
|
||||
}
|
||||
|
||||
fun saveAuthorInfo(globalName: String, globalEmail: String, name: String, email: String) = tabState.runOperation(
|
||||
showError = true,
|
||||
refreshType = RefreshType.REPO_STATE,
|
||||
) { git ->
|
||||
val newAuthorInfo = AuthorInfo(
|
||||
globalName.nullIfEmpty,
|
||||
globalEmail.nullIfEmpty,
|
||||
name.nullIfEmpty,
|
||||
email.nullIfEmpty,
|
||||
)
|
||||
|
||||
authorManager.saveAuthorInfo(git, newAuthorInfo)
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import app.credentials.CredentialsState
|
||||
import app.credentials.CredentialsStateManager
|
||||
import app.git.*
|
||||
import app.logging.printLog
|
||||
import app.models.AuthorInfoSimple
|
||||
import app.newErrorNow
|
||||
import app.ui.SelectedItem
|
||||
import app.updates.Update
|
||||
@ -19,7 +20,6 @@ import org.eclipse.jgit.blame.BlameResult
|
||||
import org.eclipse.jgit.lib.Repository
|
||||
import org.eclipse.jgit.lib.RepositoryState
|
||||
import org.eclipse.jgit.revwalk.RevCommit
|
||||
import org.eclipse.jgit.storage.file.FileBasedConfig
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
@ -46,6 +46,7 @@ class TabViewModel @Inject constructor(
|
||||
private val diffViewModelProvider: Provider<DiffViewModel>,
|
||||
private val rebaseInteractiveViewModelProvider: Provider<RebaseInteractiveViewModel>,
|
||||
private val historyViewModelProvider: Provider<HistoryViewModel>,
|
||||
private val authorViewModelProvider: Provider<AuthorViewModel>,
|
||||
private val repositoryManager: RepositoryManager,
|
||||
private val tabState: TabState,
|
||||
val appStateManager: AppStateManager,
|
||||
@ -88,12 +89,18 @@ class TabViewModel @Inject constructor(
|
||||
private val _showHistory = MutableStateFlow(false)
|
||||
val showHistory: StateFlow<Boolean> = _showHistory
|
||||
|
||||
private val _userInfo = MutableStateFlow(UserInfo(null, null))
|
||||
val userInfo: StateFlow<UserInfo> = _userInfo
|
||||
private val _showAuthorInfo = MutableStateFlow(false)
|
||||
val showAuthorInfo: StateFlow<Boolean> = _showAuthorInfo
|
||||
|
||||
private val _authorInfoSimple = MutableStateFlow(AuthorInfoSimple(null, null))
|
||||
val authorInfoSimple: StateFlow<AuthorInfoSimple> = _authorInfoSimple
|
||||
|
||||
var historyViewModel: HistoryViewModel? = null
|
||||
private set
|
||||
|
||||
var authorViewModel: AuthorViewModel? = null
|
||||
private set
|
||||
|
||||
val showError = MutableStateFlow(false)
|
||||
|
||||
init {
|
||||
@ -185,27 +192,29 @@ class TabViewModel @Inject constructor(
|
||||
printLog(TAG, "Refreshing repository state $newRepoState")
|
||||
_repositoryState.value = newRepoState
|
||||
|
||||
loadConfigInfo(git)
|
||||
loadAuthorInfo(git)
|
||||
|
||||
onRepositoryStateChanged(newRepoState)
|
||||
}
|
||||
|
||||
private fun loadConfigInfo(git: Git) {
|
||||
private fun loadAuthorInfo(git: Git) {
|
||||
val config = git.repository.config
|
||||
config.load()
|
||||
val userName = config.getString("user", null, "name")
|
||||
val email = config.getString("user", null, "email")
|
||||
|
||||
// TODO Load file-specific config
|
||||
// val fcfg = FileBasedConfig((config as FileBasedConfig).file, git.repository.fs)
|
||||
// fcfg.load()
|
||||
// val fname = fcfg.getString("user", null, "name")
|
||||
// val fmail = fcfg.getString("user", null, "email")
|
||||
// println("Fname $fname\nFmail $fmail")
|
||||
_authorInfoSimple.value = AuthorInfoSimple(userName, email)
|
||||
}
|
||||
|
||||
println(userName)
|
||||
println(email)
|
||||
_userInfo.value = UserInfo(userName, email)
|
||||
fun showAuthorInfoDialog() {
|
||||
authorViewModel = authorViewModelProvider.get()
|
||||
authorViewModel?.loadAuthorInfo()
|
||||
_showAuthorInfo.value = true
|
||||
}
|
||||
|
||||
fun closeAuthorInfoDialog() {
|
||||
_showAuthorInfo.value = false
|
||||
authorViewModel = null
|
||||
}
|
||||
|
||||
private fun onRepositoryStateChanged(newRepoState: RepositoryState) {
|
||||
|
Loading…
Reference in New Issue
Block a user