parent
07e1bbd4ed
commit
ddc198a0d7
@ -42,6 +42,7 @@ object AppIcons {
|
||||
const val REVERT = "revert.svg"
|
||||
const val SEARCH = "search.svg"
|
||||
const val SETTINGS = "settings.svg"
|
||||
const val SIGN = "sign.svg"
|
||||
const val SOURCE = "source.svg"
|
||||
const val START = "start.svg"
|
||||
const val STASH = "stash.svg"
|
||||
|
@ -0,0 +1,35 @@
|
||||
package com.jetpackduba.gitnuro.git.config
|
||||
|
||||
import com.jetpackduba.gitnuro.extensions.nullIfEmpty
|
||||
import com.jetpackduba.gitnuro.models.SignOffConfig
|
||||
import org.eclipse.jgit.lib.Repository
|
||||
import org.eclipse.jgit.storage.file.FileBasedConfig
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class LoadSignOffConfigUseCase @Inject constructor() {
|
||||
operator fun invoke(repository: Repository): SignOffConfig {
|
||||
val configFile = File(repository.directory, LocalConfigConstants.CONFIG_FILE_NAME)
|
||||
configFile.createNewFile()
|
||||
|
||||
val config = FileBasedConfig(configFile, repository.fs)
|
||||
config.load()
|
||||
|
||||
val enabled = config.getBoolean(
|
||||
LocalConfigConstants.SignOff.SECTION,
|
||||
null,
|
||||
LocalConfigConstants.SignOff.FIELD_ENABLED,
|
||||
LocalConfigConstants.SignOff.DEFAULT_SIGN_OFF_ENABLED
|
||||
)
|
||||
|
||||
|
||||
val format = config.getString(
|
||||
LocalConfigConstants.SignOff.SECTION,
|
||||
null,
|
||||
LocalConfigConstants.SignOff.FIELD_FORMAT
|
||||
)?.nullIfEmpty ?: LocalConfigConstants.SignOff.DEFAULT_SIGN_OFF_FORMAT
|
||||
|
||||
return SignOffConfig(enabled, format)
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.jetpackduba.gitnuro.git.config
|
||||
|
||||
object LocalConfigConstants {
|
||||
const val CONFIG_FILE_NAME = "gitnuro"
|
||||
|
||||
object SignOff {
|
||||
const val SECTION = "signoff"
|
||||
const val FIELD_ENABLED = "enabled"
|
||||
const val FIELD_FORMAT = "format"
|
||||
|
||||
const val DEFAULT_SIGN_OFF_FORMAT_USER = "%user"
|
||||
const val DEFAULT_SIGN_OFF_FORMAT_EMAIL = "%email"
|
||||
const val DEFAULT_SIGN_OFF_FORMAT = "Signed-off-by: $DEFAULT_SIGN_OFF_FORMAT_USER <$DEFAULT_SIGN_OFF_FORMAT_EMAIL>"
|
||||
const val DEFAULT_SIGN_OFF_ENABLED = false
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.jetpackduba.gitnuro.git.config
|
||||
|
||||
import com.jetpackduba.gitnuro.models.SignOffConfig
|
||||
import org.eclipse.jgit.lib.Repository
|
||||
import org.eclipse.jgit.storage.file.FileBasedConfig
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
class SaveLocalRepositoryConfigUseCase @Inject constructor() {
|
||||
operator fun invoke(
|
||||
repository: Repository,
|
||||
signOffConfig: SignOffConfig,
|
||||
) {
|
||||
val configFile = File(repository.directory, LocalConfigConstants.CONFIG_FILE_NAME)
|
||||
configFile.createNewFile()
|
||||
|
||||
val config = FileBasedConfig(configFile, repository.fs)
|
||||
|
||||
config.setBoolean(
|
||||
LocalConfigConstants.SignOff.SECTION,
|
||||
null,
|
||||
LocalConfigConstants.SignOff.FIELD_ENABLED,
|
||||
signOffConfig.isEnabled
|
||||
)
|
||||
|
||||
config.setString(
|
||||
LocalConfigConstants.SignOff.SECTION,
|
||||
null,
|
||||
LocalConfigConstants.SignOff.FIELD_FORMAT,
|
||||
signOffConfig.format
|
||||
)
|
||||
|
||||
config.save()
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
package com.jetpackduba.gitnuro.git.workspace
|
||||
|
||||
import com.jetpackduba.gitnuro.git.author.LoadAuthorUseCase
|
||||
import com.jetpackduba.gitnuro.git.config.LoadSignOffConfigUseCase
|
||||
import com.jetpackduba.gitnuro.git.config.LocalConfigConstants
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.eclipse.jgit.api.Git
|
||||
@ -7,15 +10,31 @@ import org.eclipse.jgit.lib.PersonIdent
|
||||
import org.eclipse.jgit.revwalk.RevCommit
|
||||
import javax.inject.Inject
|
||||
|
||||
class DoCommitUseCase @Inject constructor() {
|
||||
class DoCommitUseCase @Inject constructor(
|
||||
private val loadSignOffConfigUseCase: LoadSignOffConfigUseCase,
|
||||
private val loadAuthorUseCase: LoadAuthorUseCase,
|
||||
) {
|
||||
suspend operator fun invoke(
|
||||
git: Git,
|
||||
message: String,
|
||||
amend: Boolean,
|
||||
author: PersonIdent?,
|
||||
): RevCommit = withContext(Dispatchers.IO) {
|
||||
val signOffConfig = loadSignOffConfigUseCase(git.repository)
|
||||
|
||||
val finalMessage = if(signOffConfig.isEnabled) {
|
||||
val authorToSign = author ?: loadAuthorUseCase(git).toPersonIdent()
|
||||
|
||||
val signature = signOffConfig.format
|
||||
.replace(LocalConfigConstants.SignOff.DEFAULT_SIGN_OFF_FORMAT_USER, authorToSign.name)
|
||||
.replace(LocalConfigConstants.SignOff.DEFAULT_SIGN_OFF_FORMAT_EMAIL, authorToSign.emailAddress)
|
||||
|
||||
"$message\n\n$signature"
|
||||
} else
|
||||
message
|
||||
|
||||
git.commit()
|
||||
.setMessage(message)
|
||||
.setMessage(finalMessage)
|
||||
.setAllowEmpty(amend) // Only allow empty commits when amending
|
||||
.setAmend(amend)
|
||||
.setAuthor(author)
|
||||
|
@ -1,8 +1,16 @@
|
||||
package com.jetpackduba.gitnuro.models
|
||||
|
||||
import org.eclipse.jgit.lib.PersonIdent
|
||||
|
||||
data class AuthorInfo(
|
||||
val globalName: String?,
|
||||
val globalEmail: String?,
|
||||
val name: String?,
|
||||
val email: String?,
|
||||
)
|
||||
) {
|
||||
fun toPersonIdent() = PersonIdent(
|
||||
name ?: globalName ?: "",
|
||||
email ?: globalEmail ?: "",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
package com.jetpackduba.gitnuro.models
|
||||
|
||||
data class SignOffConfig(
|
||||
val isEnabled: Boolean,
|
||||
val format: String,
|
||||
)
|
@ -24,6 +24,7 @@ import com.jetpackduba.gitnuro.git.DiffEntryType
|
||||
import com.jetpackduba.gitnuro.keybindings.KeybindingOption
|
||||
import com.jetpackduba.gitnuro.keybindings.matchesBinding
|
||||
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
|
||||
import com.jetpackduba.gitnuro.ui.components.gitnuroDynamicViewModel
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.*
|
||||
import com.jetpackduba.gitnuro.ui.diff.Diff
|
||||
import com.jetpackduba.gitnuro.ui.log.Log
|
||||
@ -53,6 +54,7 @@ fun RepositoryOpenPage(
|
||||
var showNewBranchDialog by remember { mutableStateOf(false) }
|
||||
var showStashWithMessageDialog by remember { mutableStateOf(false) }
|
||||
var showQuickActionsDialog by remember { mutableStateOf(false) }
|
||||
var showSignOffDialog by remember { mutableStateOf(false) }
|
||||
|
||||
if (showNewBranchDialog) {
|
||||
NewBranchDialog(
|
||||
@ -93,9 +95,15 @@ fun RepositoryOpenPage(
|
||||
QuickActionType.OPEN_DIR_IN_FILE_MANAGER -> tabViewModel.openFolderInFileExplorer()
|
||||
QuickActionType.CLONE -> onShowCloneDialog()
|
||||
QuickActionType.REFRESH -> tabViewModel.refreshAll()
|
||||
QuickActionType.SIGN_OFF -> showSignOffDialog = true
|
||||
}
|
||||
},
|
||||
)
|
||||
} else if (showSignOffDialog) {
|
||||
SignOffDialog(
|
||||
viewModel = gitnuroDynamicViewModel(),
|
||||
onClose = { showSignOffDialog = false },
|
||||
)
|
||||
}
|
||||
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
@ -43,10 +44,7 @@ import com.jetpackduba.gitnuro.keybindings.KeybindingOption
|
||||
import com.jetpackduba.gitnuro.keybindings.matchesBinding
|
||||
import com.jetpackduba.gitnuro.theme.*
|
||||
import com.jetpackduba.gitnuro.ui.components.*
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.ContextMenu
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.ContextMenuElement
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.EntryType
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.statusEntriesContextMenuItems
|
||||
import com.jetpackduba.gitnuro.ui.context_menu.*
|
||||
import com.jetpackduba.gitnuro.ui.dialogs.CommitAuthorDialog
|
||||
import com.jetpackduba.gitnuro.viewmodels.CommitterDataRequestState
|
||||
import com.jetpackduba.gitnuro.viewmodels.StageState
|
||||
@ -306,7 +304,7 @@ fun UncommitedChanges(
|
||||
onAmendChecked = { isAmend ->
|
||||
statusViewModel.amend(isAmend)
|
||||
},
|
||||
onCommit = { doCommit() },
|
||||
onCommit = doCommit,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -322,8 +320,6 @@ fun UncommitedChangesButtons(
|
||||
onAmendChecked: (Boolean) -> Unit,
|
||||
onCommit: () -> Unit
|
||||
) {
|
||||
var showDropDownMenu by remember { mutableStateOf(false) }
|
||||
|
||||
val buttonText = if (isAmend)
|
||||
"Amend"
|
||||
else
|
||||
@ -368,47 +364,8 @@ fun UncommitedChangesButtons(
|
||||
onCommit()
|
||||
},
|
||||
enabled = canCommit || (canAmend && isAmend),
|
||||
shape = MaterialTheme.shapes.small.copy(topEnd = CornerSize(0.dp), bottomEnd = CornerSize(0.dp))
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
)
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.width(1.dp)
|
||||
.height(36.dp),
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(36.dp)
|
||||
.clip(MaterialTheme.shapes.small.copy(topStart = CornerSize(0.dp), bottomStart = CornerSize(0.dp)))
|
||||
.background(MaterialTheme.colors.primary)
|
||||
.handMouseClickable { showDropDownMenu = true }
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.ArrowDropDown,
|
||||
contentDescription = null,
|
||||
tint = Color.White,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
.align(Alignment.Center),
|
||||
)
|
||||
DropdownMenu(
|
||||
onDismissRequest = {
|
||||
showDropDownMenu = false
|
||||
},
|
||||
content = {
|
||||
/*DropDownContent(
|
||||
enabled = canAmend,
|
||||
dropDownContentData = DropDownContentData(
|
||||
label = "Amend previous commit",
|
||||
icon = null,
|
||||
onClick = onCommit
|
||||
),
|
||||
onDismiss = { showDropDownMenu = false }
|
||||
)*/
|
||||
},
|
||||
expanded = showDropDownMenu,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,13 +26,13 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.AppIcons
|
||||
import com.jetpackduba.gitnuro.managers.AppStateManager
|
||||
import com.jetpackduba.gitnuro.LocalTabScope
|
||||
import com.jetpackduba.gitnuro.di.AppComponent
|
||||
import com.jetpackduba.gitnuro.di.DaggerTabComponent
|
||||
import com.jetpackduba.gitnuro.di.TabComponent
|
||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.extensions.handOnHover
|
||||
import com.jetpackduba.gitnuro.managers.AppStateManager
|
||||
import com.jetpackduba.gitnuro.viewmodels.TabViewModel
|
||||
import com.jetpackduba.gitnuro.viewmodels.TabViewModelsHolder
|
||||
import kotlinx.coroutines.delay
|
||||
@ -264,9 +264,12 @@ inline fun <reified T> gitnuroViewModel(): T {
|
||||
tab.tabViewModelsHolder.viewModels[T::class] as T
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
inline fun <reified T> gitnuroDynamicViewModel(): T {
|
||||
val tab = LocalTabScope.current
|
||||
|
||||
return tab.tabViewModelsHolder.dynamicViewModel(T::class) as T
|
||||
return remember(tab) {
|
||||
tab.tabViewModelsHolder.dynamicViewModel(T::class) as T
|
||||
}
|
||||
}
|
@ -36,6 +36,7 @@ fun QuickActionsDialog(
|
||||
QuickAction(AppIcons.CODE, "Open repository in file manager", QuickActionType.OPEN_DIR_IN_FILE_MANAGER),
|
||||
QuickAction(AppIcons.DOWNLOAD, "Clone new repository", QuickActionType.CLONE),
|
||||
QuickAction(AppIcons.REFRESH, "Refresh repository data", QuickActionType.REFRESH),
|
||||
QuickAction(AppIcons.SIGN, "Signoff config", QuickActionType.SIGN_OFF),
|
||||
)
|
||||
}
|
||||
|
||||
@ -126,5 +127,6 @@ data class QuickAction(val icon: String, val title: String, val type: QuickActio
|
||||
enum class QuickActionType {
|
||||
OPEN_DIR_IN_FILE_MANAGER,
|
||||
CLONE,
|
||||
REFRESH;
|
||||
REFRESH,
|
||||
SIGN_OFF
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
package com.jetpackduba.gitnuro.ui.dialogs
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Checkbox
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusProperties
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.jetpackduba.gitnuro.AppIcons
|
||||
import com.jetpackduba.gitnuro.extensions.handMouseClickable
|
||||
import com.jetpackduba.gitnuro.ui.components.AdjustableOutlinedTextField
|
||||
import com.jetpackduba.gitnuro.ui.components.PrimaryButton
|
||||
import com.jetpackduba.gitnuro.viewmodels.SignOffDialogViewModel
|
||||
import com.jetpackduba.gitnuro.viewmodels.SignOffState
|
||||
|
||||
@Composable
|
||||
fun SignOffDialog(
|
||||
viewModel: SignOffDialogViewModel,
|
||||
onClose: () -> Unit,
|
||||
) {
|
||||
val state = viewModel.state.collectAsState().value
|
||||
|
||||
LaunchedEffect(viewModel) {
|
||||
viewModel.loadSignOffFormat()
|
||||
}
|
||||
|
||||
|
||||
var signOffField by remember(viewModel, state) {
|
||||
val signOff = if (state is SignOffState.Loaded) {
|
||||
state.signOffConfig.format
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
mutableStateOf(signOff)
|
||||
}
|
||||
|
||||
var enabledSignOff by remember(viewModel, state) {
|
||||
val signOff = if (state is SignOffState.Loaded) {
|
||||
state.signOffConfig.isEnabled
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
||||
mutableStateOf(signOff)
|
||||
}
|
||||
|
||||
val signOffFieldFocusRequester = remember { FocusRequester() }
|
||||
val buttonFieldFocusRequester = remember { FocusRequester() }
|
||||
|
||||
MaterialDialog(onCloseRequested = onClose) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.width(IntrinsicSize.Min),
|
||||
) {
|
||||
Icon(
|
||||
painterResource(AppIcons.SIGN),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.padding(bottom = 16.dp)
|
||||
.size(64.dp),
|
||||
tint = MaterialTheme.colors.onBackground,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "Edit sign off",
|
||||
modifier = Modifier
|
||||
.padding(bottom = 8.dp),
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
style = MaterialTheme.typography.body1,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "Enable or disable the signoff or adjust its format",
|
||||
modifier = Modifier
|
||||
.padding(bottom = 16.dp),
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
style = MaterialTheme.typography.body2,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
AdjustableOutlinedTextField(
|
||||
modifier = Modifier
|
||||
.focusRequester(signOffFieldFocusRequester)
|
||||
.focusProperties {
|
||||
this.next = buttonFieldFocusRequester
|
||||
}
|
||||
.width(300.dp),
|
||||
value = signOffField,
|
||||
enabled = state is SignOffState.Loaded,
|
||||
maxLines = 1,
|
||||
onValueChange = {
|
||||
signOffField = it
|
||||
},
|
||||
)
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.handMouseClickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
) {
|
||||
if (state is SignOffState.Loaded) {
|
||||
enabledSignOff = !enabledSignOff
|
||||
}
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp)
|
||||
) {
|
||||
Checkbox(
|
||||
checked = enabledSignOff,
|
||||
enabled = state is SignOffState.Loaded,
|
||||
onCheckedChange = {
|
||||
enabledSignOff = it
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(all = 8.dp)
|
||||
.size(12.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
"Enable signoff for this repository",
|
||||
style = MaterialTheme.typography.body2,
|
||||
color = MaterialTheme.colors.onBackground,
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 16.dp)
|
||||
.align(Alignment.End)
|
||||
) {
|
||||
PrimaryButton(
|
||||
text = "Cancel",
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
onClick = onClose,
|
||||
backgroundColor = Color.Transparent,
|
||||
textColor = MaterialTheme.colors.onBackground,
|
||||
)
|
||||
PrimaryButton(
|
||||
modifier = Modifier
|
||||
.focusRequester(buttonFieldFocusRequester)
|
||||
.focusProperties {
|
||||
this.previous = signOffFieldFocusRequester
|
||||
this.next = signOffFieldFocusRequester
|
||||
},
|
||||
enabled = signOffField.isNotBlank() && state is SignOffState.Loaded,
|
||||
onClick = {
|
||||
viewModel.saveSignOffFormat(enabledSignOff, signOffField)
|
||||
onClose()
|
||||
},
|
||||
text = "Save"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(state) {
|
||||
signOffFieldFocusRequester.requestFocus()
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.jetpackduba.gitnuro.viewmodels
|
||||
|
||||
import com.jetpackduba.gitnuro.git.RefreshType
|
||||
import com.jetpackduba.gitnuro.git.TabState
|
||||
import com.jetpackduba.gitnuro.git.config.LoadSignOffConfigUseCase
|
||||
import com.jetpackduba.gitnuro.git.config.SaveLocalRepositoryConfigUseCase
|
||||
import com.jetpackduba.gitnuro.models.SignOffConfig
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
class SignOffDialogViewModel @Inject constructor(
|
||||
private val tabState: TabState,
|
||||
private val loadSignOffConfigUseCase: LoadSignOffConfigUseCase,
|
||||
private val saveLocalRepositoryConfigUseCase: SaveLocalRepositoryConfigUseCase,
|
||||
) {
|
||||
private val _state = MutableStateFlow<SignOffState>(SignOffState.Loading)
|
||||
val state = _state.asStateFlow()
|
||||
|
||||
fun loadSignOffFormat() = tabState.runOperation(
|
||||
showError = true,
|
||||
refreshType = RefreshType.NONE,
|
||||
) { git ->
|
||||
val signOffConfig = loadSignOffConfigUseCase(git.repository)
|
||||
|
||||
_state.value = SignOffState.Loaded(signOffConfig)
|
||||
}
|
||||
|
||||
fun saveSignOffFormat(newIsEnabled: Boolean, newFormat: String) = tabState.runOperation(
|
||||
showError = true,
|
||||
refreshType = RefreshType.NONE,
|
||||
) { git ->
|
||||
saveLocalRepositoryConfigUseCase(git.repository, SignOffConfig(newIsEnabled, newFormat))
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface SignOffState {
|
||||
object Loading : SignOffState
|
||||
data class Loaded(val signOffConfig: SignOffConfig) : SignOffState
|
||||
}
|
@ -23,6 +23,7 @@ class TabViewModelsHolder @Inject constructor(
|
||||
private val authorViewModelProvider: Provider<AuthorViewModel>,
|
||||
private val changeDefaultUpstreamBranchViewModelProvider: Provider<ChangeDefaultUpstreamBranchViewModel>,
|
||||
private val submoduleDialogViewModelProvider: Provider<SubmoduleDialogViewModel>,
|
||||
private val signOffDialogViewModelProvider: Provider<SignOffDialogViewModel>,
|
||||
) {
|
||||
val viewModels = mapOf(
|
||||
logViewModel::class to logViewModel,
|
||||
@ -43,6 +44,7 @@ class TabViewModelsHolder @Inject constructor(
|
||||
AuthorViewModel::class -> authorViewModelProvider.get()
|
||||
ChangeDefaultUpstreamBranchViewModel::class -> changeDefaultUpstreamBranchViewModelProvider.get()
|
||||
SubmoduleDialogViewModel::class -> submoduleDialogViewModelProvider.get()
|
||||
SignOffDialogViewModel::class -> signOffDialogViewModelProvider.get()
|
||||
else -> throw NotImplementedError("View model provider not implemented")
|
||||
}
|
||||
}
|
||||
|
1
src/main/resources/sign.svg
Normal file
1
src/main/resources/sign.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><path d="M16.81,8.94l-3.75-3.75L4,14.25V18h3.75L16.81,8.94z M6,16v-0.92l7.06-7.06l0.92,0.92L6.92,16H6z"/><path d="M19.71,6.04c0.39-0.39,0.39-1.02,0-1.41l-2.34-2.34C17.17,2.09,16.92,2,16.66,2c-0.25,0-0.51,0.1-0.7,0.29l-1.83,1.83 l3.75,3.75L19.71,6.04z"/><rect height="4" width="20" x="2" y="20"/></g></g></svg>
|
After Width: | Height: | Size: 500 B |
Loading…
Reference in New Issue
Block a user