mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
257 lines
7.0 KiB
Go
257 lines
7.0 KiB
Go
package tui
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/AvengeMedia/DankMaterialShell/backend/internal/deps"
|
|
"github.com/AvengeMedia/DankMaterialShell/backend/internal/distros"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
)
|
|
|
|
func (m Model) viewDetectingDeps() string {
|
|
var b strings.Builder
|
|
|
|
b.WriteString(m.renderBanner())
|
|
b.WriteString("\n")
|
|
|
|
title := m.styles.Title.Render("Detecting Dependencies")
|
|
b.WriteString(title)
|
|
b.WriteString("\n\n")
|
|
|
|
spinner := m.spinner.View()
|
|
status := m.styles.Normal.Render("Scanning system for existing packages and configurations...")
|
|
b.WriteString(fmt.Sprintf("%s %s", spinner, status))
|
|
|
|
return b.String()
|
|
}
|
|
|
|
func (m Model) viewDependencyReview() string {
|
|
var b strings.Builder
|
|
|
|
b.WriteString(m.renderBanner())
|
|
b.WriteString("\n")
|
|
|
|
title := m.styles.Title.Render("Dependency Review")
|
|
b.WriteString(title)
|
|
b.WriteString("\n\n")
|
|
|
|
if len(m.dependencies) > 0 {
|
|
for i, dep := range m.dependencies {
|
|
var status string
|
|
var reinstallMarker string
|
|
var variantMarker string
|
|
|
|
isDMS := dep.Name == "dms (DankMaterialShell)"
|
|
|
|
if dep.CanToggle && dep.Variant == deps.VariantGit {
|
|
variantMarker = "[git] "
|
|
}
|
|
|
|
if m.disabledItems[dep.Name] {
|
|
reinstallMarker = "✗ "
|
|
status = m.styles.Subtle.Render("Will skip")
|
|
} else if m.reinstallItems[dep.Name] {
|
|
reinstallMarker = "🔄 "
|
|
status = m.styles.Warning.Render("Will upgrade")
|
|
} else if isDMS {
|
|
reinstallMarker = "⚡ "
|
|
switch dep.Status {
|
|
case deps.StatusInstalled:
|
|
status = m.styles.Success.Render("✓ Required (installed)")
|
|
case deps.StatusMissing:
|
|
status = m.styles.Warning.Render("○ Required (will install)")
|
|
case deps.StatusNeedsUpdate:
|
|
status = m.styles.Warning.Render("△ Required (needs update)")
|
|
case deps.StatusNeedsReinstall:
|
|
status = m.styles.Error.Render("! Required (needs reinstall)")
|
|
}
|
|
} else {
|
|
switch dep.Status {
|
|
case deps.StatusInstalled:
|
|
status = m.styles.Subtle.Render("✓ Already installed")
|
|
case deps.StatusMissing:
|
|
status = m.styles.Warning.Render("○ Will install")
|
|
case deps.StatusNeedsUpdate:
|
|
status = m.styles.Warning.Render("△ Will install")
|
|
case deps.StatusNeedsReinstall:
|
|
status = m.styles.Error.Render("! Will install")
|
|
}
|
|
}
|
|
|
|
var line string
|
|
if i == m.selectedDep {
|
|
line = fmt.Sprintf("▶ %s%s%-25s %s", reinstallMarker, variantMarker, dep.Name, status)
|
|
if dep.Version != "" {
|
|
line += fmt.Sprintf(" (%s)", dep.Version)
|
|
}
|
|
line = m.styles.SelectedOption.Render(line)
|
|
} else {
|
|
line = fmt.Sprintf(" %s%s%-25s %s", reinstallMarker, variantMarker, dep.Name, status)
|
|
if dep.Version != "" {
|
|
line += fmt.Sprintf(" (%s)", dep.Version)
|
|
}
|
|
line = m.styles.Normal.Render(line)
|
|
}
|
|
|
|
b.WriteString(line)
|
|
b.WriteString("\n")
|
|
}
|
|
}
|
|
|
|
b.WriteString("\n")
|
|
help := m.styles.Subtle.Render("↑/↓: Navigate, Space: Toggle, G: Toggle stable/git, Enter: Continue")
|
|
b.WriteString(help)
|
|
|
|
return b.String()
|
|
}
|
|
|
|
func (m Model) updateDetectingDepsState(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
if depsMsg, ok := msg.(depsDetectedMsg); ok {
|
|
m.isLoading = false
|
|
if depsMsg.err != nil {
|
|
m.err = depsMsg.err
|
|
m.state = StateError
|
|
} else {
|
|
m.dependencies = depsMsg.deps
|
|
m.state = StateDependencyReview
|
|
}
|
|
return m, m.listenForLogs()
|
|
}
|
|
return m, m.listenForLogs()
|
|
}
|
|
|
|
func (m Model) updateDependencyReviewState(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
if keyMsg, ok := msg.(tea.KeyMsg); ok {
|
|
switch keyMsg.String() {
|
|
case "up":
|
|
if m.selectedDep > 0 {
|
|
m.selectedDep--
|
|
}
|
|
case "down":
|
|
if m.selectedDep < len(m.dependencies)-1 {
|
|
m.selectedDep++
|
|
}
|
|
case " ":
|
|
if len(m.dependencies) > 0 {
|
|
depName := m.dependencies[m.selectedDep].Name
|
|
isDMS := depName == "dms (DankMaterialShell)"
|
|
|
|
if !isDMS {
|
|
isInstalled := m.dependencies[m.selectedDep].Status == deps.StatusInstalled ||
|
|
m.dependencies[m.selectedDep].Status == deps.StatusNeedsReinstall
|
|
|
|
if isInstalled {
|
|
m.reinstallItems[depName] = !m.reinstallItems[depName]
|
|
m.disabledItems[depName] = false
|
|
} else {
|
|
m.disabledItems[depName] = !m.disabledItems[depName]
|
|
m.reinstallItems[depName] = false
|
|
}
|
|
}
|
|
}
|
|
case "g", "G":
|
|
if len(m.dependencies) > 0 && m.dependencies[m.selectedDep].CanToggle {
|
|
if m.dependencies[m.selectedDep].Variant == deps.VariantStable {
|
|
m.dependencies[m.selectedDep].Variant = deps.VariantGit
|
|
} else {
|
|
m.dependencies[m.selectedDep].Variant = deps.VariantStable
|
|
}
|
|
}
|
|
case "enter":
|
|
// Check if on Gentoo - show USE flags screen
|
|
if m.osInfo != nil {
|
|
if config, exists := distros.Registry[m.osInfo.Distribution.ID]; exists && config.Family == distros.FamilyGentoo {
|
|
m.state = StateGentooUseFlags
|
|
return m, nil
|
|
}
|
|
}
|
|
// Check if fingerprint is enabled
|
|
if checkFingerprintEnabled() {
|
|
m.state = StateAuthMethodChoice
|
|
m.selectedConfig = 0 // Default to fingerprint
|
|
return m, nil
|
|
} else {
|
|
m.state = StatePasswordPrompt
|
|
m.passwordInput.Focus()
|
|
return m, nil
|
|
}
|
|
case "esc":
|
|
m.state = StateSelectWindowManager
|
|
return m, nil
|
|
}
|
|
}
|
|
return m, m.listenForLogs()
|
|
}
|
|
|
|
func (m Model) installPackages() tea.Cmd {
|
|
return func() tea.Msg {
|
|
if m.osInfo == nil {
|
|
return packageInstallProgressMsg{
|
|
progress: 0.0,
|
|
step: "Error: OS info not available",
|
|
isComplete: true,
|
|
}
|
|
}
|
|
|
|
installer, err := distros.NewPackageInstaller(m.osInfo.Distribution.ID, m.logChan)
|
|
if err != nil {
|
|
return packageInstallProgressMsg{
|
|
progress: 0.0,
|
|
step: fmt.Sprintf("Error: %s", err.Error()),
|
|
isComplete: true,
|
|
}
|
|
}
|
|
|
|
// Convert TUI selection to deps enum
|
|
var wm deps.WindowManager
|
|
if m.selectedWM == 0 {
|
|
wm = deps.WindowManagerNiri
|
|
} else {
|
|
wm = deps.WindowManagerHyprland
|
|
}
|
|
|
|
installerProgressChan := make(chan distros.InstallProgressMsg, 100)
|
|
|
|
go func() {
|
|
defer close(installerProgressChan)
|
|
err := installer.InstallPackages(context.Background(), m.dependencies, wm, m.sudoPassword, m.reinstallItems, m.disabledItems, m.skipGentooUseFlags, installerProgressChan)
|
|
if err != nil {
|
|
installerProgressChan <- distros.InstallProgressMsg{
|
|
Progress: 0.0,
|
|
Step: fmt.Sprintf("Installation error: %s", err.Error()),
|
|
IsComplete: true,
|
|
Error: err,
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Convert installer messages to TUI messages
|
|
go func() {
|
|
for msg := range installerProgressChan {
|
|
tuiMsg := packageInstallProgressMsg{
|
|
progress: msg.Progress,
|
|
step: msg.Step,
|
|
isComplete: msg.IsComplete,
|
|
needsSudo: msg.NeedsSudo,
|
|
commandInfo: msg.CommandInfo,
|
|
logOutput: msg.LogOutput,
|
|
error: msg.Error,
|
|
}
|
|
if msg.IsComplete {
|
|
m.logChan <- fmt.Sprintf("[DEBUG] Sending completion signal: step=%s, progress=%.2f", msg.Step, msg.Progress)
|
|
}
|
|
m.packageProgressChan <- tuiMsg
|
|
}
|
|
m.logChan <- "[DEBUG] Installer channel closed"
|
|
}()
|
|
|
|
return packageInstallProgressMsg{
|
|
progress: 0.05,
|
|
step: "Starting installation...",
|
|
isComplete: false,
|
|
}
|
|
}
|
|
}
|