summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui
diff options
context:
space:
mode:
authorNippy <nippy@rp1.hu>2026-05-09 13:33:09 +0200
committerNippy <nippy@rp1.hu>2026-05-09 13:33:09 +0200
commita2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5 (patch)
tree1a8769217f84bfe9d6216fafaadaf8cdd876d457 /raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui
parent34b9c34f982b2596cfa9e368a2d7f74e9a17477c (diff)
downloadRaveOS-PKGBUILD-a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5.tar.gz
RaveOS-PKGBUILD-a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5.zip
raveos update
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui')
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/app.go240
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/banner.go21
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/messages.go39
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/states.go22
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/styles.go124
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_config.go382
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_dependencies.go304
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_gcc.go103
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_use_flags.go92
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_install.go405
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_password.go338
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_selection.go224
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_welcome.go216
13 files changed, 0 insertions, 2510 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/app.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/app.go
deleted file mode 100644
index d07430a..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/app.go
+++ /dev/null
@@ -1,240 +0,0 @@
-package tui
-
-import (
- "github.com/AvengeMedia/DankMaterialShell/core/internal/deps"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/distros"
- "github.com/charmbracelet/bubbles/spinner"
- "github.com/charmbracelet/bubbles/textinput"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-type Model struct {
- version string
- state ApplicationState
-
- osInfo *distros.OSInfo
- dependencies []deps.Dependency
- err error
-
- spinner spinner.Model
- passwordInput textinput.Model
- width int
- height int
- isLoading bool
- styles Styles
-
- logMessages []string
- logChan chan string
- logFilePath string
- packageProgressChan chan packageInstallProgressMsg
- packageProgress packageInstallProgressMsg
- installationLogs []string
- showDebugLogs bool
-
- selectedWM int
- selectedTerminal int
- selectedDep int
- selectedConfig int
- reinstallItems map[string]bool
- disabledItems map[string]bool
- replaceConfigs map[string]bool
- skipGentooUseFlags bool
- sudoPassword string
- existingConfigs []ExistingConfigInfo
- fingerprintFailed bool
-}
-
-func NewModel(version string, logFilePath string) Model {
- s := spinner.New()
- s.Spinner = spinner.Dot
-
- theme := TerminalTheme()
- styles := NewStyles(theme)
- s.Style = styles.SpinnerStyle
-
- pi := textinput.New()
- pi.Placeholder = "Enter sudo password"
- pi.EchoMode = textinput.EchoPassword
- pi.EchoCharacter = '•'
- pi.Focus()
-
- logChan := make(chan string, 1000)
- packageProgressChan := make(chan packageInstallProgressMsg, 100)
-
- return Model{
- version: version,
- state: StateWelcome,
- spinner: s,
- passwordInput: pi,
- isLoading: true,
- styles: styles,
-
- logMessages: []string{},
- logChan: logChan,
- logFilePath: logFilePath,
- packageProgressChan: packageProgressChan,
- packageProgress: packageInstallProgressMsg{
- progress: 0.0,
- step: "Initializing package installation",
- isComplete: false,
- },
- showDebugLogs: false,
- selectedWM: 0,
- selectedTerminal: 0, // Default to Ghostty
- selectedDep: 0,
- selectedConfig: 0,
- reinstallItems: make(map[string]bool),
- disabledItems: make(map[string]bool),
- replaceConfigs: make(map[string]bool),
- installationLogs: []string{},
- }
-}
-
-func (m Model) GetLogChan() <-chan string {
- return m.logChan
-}
-
-func (m Model) Init() tea.Cmd {
- return tea.Batch(
- m.spinner.Tick,
- m.listenForLogs(),
- m.detectOS(),
- )
-}
-
-func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "ctrl+c":
- return m, tea.Quit
- case "ctrl+d":
- // Toggle debug logs view (except during password input states)
- if m.state != StatePasswordPrompt && m.state != StateFingerprintAuth {
- m.showDebugLogs = !m.showDebugLogs
- return m, nil
- }
- }
- }
-
- if tickMsg, ok := msg.(spinner.TickMsg); ok {
- var cmd tea.Cmd
- m.spinner, cmd = m.spinner.Update(tickMsg)
- return m, tea.Batch(cmd, m.listenForLogs())
- }
-
- if sizeMsg, ok := msg.(tea.WindowSizeMsg); ok {
- m.width = sizeMsg.Width
- m.height = sizeMsg.Height
- }
-
- if logMsg, ok := msg.(logMsg); ok {
- m.logMessages = append(m.logMessages, logMsg.message)
- return m, m.listenForLogs()
- }
-
- switch m.state {
- case StateWelcome:
- return m.updateWelcomeState(msg)
- case StateSelectWindowManager:
- return m.updateSelectWindowManagerState(msg)
- case StateSelectTerminal:
- return m.updateSelectTerminalState(msg)
- case StateDetectingDeps:
- return m.updateDetectingDepsState(msg)
- case StateDependencyReview:
- return m.updateDependencyReviewState(msg)
- case StateGentooUseFlags:
- return m.updateGentooUseFlagsState(msg)
- case StateGentooGCCCheck:
- return m.updateGentooGCCCheckState(msg)
- case StateAuthMethodChoice:
- return m.updateAuthMethodChoiceState(msg)
- case StateFingerprintAuth:
- return m.updateFingerprintAuthState(msg)
- case StatePasswordPrompt:
- return m.updatePasswordPromptState(msg)
- case StateInstallingPackages:
- return m.updateInstallingPackagesState(msg)
- case StateConfigConfirmation:
- return m.updateConfigConfirmationState(msg)
- case StateDeployingConfigs:
- return m.updateDeployingConfigsState(msg)
- case StateInstallComplete:
- return m.updateInstallCompleteState(msg)
- case StateError:
- return m.updateErrorState(msg)
- default:
- return m, m.listenForLogs()
- }
-}
-
-func (m Model) View() string {
- // If debug logs are shown, show that view regardless of state
- if m.showDebugLogs {
- return m.viewDebugLogs()
- }
-
- switch m.state {
- case StateWelcome:
- return m.viewWelcome()
- case StateSelectWindowManager:
- return m.viewSelectWindowManager()
- case StateSelectTerminal:
- return m.viewSelectTerminal()
- case StateDetectingDeps:
- return m.viewDetectingDeps()
- case StateDependencyReview:
- return m.viewDependencyReview()
- case StateGentooUseFlags:
- return m.viewGentooUseFlags()
- case StateGentooGCCCheck:
- return m.viewGentooGCCCheck()
- case StateAuthMethodChoice:
- return m.viewAuthMethodChoice()
- case StateFingerprintAuth:
- return m.viewFingerprintAuth()
- case StatePasswordPrompt:
- return m.viewPasswordPrompt()
- case StateInstallingPackages:
- return m.viewInstallingPackages()
- case StateConfigConfirmation:
- return m.viewConfigConfirmation()
- case StateDeployingConfigs:
- return m.viewDeployingConfigs()
- case StateInstallComplete:
- return m.viewInstallComplete()
- case StateError:
- return m.viewError()
- default:
- return m.viewWelcome()
- }
-}
-
-func (m Model) listenForLogs() tea.Cmd {
- return func() tea.Msg {
- select {
- case msg, ok := <-m.logChan:
- if !ok {
- return nil
- }
- return logMsg{message: msg}
- default:
- return nil
- }
- }
-}
-
-func (m Model) detectOS() tea.Cmd {
- return func() tea.Msg {
- info, err := distros.GetOSInfo()
- osInfoMsg := &distros.OSInfo{}
- if info != nil {
- osInfoMsg.Distribution = info.Distribution
- osInfoMsg.Version = info.Version
- osInfoMsg.VersionID = info.VersionID
- osInfoMsg.PrettyName = info.PrettyName
- osInfoMsg.Architecture = info.Architecture
- }
- return osInfoCompleteMsg{info: osInfoMsg, err: err}
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/banner.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/banner.go
deleted file mode 100644
index e3a2ca3..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/banner.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package tui
-
-import "github.com/charmbracelet/lipgloss"
-
-func (m Model) renderBanner() string {
- logo := `
-██████╗ █████╗ ███╗ ██╗██╗ ██╗
-██╔══██╗██╔══██╗████╗ ██║██║ ██╔╝
-██║ ██║███████║██╔██╗ ██║█████╔╝
-██║ ██║██╔══██║██║╚██╗██║██╔═██╗
-██████╔╝██║ ██║██║ ╚████║██║ ██╗
-╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ `
-
- theme := TerminalTheme()
- style := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- MarginBottom(1)
-
- return style.Render(logo)
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/messages.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/messages.go
deleted file mode 100644
index 7c03098..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/messages.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package tui
-
-import (
- "github.com/AvengeMedia/DankMaterialShell/core/internal/deps"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/distros"
-)
-
-type logMsg struct {
- message string
-}
-
-type osInfoCompleteMsg struct {
- info *distros.OSInfo
- err error
-}
-
-type depsDetectedMsg struct {
- deps []deps.Dependency
- err error
-}
-
-type packageInstallProgressMsg struct {
- progress float64
- step string
- isComplete bool
- needsSudo bool
- commandInfo string
- logOutput string
- error error
-}
-
-type packageProgressCompletedMsg struct{}
-
-type passwordValidMsg struct {
- password string
- valid bool
-}
-
-type delayCompleteMsg struct{}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/states.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/states.go
deleted file mode 100644
index 6e9e194..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/states.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package tui
-
-type ApplicationState int
-
-const (
- StateWelcome ApplicationState = iota
- StateSelectWindowManager
- StateSelectTerminal
- StateDetectingDeps
- StateDependencyReview
- StateGentooUseFlags
- StateGentooGCCCheck
- StateAuthMethodChoice
- StateFingerprintAuth
- StatePasswordPrompt
- StateInstallingPackages
- StateConfigConfirmation
- StateDeployingConfigs
- StateInstallComplete
- StateFinalComplete
- StateError
-)
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/styles.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/styles.go
deleted file mode 100644
index 45a9dae..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/styles.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package tui
-
-import (
- "github.com/charmbracelet/bubbles/progress"
- "github.com/charmbracelet/lipgloss"
-)
-
-type AppTheme struct {
- Primary string
- Secondary string
- Accent string
- Text string
- Subtle string
- Error string
- Warning string
- Success string
- Background string
- Surface string
-}
-
-func TerminalTheme() AppTheme {
- return AppTheme{
- Primary: "6", // #625690 - purple
- Secondary: "5", // #36247a - dark purple
- Accent: "12", // #7060ac - light purple
- Text: "7", // #2e2e2e - dark gray
- Subtle: "8", // #4a4a4a - medium gray
- Error: "1", // #d83636 - red
- Warning: "3", // #ffff89 - yellow
- Success: "2", // #53e550 - green
- Background: "15", // #1a1a1a - near black
- Surface: "8", // #4a4a4a - medium gray
- }
-}
-
-func NewStyles(theme AppTheme) Styles {
- return Styles{
- Title: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- MarginLeft(1).
- MarginBottom(1),
-
- Normal: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Text)),
-
- Bold: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Text)).
- Bold(true),
-
- Subtle: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Subtle)),
-
- Error: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Error)),
-
- Warning: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Warning)),
-
- StatusBar: lipgloss.NewStyle().
- Foreground(lipgloss.Color("#33275e")).
- Background(lipgloss.Color(theme.Primary)).
- Padding(0, 1),
-
- Key: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent)).
- Bold(true),
-
- SpinnerStyle: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)),
-
- Success: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Success)).
- Bold(true),
-
- HighlightButton: lipgloss.NewStyle().
- Foreground(lipgloss.Color("#33275e")).
- Background(lipgloss.Color(theme.Primary)).
- Padding(0, 2).
- Bold(true),
-
- SelectedOption: lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent)).
- Bold(true),
-
- CodeBlock: lipgloss.NewStyle().
- Background(lipgloss.Color(theme.Surface)).
- Foreground(lipgloss.Color(theme.Text)).
- Padding(1, 2).
- MarginLeft(2),
- }
-}
-
-type Styles struct {
- Title lipgloss.Style
- Normal lipgloss.Style
- Bold lipgloss.Style
- Subtle lipgloss.Style
- Warning lipgloss.Style
- Error lipgloss.Style
- StatusBar lipgloss.Style
- Key lipgloss.Style
- SpinnerStyle lipgloss.Style
- Success lipgloss.Style
- HighlightButton lipgloss.Style
- SelectedOption lipgloss.Style
- CodeBlock lipgloss.Style
-}
-
-func (s Styles) NewThemedProgress(width int) progress.Model {
- theme := TerminalTheme()
- prog := progress.New(
- progress.WithGradient(theme.Secondary, theme.Primary),
- )
-
- prog.Width = width
- prog.ShowPercentage = true
- prog.PercentFormat = "%.0f%%"
- prog.PercentageStyle = lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Text)).
- Bold(true)
-
- return prog
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_config.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_config.go
deleted file mode 100644
index 14daff3..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_config.go
+++ /dev/null
@@ -1,382 +0,0 @@
-package tui
-
-import (
- "context"
- "fmt"
- "os"
- "path/filepath"
- "strings"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/config"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/deps"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-type configDeploymentResult struct {
- results []config.DeploymentResult
- error error
-}
-
-type ExistingConfigInfo struct {
- ConfigType string
- Path string
- Exists bool
-}
-
-type configCheckResult struct {
- configs []ExistingConfigInfo
- error error
-}
-
-func (m Model) viewDeployingConfigs() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Deploying Configurations")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- spinner := m.spinner.View()
- status := m.styles.Normal.Render("Setting up configuration files...")
- fmt.Fprintf(&b, "%s %s", spinner, status)
- b.WriteString("\n\n")
-
- // Show progress information
- info := m.styles.Subtle.Render("• Creating backups of existing configurations\n• Deploying optimized configurations\n• Detecting system paths")
- b.WriteString(info)
-
- // Show live log output if available
- if len(m.installationLogs) > 0 {
- b.WriteString("\n\n")
- logHeader := m.styles.Subtle.Render("Configuration Log:")
- b.WriteString(logHeader)
- b.WriteString("\n")
-
- // Show last few lines of logs
- maxLines := 5
- startIdx := 0
- if len(m.installationLogs) > maxLines {
- startIdx = len(m.installationLogs) - maxLines
- }
-
- for i := startIdx; i < len(m.installationLogs); i++ {
- if m.installationLogs[i] != "" {
- logLine := m.styles.Subtle.Render(" " + m.installationLogs[i])
- b.WriteString(logLine)
- b.WriteString("\n")
- }
- }
- }
-
- return b.String()
-}
-
-func (m Model) updateDeployingConfigsState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if result, ok := msg.(configDeploymentResult); ok {
- if result.error != nil {
- m.err = result.error
- m.state = StateError
- m.isLoading = false
- return m, nil
- }
-
- for _, deployResult := range result.results {
- if deployResult.Deployed {
- logMsg := fmt.Sprintf("✓ %s configuration deployed", deployResult.ConfigType)
- if deployResult.BackupPath != "" {
- logMsg += fmt.Sprintf(" (backup: %s)", deployResult.BackupPath)
- }
- m.installationLogs = append(m.installationLogs, logMsg)
- }
- }
-
- m.state = StateInstallComplete
- m.isLoading = false
- return m, nil
- }
-
- return m, m.listenForLogs()
-}
-
-func (m Model) deployConfigurations() tea.Cmd {
- return func() tea.Msg {
- // Determine the selected window manager
- var wm deps.WindowManager
- switch m.selectedWM {
- case 0:
- wm = deps.WindowManagerNiri
- case 1:
- wm = deps.WindowManagerHyprland
- default:
- wm = deps.WindowManagerNiri
- }
-
- // Determine the selected terminal
- var terminal deps.Terminal
- if m.osInfo != nil && m.osInfo.Distribution.ID == "gentoo" {
- switch m.selectedTerminal {
- case 0:
- terminal = deps.TerminalKitty
- case 1:
- terminal = deps.TerminalAlacritty
- default:
- terminal = deps.TerminalKitty
- }
- } else {
- switch m.selectedTerminal {
- case 0:
- terminal = deps.TerminalGhostty
- case 1:
- terminal = deps.TerminalKitty
- default:
- terminal = deps.TerminalAlacritty
- }
- }
-
- deployer := config.NewConfigDeployer(m.logChan)
-
- results, err := deployer.DeployConfigurationsSelectiveWithReinstalls(context.Background(), wm, terminal, m.dependencies, m.replaceConfigs, m.reinstallItems)
-
- return configDeploymentResult{
- results: results,
- error: err,
- }
- }
-}
-
-func (m Model) viewConfigConfirmation() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Configuration Deployment")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- if len(m.existingConfigs) == 0 {
- // No existing configs, proceed directly
- info := m.styles.Normal.Render("No existing configurations found. Proceeding with deployment...")
- b.WriteString(info)
- return b.String()
- }
-
- // Show existing configurations with toggle options
- for i, configInfo := range m.existingConfigs {
- if configInfo.Exists {
- var status string
- var replaceMarker string
-
- shouldReplace := m.replaceConfigs[configInfo.ConfigType]
- if _, exists := m.replaceConfigs[configInfo.ConfigType]; !exists {
- shouldReplace = true
- m.replaceConfigs[configInfo.ConfigType] = true
- }
-
- if shouldReplace {
- replaceMarker = "🔄 "
- status = m.styles.Warning.Render("Will replace")
- } else {
- replaceMarker = "✓ "
- status = m.styles.Success.Render("Keep existing")
- }
-
- var line string
- if i == m.selectedConfig {
- line = fmt.Sprintf("▶ %s%-15s %s", replaceMarker, configInfo.ConfigType, status)
- line += fmt.Sprintf("\n %s", configInfo.Path)
- line = m.styles.SelectedOption.Render(line)
- } else {
- line = fmt.Sprintf(" %s%-15s %s", replaceMarker, configInfo.ConfigType, status)
- line += fmt.Sprintf("\n %s", configInfo.Path)
- line = m.styles.Normal.Render(line)
- }
-
- b.WriteString(line)
- b.WriteString("\n\n")
- }
- }
-
- backup := m.styles.Success.Render("✓ Replaced configurations will be backed up with timestamp")
- b.WriteString(backup)
- b.WriteString("\n\n")
-
- help := m.styles.Subtle.Render("↑/↓: Navigate, Space: Toggle replace/keep, Enter: Continue")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateConfigConfirmationState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if result, ok := msg.(configCheckResult); ok {
- if result.error != nil {
- m.err = result.error
- m.state = StateError
- return m, nil
- }
-
- m.existingConfigs = result.configs
-
- firstExistingSet := false
- for i, config := range result.configs {
- if config.Exists {
- m.replaceConfigs[config.ConfigType] = true
- if !firstExistingSet {
- m.selectedConfig = i
- firstExistingSet = true
- }
- }
- }
-
- hasExisting := false
- for _, config := range result.configs {
- if config.Exists {
- hasExisting = true
- break
- }
- }
-
- if !hasExisting {
- // No existing configs, proceed directly to deployment
- m.state = StateDeployingConfigs
- return m, m.deployConfigurations()
- }
-
- // Show confirmation view
- return m, nil
- }
-
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "up":
- if m.selectedConfig > 0 {
- for i := m.selectedConfig - 1; i >= 0; i-- {
- if m.existingConfigs[i].Exists {
- m.selectedConfig = i
- break
- }
- }
- }
- case "down":
- if m.selectedConfig < len(m.existingConfigs)-1 {
- for i := m.selectedConfig + 1; i < len(m.existingConfigs); i++ {
- if m.existingConfigs[i].Exists {
- m.selectedConfig = i
- break
- }
- }
- }
- case " ":
- if len(m.existingConfigs) > 0 && m.selectedConfig < len(m.existingConfigs) {
- configType := m.existingConfigs[m.selectedConfig].ConfigType
- if m.existingConfigs[m.selectedConfig].Exists {
- m.replaceConfigs[configType] = !m.replaceConfigs[configType]
- }
- }
- case "enter":
- m.state = StateDeployingConfigs
- return m, m.deployConfigurations()
- }
- }
-
- return m, nil
-}
-
-func (m Model) checkExistingConfigurations() tea.Cmd {
- return func() tea.Msg {
- var configs []ExistingConfigInfo
-
- if m.selectedWM == 0 {
- niriPath := filepath.Join(os.Getenv("HOME"), ".config", "niri", "config.kdl")
- niriExists := false
- if _, err := os.Stat(niriPath); err == nil {
- niriExists = true
- }
- configs = append(configs, ExistingConfigInfo{
- ConfigType: "Niri",
- Path: niriPath,
- Exists: niriExists,
- })
- } else {
- hyprlandPath := filepath.Join(os.Getenv("HOME"), ".config", "hypr", "hyprland.conf")
- hyprlandExists := false
- if _, err := os.Stat(hyprlandPath); err == nil {
- hyprlandExists = true
- }
- configs = append(configs, ExistingConfigInfo{
- ConfigType: "Hyprland",
- Path: hyprlandPath,
- Exists: hyprlandExists,
- })
- }
-
- if m.osInfo != nil && m.osInfo.Distribution.ID == "gentoo" {
- if m.selectedTerminal == 0 {
- kittyPath := filepath.Join(os.Getenv("HOME"), ".config", "kitty", "kitty.conf")
- kittyExists := false
- if _, err := os.Stat(kittyPath); err == nil {
- kittyExists = true
- }
- configs = append(configs, ExistingConfigInfo{
- ConfigType: "Kitty",
- Path: kittyPath,
- Exists: kittyExists,
- })
- } else {
- alacrittyPath := filepath.Join(os.Getenv("HOME"), ".config", "alacritty", "alacritty.toml")
- alacrittyExists := false
- if _, err := os.Stat(alacrittyPath); err == nil {
- alacrittyExists = true
- }
- configs = append(configs, ExistingConfigInfo{
- ConfigType: "Alacritty",
- Path: alacrittyPath,
- Exists: alacrittyExists,
- })
- }
- } else {
- switch m.selectedTerminal {
- case 0:
- ghosttyPath := filepath.Join(os.Getenv("HOME"), ".config", "ghostty", "config")
- ghosttyExists := false
- if _, err := os.Stat(ghosttyPath); err == nil {
- ghosttyExists = true
- }
- configs = append(configs, ExistingConfigInfo{
- ConfigType: "Ghostty",
- Path: ghosttyPath,
- Exists: ghosttyExists,
- })
- case 1:
- kittyPath := filepath.Join(os.Getenv("HOME"), ".config", "kitty", "kitty.conf")
- kittyExists := false
- if _, err := os.Stat(kittyPath); err == nil {
- kittyExists = true
- }
- configs = append(configs, ExistingConfigInfo{
- ConfigType: "Kitty",
- Path: kittyPath,
- Exists: kittyExists,
- })
- default:
- alacrittyPath := filepath.Join(os.Getenv("HOME"), ".config", "alacritty", "alacritty.toml")
- alacrittyExists := false
- if _, err := os.Stat(alacrittyPath); err == nil {
- alacrittyExists = true
- }
- configs = append(configs, ExistingConfigInfo{
- ConfigType: "Alacritty",
- Path: alacrittyPath,
- Exists: alacrittyExists,
- })
- }
- }
-
- return configCheckResult{
- configs: configs,
- error: nil,
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_dependencies.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_dependencies.go
deleted file mode 100644
index 13f0335..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_dependencies.go
+++ /dev/null
@@ -1,304 +0,0 @@
-package tui
-
-import (
- "context"
- "fmt"
- "strings"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/deps"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/distros"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/greeter"
- 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...")
- fmt.Fprintf(&b, "%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")
- }
- }
-
- note := ""
- if dep.Name == "dms-greeter" {
- note = m.styles.Subtle.Render(" (selection replaces your current display manager)")
- }
-
- 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) + note
- } 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) + note
- }
-
- 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
- // dms-greeter is opt-in skipped by default
- for _, dep := range depsMsg.deps {
- if dep.Name == "dms-greeter" {
- m.disabledItems["dms-greeter"] = true
- break
- }
- }
- 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 {
- // Run optional greeter setup
- if msg.Phase == distros.PhaseComplete && msg.IsComplete && msg.Error == nil {
- greeterSelected := false
- for _, dep := range m.dependencies {
- if dep.Name == "dms-greeter" && !m.disabledItems["dms-greeter"] {
- greeterSelected = true
- break
- }
- }
- if greeterSelected {
- compositorName := "niri"
- if m.selectedWM == 1 {
- compositorName = "Hyprland"
- }
- m.packageProgressChan <- packageInstallProgressMsg{
- progress: 0.92,
- step: "Configuring DMS greeter...",
- logOutput: "Starting automated greeter setup...",
- }
- greeterLogFunc := func(line string) {
- m.packageProgressChan <- packageInstallProgressMsg{
- progress: 0.94,
- step: "Configuring DMS greeter...",
- logOutput: line,
- }
- }
- if err := greeter.AutoSetupGreeter(compositorName, m.sudoPassword, greeterLogFunc); err != nil {
- m.packageProgressChan <- packageInstallProgressMsg{
- progress: 0.96,
- step: "Greeter setup warning",
- logOutput: fmt.Sprintf("⚠ Greeter auto-setup warning (non-fatal): %v", err),
- }
- }
- }
- }
- 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,
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_gcc.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_gcc.go
deleted file mode 100644
index 74195a4..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_gcc.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package tui
-
-import (
- "context"
- "fmt"
- "os/exec"
- "strconv"
- "strings"
-
- tea "github.com/charmbracelet/bubbletea"
-)
-
-type gccVersionCheckMsg struct {
- version string
- major int
- err error
-}
-
-func (m Model) viewGentooGCCCheck() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("GCC Version Check Failed")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- error := m.styles.Error.Render("⚠ Hyprland requires GCC 15 or newer")
- b.WriteString(error)
- b.WriteString("\n\n")
-
- info := m.styles.Normal.Render("Your current GCC version is too old. Please upgrade GCC before continuing.")
- b.WriteString(info)
- b.WriteString("\n\n")
-
- instructionsTitle := m.styles.Subtle.Render("To upgrade GCC:")
- b.WriteString(instructionsTitle)
- b.WriteString("\n\n")
-
- steps := []string{
- "1. Install GCC 15 (if not already installed):",
- " sudo emerge -1av =sys-devel/gcc:15",
- "",
- "2. Switch to GCC 15 using gcc-config:",
- " sudo gcc-config $(gcc-config -l | grep gcc-15 | awk '{print $2}' | head -1)",
- "",
- "3. Update environment:",
- " source /etc/profile",
- "",
- "4. Restart this installer",
- }
-
- for _, step := range steps {
- stepLine := m.styles.Subtle.Render(step)
- b.WriteString(stepLine)
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- help := m.styles.Subtle.Render("Press Esc to go back, Ctrl+C to exit")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateGentooGCCCheckState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "esc":
- m.state = StateSelectWindowManager
- return m, nil
- }
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) checkGCCVersion() tea.Cmd {
- return func() tea.Msg {
- cmd := exec.CommandContext(context.Background(), "gcc", "-dumpversion")
- output, err := cmd.Output()
- if err != nil {
- return gccVersionCheckMsg{err: err}
- }
-
- version := strings.TrimSpace(string(output))
- parts := strings.Split(version, ".")
- if len(parts) == 0 {
- return gccVersionCheckMsg{err: fmt.Errorf("invalid gcc version format")}
- }
-
- major, err := strconv.Atoi(parts[0])
- if err != nil {
- return gccVersionCheckMsg{err: err}
- }
-
- return gccVersionCheckMsg{
- version: version,
- major: major,
- err: nil,
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_use_flags.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_use_flags.go
deleted file mode 100644
index eb259ef..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_gentoo_use_flags.go
+++ /dev/null
@@ -1,92 +0,0 @@
-package tui
-
-import (
- "fmt"
- "strings"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/distros"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-func (m Model) viewGentooUseFlags() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Gentoo Global USE Flags")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- info := m.styles.Normal.Render("The following global USE flags will be enabled in /etc/portage/make.conf:")
- b.WriteString(info)
- b.WriteString("\n\n")
-
- for _, flag := range distros.GentooGlobalUseFlags {
- flagLine := m.styles.Success.Render(fmt.Sprintf(" • %s", flag))
- b.WriteString(flagLine)
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- note := m.styles.Subtle.Render("These flags ensure proper Qt6, Wayland, and compositor support.")
- b.WriteString(note)
- b.WriteString("\n\n")
-
- var toggleLine string
- if m.skipGentooUseFlags {
- toggleLine = "▶ [✗] Skip adding global USE flags (will use existing configuration)"
- toggleLine = m.styles.Warning.Render(toggleLine)
- } else {
- toggleLine = " [ ] Skip adding global USE flags (will use existing configuration)"
- toggleLine = m.styles.Subtle.Render(toggleLine)
- }
- b.WriteString(toggleLine)
- b.WriteString("\n\n")
-
- help := m.styles.Subtle.Render("Space: Toggle skip, Enter: Continue, Esc: Go back")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateGentooUseFlagsState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if gccMsg, ok := msg.(gccVersionCheckMsg); ok {
- if gccMsg.err != nil || gccMsg.major < 15 {
- m.state = StateGentooGCCCheck
- return m, nil
- }
- if checkFingerprintEnabled() {
- m.state = StateAuthMethodChoice
- m.selectedConfig = 0
- } else {
- m.state = StatePasswordPrompt
- m.passwordInput.Focus()
- }
- return m, nil
- }
-
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case " ":
- m.skipGentooUseFlags = !m.skipGentooUseFlags
- return m, nil
- case "enter":
- if m.selectedWM == 1 {
- return m, m.checkGCCVersion()
- }
- if checkFingerprintEnabled() {
- m.state = StateAuthMethodChoice
- m.selectedConfig = 0
- } else {
- m.state = StatePasswordPrompt
- m.passwordInput.Focus()
- }
- return m, nil
- case "esc":
- m.state = StateDependencyReview
- return m, nil
- }
- }
- return m, m.listenForLogs()
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_install.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_install.go
deleted file mode 100644
index c110711..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_install.go
+++ /dev/null
@@ -1,405 +0,0 @@
-package tui
-
-import (
- "fmt"
- "strings"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/deps"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/distros"
- tea "github.com/charmbracelet/bubbletea"
- "github.com/charmbracelet/lipgloss"
-)
-
-// wrapText wraps text to the specified width
-func wrapText(text string, width int) string {
- if len(text) <= width {
- return text
- }
-
- var result strings.Builder
- words := strings.Fields(text)
- currentLine := ""
-
- for _, word := range words {
- if len(currentLine) == 0 {
- currentLine = word
- } else if len(currentLine)+1+len(word) <= width {
- currentLine += " " + word
- } else {
- result.WriteString(currentLine)
- result.WriteString("\n")
- currentLine = word
- }
- }
-
- if len(currentLine) > 0 {
- result.WriteString(currentLine)
- }
-
- return result.String()
-}
-
-func (m Model) viewInstallingPackages() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Installing Packages")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- if !m.packageProgress.isComplete {
- spinner := m.spinner.View()
- status := m.styles.Normal.Render(m.packageProgress.step)
- fmt.Fprintf(&b, "%s %s", spinner, status)
- b.WriteString("\n\n")
-
- // Show progress bar
- progressBar := fmt.Sprintf("[%s%s] %.0f%%",
- strings.Repeat("█", int(m.packageProgress.progress*30)),
- strings.Repeat("░", 30-int(m.packageProgress.progress*30)),
- m.packageProgress.progress*100)
- b.WriteString(m.styles.Normal.Render(progressBar))
- b.WriteString("\n")
-
- // Show command info if available
- if m.packageProgress.commandInfo != "" {
- cmdInfo := m.styles.Subtle.Render("$ " + m.packageProgress.commandInfo)
- b.WriteString(cmdInfo)
- b.WriteString("\n")
- }
-
- // Show live log output
- if len(m.installationLogs) > 0 {
- b.WriteString("\n")
- logHeader := m.styles.Subtle.Render("Live Output:")
- b.WriteString(logHeader)
- b.WriteString("\n")
-
- // Show last few lines of accumulated logs
- maxLines := 8
- startIdx := 0
- if len(m.installationLogs) > maxLines {
- startIdx = len(m.installationLogs) - maxLines
- }
-
- for i := startIdx; i < len(m.installationLogs); i++ {
- if m.installationLogs[i] != "" {
- logLine := m.styles.Subtle.Render(" " + m.installationLogs[i])
- b.WriteString(logLine)
- b.WriteString("\n")
- }
- }
- }
-
- // Show error if any
- if m.packageProgress.error != nil {
- b.WriteString("\n")
- wrappedErrorMsg := wrapText("Error: "+m.packageProgress.error.Error(), 80)
- errorMsg := m.styles.Error.Render(wrappedErrorMsg)
- b.WriteString(errorMsg)
- }
-
- // Show sudo prompt if needed
- if m.packageProgress.needsSudo {
- sudoWarning := m.styles.Warning.Render("⚠ Using provided sudo password")
- b.WriteString(sudoWarning)
- }
- } else {
- if m.packageProgress.error != nil {
- wrappedFailedMsg := wrapText("✗ Installation failed: "+m.packageProgress.error.Error(), 80)
- errorMsg := m.styles.Error.Render(wrappedFailedMsg)
- b.WriteString(errorMsg)
- } else {
- success := m.styles.Success.Render("✓ Installation complete!")
- b.WriteString(success)
- }
- }
-
- return b.String()
-}
-
-func dmsPackageName(distroID string, dependencies []deps.Dependency) string {
- config, ok := distros.Registry[distroID]
- if !ok {
- return "dms"
- }
-
- var isGit bool
- for _, dep := range dependencies {
- if dep.Name == "dms (DankMaterialShell)" {
- isGit = dep.Variant == deps.VariantGit
- break
- }
- }
-
- switch config.Family {
- case distros.FamilyArch:
- if isGit {
- return "dms-shell-git"
- }
- return "dms-shell"
- case distros.FamilyFedora, distros.FamilyUbuntu, distros.FamilyDebian, distros.FamilySUSE:
- if isGit {
- return "dms-git"
- }
- return "dms"
- default:
- return "dms"
- }
-}
-
-func uninstallCommand(distroID string, dependencies []deps.Dependency) string {
- config, ok := distros.Registry[distroID]
- if !ok {
- return ""
- }
- if config.Family == distros.FamilyGentoo {
- return "rm -rf ~/.config/quickshell/dms && sudo rm /usr/local/bin/dms"
- }
- pkg := dmsPackageName(distroID, dependencies)
- switch config.Family {
- case distros.FamilyArch:
- return "sudo pacman -Rs " + pkg
- case distros.FamilyFedora:
- return "sudo dnf remove " + pkg
- case distros.FamilyUbuntu, distros.FamilyDebian:
- return "sudo apt remove " + pkg
- case distros.FamilySUSE:
- return "sudo zypper remove " + pkg
- default:
- return ""
- }
-}
-
-func (m Model) viewInstallComplete() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Success.Render("Setup Complete!")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- success := m.styles.Success.Render("✓ All packages installed and configurations deployed.")
- b.WriteString(success)
- b.WriteString("\n\n")
-
- accomplishments := []string{
- "• Window manager and dependencies installed",
- "• Terminal and development tools configured",
- "• Configuration files deployed with backups",
- "• System optimized for DankMaterialShell",
- }
-
- for _, item := range accomplishments {
- b.WriteString(m.styles.Subtle.Render(item))
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- info := m.styles.Normal.Render("Your system is ready! Log out and log back in to start using\nyour new desktop environment.\nIf you do not have a greeter, login with \"niri-session\" or \"Hyprland\"")
- b.WriteString(info)
- b.WriteString("\n\n")
-
- theme := TerminalTheme()
- cmdStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(theme.Accent))
- labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(theme.Subtle))
-
- b.WriteString(labelStyle.Render("Troubleshooting:") + "\n")
- b.WriteString(labelStyle.Render(" Disable autostart: ") + cmdStyle.Render("systemctl --user disable dms") + "\n")
- b.WriteString(labelStyle.Render(" View logs: ") + cmdStyle.Render("journalctl --user -u dms") + "\n")
-
- if m.osInfo != nil {
- if cmd := uninstallCommand(m.osInfo.Distribution.ID, m.dependencies); cmd != "" {
- b.WriteString(labelStyle.Render(" Uninstall: ") + cmdStyle.Render(cmd) + "\n")
- }
- }
-
- b.WriteString("\n")
- b.WriteString(m.styles.Normal.Render("Press Enter to exit."))
-
- if m.logFilePath != "" {
- b.WriteString("\n\n")
- logInfo := m.styles.Subtle.Render(fmt.Sprintf("Full logs: %s", m.logFilePath))
- b.WriteString(logInfo)
- }
-
- return b.String()
-}
-
-func (m Model) viewError() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Error.Render("Installation Failed")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- if m.err != nil {
- wrappedError := wrapText("✗ "+m.err.Error(), 80)
- error := m.styles.Error.Render(wrappedError)
- b.WriteString(error)
- b.WriteString("\n\n")
- }
-
- // Show package progress error if available
- if m.packageProgress.error != nil {
- wrappedPackageError := wrapText("Package Installation Error: "+m.packageProgress.error.Error(), 80)
- packageError := m.styles.Error.Render(wrappedPackageError)
- b.WriteString(packageError)
- b.WriteString("\n\n")
- }
-
- // Show persistent installation logs
- if len(m.installationLogs) > 0 {
- logHeader := m.styles.Warning.Render("Installation Logs (last 15 lines):")
- b.WriteString(logHeader)
- b.WriteString("\n")
-
- maxLines := 15
- startIdx := 0
- if len(m.installationLogs) > maxLines {
- startIdx = len(m.installationLogs) - maxLines
- }
-
- for i := startIdx; i < len(m.installationLogs); i++ {
- if m.installationLogs[i] != "" {
- logLine := m.styles.Subtle.Render(" " + m.installationLogs[i])
- b.WriteString(logLine)
- b.WriteString("\n")
- }
- }
- b.WriteString("\n")
- }
-
- hint := m.styles.Subtle.Render("Press Ctrl+D for full debug logs")
- b.WriteString(hint)
- b.WriteString("\n")
-
- if m.logFilePath != "" {
- b.WriteString("\n")
- logInfo := m.styles.Warning.Render(fmt.Sprintf("Full logs: %s", m.logFilePath))
- b.WriteString(logInfo)
- b.WriteString("\n")
- }
-
- help := m.styles.Subtle.Render("Press Enter to exit")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateInstallingPackagesState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if progressMsg, ok := msg.(packageInstallProgressMsg); ok {
- m.packageProgress = progressMsg
-
- // Accumulate log output
- if progressMsg.logOutput != "" {
- m.installationLogs = append(m.installationLogs, progressMsg.logOutput)
- // Keep only last 50 lines to preserve more context for debugging
- if len(m.installationLogs) > 50 {
- m.installationLogs = m.installationLogs[len(m.installationLogs)-50:]
- }
- }
-
- if progressMsg.isComplete {
- if progressMsg.error != nil {
- m.state = StateError
- m.isLoading = false
- } else {
- m.installationLogs = []string{}
- m.state = StateConfigConfirmation
- m.isLoading = true
- return m, tea.Batch(m.spinner.Tick, m.checkExistingConfigurations())
- }
- }
- return m, m.listenForPackageProgress()
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) updateInstallCompleteState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "enter":
- return m, tea.Quit
- }
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) updateErrorState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "enter":
- return m, tea.Quit
- }
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) listenForPackageProgress() tea.Cmd {
- return func() tea.Msg {
- msg, ok := <-m.packageProgressChan
- if !ok {
- return packageProgressCompletedMsg{}
- }
- // Always return the message, completion will be handled in updateInstallingPackagesState
- return msg
- }
-}
-
-func (m Model) viewDebugLogs() string {
- var b strings.Builder
-
- theme := TerminalTheme()
-
- titleStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true)
-
- b.WriteString(titleStyle.Render("Debug Logs"))
- b.WriteString("\n\n")
-
- // Combine both logMessages and installationLogs
- allLogs := append([]string{}, m.logMessages...)
- allLogs = append(allLogs, m.installationLogs...)
-
- if len(allLogs) == 0 {
- b.WriteString("No logs available\n")
- } else {
- // Calculate available height (reserve space for header and footer)
- maxHeight := m.height - 6
- if maxHeight < 10 {
- maxHeight = 10
- }
-
- // Show the most recent logs
- startIdx := 0
- if len(allLogs) > maxHeight {
- startIdx = len(allLogs) - maxHeight
- }
-
- for i := startIdx; i < len(allLogs); i++ {
- if allLogs[i] != "" {
- fmt.Fprintf(&b, "%d: %s\n", i, allLogs[i])
- }
- }
-
- if startIdx > 0 {
- subtleStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(theme.Subtle))
- b.WriteString(subtleStyle.Render(fmt.Sprintf("... (%d older log entries hidden)\n", startIdx)))
- }
- }
-
- b.WriteString("\n")
- statusStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(theme.Accent))
- b.WriteString(statusStyle.Render("Press Ctrl+D to return, Ctrl+C to quit"))
-
- return b.String()
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_password.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_password.go
deleted file mode 100644
index deec061..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_password.go
+++ /dev/null
@@ -1,338 +0,0 @@
-package tui
-
-import (
- "context"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
- "time"
-
- tea "github.com/charmbracelet/bubbletea"
-)
-
-func (m Model) viewAuthMethodChoice() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Authentication Method")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- message := "Fingerprint authentication is available.\nHow would you like to authenticate?"
- b.WriteString(m.styles.Normal.Render(message))
- b.WriteString("\n\n")
-
- // Option 0: Fingerprint
- if m.selectedConfig == 0 {
- option := m.styles.SelectedOption.Render("▶ Use Fingerprint")
- b.WriteString(option)
- } else {
- option := m.styles.Normal.Render(" Use Fingerprint")
- b.WriteString(option)
- }
- b.WriteString("\n")
-
- // Option 1: Password
- if m.selectedConfig == 1 {
- option := m.styles.SelectedOption.Render("▶ Use Password")
- b.WriteString(option)
- } else {
- option := m.styles.Normal.Render(" Use Password")
- b.WriteString(option)
- }
- b.WriteString("\n\n")
-
- help := m.styles.Subtle.Render("↑/↓: Navigate, Enter: Select, Esc: Back")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) viewFingerprintAuth() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Fingerprint Authentication")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- if m.fingerprintFailed {
- errorMsg := m.styles.Error.Render("✗ Fingerprint authentication failed")
- b.WriteString(errorMsg)
- b.WriteString("\n")
- retryMsg := m.styles.Subtle.Render("Returning to authentication menu...")
- b.WriteString(retryMsg)
- } else {
- message := "Please place your finger on the fingerprint reader."
- b.WriteString(m.styles.Normal.Render(message))
- b.WriteString("\n\n")
-
- spinner := m.spinner.View()
- status := m.styles.Normal.Render("Waiting for fingerprint...")
- fmt.Fprintf(&b, "%s %s", spinner, status)
- }
-
- return b.String()
-}
-
-func (m Model) viewPasswordPrompt() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Password Authentication")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- message := "Installation requires sudo privileges.\nPlease enter your password to continue:"
- b.WriteString(m.styles.Normal.Render(message))
- b.WriteString("\n\n")
-
- // Password input
- b.WriteString(m.passwordInput.View())
- b.WriteString("\n")
-
- // Show validation status
- if m.packageProgress.step == "Validating sudo password..." {
- spinner := m.spinner.View()
- status := m.styles.Normal.Render(m.packageProgress.step)
- b.WriteString(spinner + " " + status)
- b.WriteString("\n")
- } else if m.packageProgress.error != nil {
- errorMsg := m.styles.Error.Render("✗ " + m.packageProgress.error.Error() + ". Please try again.")
- b.WriteString(errorMsg)
- b.WriteString("\n")
- } else if m.packageProgress.step == "Password validation failed" {
- errorMsg := m.styles.Error.Render("✗ Incorrect password. Please try again.")
- b.WriteString(errorMsg)
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- help := m.styles.Subtle.Render("Enter: Continue, Esc: Back, Ctrl+C: Cancel")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateAuthMethodChoiceState(msg tea.Msg) (tea.Model, tea.Cmd) {
- m.fingerprintFailed = false
-
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "up":
- if m.selectedConfig > 0 {
- m.selectedConfig--
- }
- case "down":
- if m.selectedConfig < 1 {
- m.selectedConfig++
- }
- case "enter":
- if m.selectedConfig == 0 {
- m.state = StateFingerprintAuth
- m.isLoading = true
- return m, tea.Batch(m.spinner.Tick, m.tryFingerprint())
- } else {
- m.state = StatePasswordPrompt
- m.passwordInput.Focus()
- return m, nil
- }
- case "esc":
- m.state = StateDependencyReview
- return m, nil
- }
- }
- return m, nil
-}
-
-func (m Model) updateFingerprintAuthState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if validMsg, ok := msg.(passwordValidMsg); ok {
- if validMsg.valid {
- m.sudoPassword = ""
- m.packageProgress = packageInstallProgressMsg{}
- m.state = StateInstallingPackages
- m.isLoading = true
- return m, tea.Batch(m.spinner.Tick, m.installPackages())
- } else {
- m.fingerprintFailed = true
- return m, m.delayThenReturn()
- }
- }
-
- if _, ok := msg.(delayCompleteMsg); ok {
- m.fingerprintFailed = false
- m.selectedConfig = 0
- m.state = StateAuthMethodChoice
- return m, nil
- }
-
- return m, m.listenForLogs()
-}
-
-func (m Model) updatePasswordPromptState(msg tea.Msg) (tea.Model, tea.Cmd) {
- var cmd tea.Cmd
-
- if validMsg, ok := msg.(passwordValidMsg); ok {
- if validMsg.valid {
- // Password is valid, proceed with installation
- m.sudoPassword = validMsg.password
- m.passwordInput.SetValue("") // Clear password input
- // Clear any error state
- m.packageProgress = packageInstallProgressMsg{}
- m.state = StateInstallingPackages
- m.isLoading = true
- return m, tea.Batch(m.spinner.Tick, m.installPackages())
- } else {
- // Password is invalid, show error and stay on password prompt
- m.packageProgress = packageInstallProgressMsg{
- progress: 0.0,
- step: "Password validation failed",
- error: fmt.Errorf("incorrect password"),
- logOutput: "Authentication failed",
- }
- m.passwordInput.SetValue("")
- m.passwordInput.Focus()
- return m, nil
- }
- }
-
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "enter":
- // Don't allow multiple validation attempts while one is in progress
- if m.packageProgress.step == "Validating sudo password..." {
- return m, nil
- }
-
- // Validate password first
- password := m.passwordInput.Value()
- if password == "" {
- return m, nil // Don't proceed with empty password
- }
-
- // Clear any previous error and show validation in progress
- m.packageProgress = packageInstallProgressMsg{
- progress: 0.01,
- step: "Validating sudo password...",
- isComplete: false,
- logOutput: "Testing password with sudo -v",
- }
- return m, m.validatePassword(password)
- case "esc":
- // Go back to dependency review
- m.passwordInput.SetValue("")
- m.packageProgress = packageInstallProgressMsg{} // Clear any validation state
- m.state = StateDependencyReview
- return m, nil
- }
- }
-
- m.passwordInput, cmd = m.passwordInput.Update(msg)
- return m, cmd
-}
-
-func checkFingerprintEnabled() bool {
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
- defer cancel()
-
- // Check if pam_fprintd.so is in PAM config
- cmd := exec.CommandContext(ctx, "grep", "-q", "pam_fprintd.so", "/etc/pam.d/system-auth")
- if err := cmd.Run(); err != nil {
- return false
- }
-
- // Check if fprintd-list exists and user has enrolled fingerprints
- user := os.Getenv("USER")
- if user == "" {
- return false
- }
-
- listCmd := exec.CommandContext(ctx, "fprintd-list", user)
- output, err := listCmd.CombinedOutput()
- if err != nil {
- return false
- }
-
- // If output contains "finger:" or similar, fingerprints are enrolled
- return strings.Contains(string(output), "finger")
-}
-
-func (m Model) delayThenReturn() tea.Cmd {
- return func() tea.Msg {
- time.Sleep(2 * time.Second)
- return delayCompleteMsg{}
- }
-}
-
-func (m Model) tryFingerprint() tea.Cmd {
- return func() tea.Msg {
- clearCmd := exec.Command("sudo", "-k")
- clearCmd.Run()
-
- tmpDir := os.TempDir()
- askpassScript := filepath.Join(tmpDir, fmt.Sprintf("danklinux-fp-%d.sh", time.Now().UnixNano()))
-
- scriptContent := "#!/bin/sh\nexit 1\n"
- if err := os.WriteFile(askpassScript, []byte(scriptContent), 0o700); err != nil {
- return passwordValidMsg{password: "", valid: false}
- }
- defer os.Remove(askpassScript)
-
- ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
- defer cancel()
-
- cmd := exec.CommandContext(ctx, "sudo", "-A", "-v")
- cmd.Env = append(os.Environ(), fmt.Sprintf("SUDO_ASKPASS=%s", askpassScript))
-
- err := cmd.Run()
-
- if err != nil {
- return passwordValidMsg{password: "", valid: false}
- }
-
- return passwordValidMsg{password: "", valid: true}
- }
-}
-
-func (m Model) validatePassword(password string) tea.Cmd {
- return func() tea.Msg {
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
- defer cancel()
-
- cmd := exec.CommandContext(ctx, "sudo", "-S", "-v")
-
- stdin, err := cmd.StdinPipe()
- if err != nil {
- return passwordValidMsg{password: "", valid: false}
- }
-
- if err := cmd.Start(); err != nil {
- return passwordValidMsg{password: "", valid: false}
- }
-
- _, err = fmt.Fprintf(stdin, "%s\n", password)
- stdin.Close()
- if err != nil {
- return passwordValidMsg{password: "", valid: false}
- }
-
- err = cmd.Wait()
-
- if err != nil {
- if ctx.Err() == context.DeadlineExceeded {
- return passwordValidMsg{password: "", valid: false}
- }
- return passwordValidMsg{password: "", valid: false}
- }
-
- return passwordValidMsg{password: password, valid: true}
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_selection.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_selection.go
deleted file mode 100644
index e45105e..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_selection.go
+++ /dev/null
@@ -1,224 +0,0 @@
-package tui
-
-import (
- "context"
- "fmt"
- "strings"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/deps"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/distros"
- tea "github.com/charmbracelet/bubbletea"
-)
-
-func (m Model) viewSelectWindowManager() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Choose Window Manager")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- options := []struct {
- name string
- description string
- }{
- {"niri", "Scrollable-tiling Wayland compositor."},
- }
-
- if m.osInfo == nil || m.osInfo.Distribution.ID != "debian" {
- options = append(options, struct {
- name string
- description string
- }{"Hyprland", "Dynamic tiling Wayland compositor."})
- }
-
- for i, option := range options {
- if i == m.selectedWM {
- selected := m.styles.SelectedOption.Render("▶ " + option.name)
- b.WriteString(selected)
- b.WriteString("\n")
- desc := m.styles.Subtle.Render(" " + option.description)
- b.WriteString(desc)
- } else {
- normal := m.styles.Normal.Render(" " + option.name)
- b.WriteString(normal)
- b.WriteString("\n")
- desc := m.styles.Subtle.Render(" " + option.description)
- b.WriteString(desc)
- }
- b.WriteString("\n")
- if i < len(options)-1 {
- b.WriteString("\n")
- }
- }
-
- b.WriteString("\n")
- help := m.styles.Subtle.Render("Use ↑/↓ to navigate, Enter to select, Esc to go back")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) viewSelectTerminal() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- title := m.styles.Title.Render("Choose Terminal Emulator")
- b.WriteString(title)
- b.WriteString("\n\n")
-
- var options []struct {
- name string
- description string
- }
-
- if m.osInfo != nil && m.osInfo.Distribution.ID == "gentoo" {
- options = []struct {
- name string
- description string
- }{
- {"kitty", "A feature-rich, customizable terminal emulator."},
- {"alacritty", "A simple terminal emulator."},
- }
- } else {
- options = []struct {
- name string
- description string
- }{
- {"ghostty", "A fast, native terminal emulator built in Zig."},
- {"kitty", "A feature-rich, customizable terminal emulator."},
- {"alacritty", "A simple terminal emulator."},
- }
- }
-
- for i, option := range options {
- if i == m.selectedTerminal {
- selected := m.styles.SelectedOption.Render("▶ " + option.name)
- b.WriteString(selected)
- b.WriteString("\n")
- desc := m.styles.Subtle.Render(" " + option.description)
- b.WriteString(desc)
- } else {
- normal := m.styles.Normal.Render(" " + option.name)
- b.WriteString(normal)
- b.WriteString("\n")
- desc := m.styles.Subtle.Render(" " + option.description)
- b.WriteString(desc)
- }
- b.WriteString("\n")
- if i < len(options)-1 {
- b.WriteString("\n")
- }
- }
-
- b.WriteString("\n")
- help := m.styles.Subtle.Render("Use ↑/↓ to navigate, Enter to select, Esc to go back")
- b.WriteString(help)
-
- return b.String()
-}
-
-func (m Model) updateSelectTerminalState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- maxTerminalIndex := 2
- if m.osInfo != nil && m.osInfo.Distribution.ID == "gentoo" {
- maxTerminalIndex = 1
- }
-
- switch keyMsg.String() {
- case "up":
- if m.selectedTerminal > 0 {
- m.selectedTerminal--
- }
- case "down":
- if m.selectedTerminal < maxTerminalIndex {
- m.selectedTerminal++
- }
- case "enter":
- m.state = StateDetectingDeps
- m.isLoading = true
- return m, tea.Batch(m.spinner.Tick, m.detectDependencies())
- case "esc":
- m.state = StateSelectWindowManager
- return m, m.listenForLogs()
- }
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) updateSelectWindowManagerState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- maxWMIndex := 1
- if m.osInfo != nil && m.osInfo.Distribution.ID == "debian" {
- maxWMIndex = 0
- }
-
- switch keyMsg.String() {
- case "up":
- if m.selectedWM > 0 {
- m.selectedWM--
- }
- case "down":
- if m.selectedWM < maxWMIndex {
- m.selectedWM++
- }
- case "enter":
- m.state = StateSelectTerminal
- return m, m.listenForLogs()
- case "esc":
- // Go back to welcome screen
- m.state = StateWelcome
- return m, m.listenForLogs()
- }
- }
- return m, m.listenForLogs()
-}
-
-func (m Model) detectDependencies() tea.Cmd {
- return func() tea.Msg {
- if m.osInfo == nil {
- return depsDetectedMsg{deps: nil, err: fmt.Errorf("OS info not available")}
- }
-
- detector, err := distros.NewDependencyDetector(m.osInfo.Distribution.ID, m.logChan)
- if err != nil {
- return depsDetectedMsg{deps: nil, err: err}
- }
-
- // Convert TUI selection to deps enum
- var wm deps.WindowManager
- if m.selectedWM == 0 {
- wm = deps.WindowManagerNiri // First option is Niri
- } else {
- wm = deps.WindowManagerHyprland // Second option is Hyprland
- }
-
- var terminal deps.Terminal
- if m.osInfo != nil && m.osInfo.Distribution.ID == "gentoo" {
- switch m.selectedTerminal {
- case 0:
- terminal = deps.TerminalKitty
- case 1:
- terminal = deps.TerminalAlacritty
- default:
- terminal = deps.TerminalKitty
- }
- } else {
- switch m.selectedTerminal {
- case 0:
- terminal = deps.TerminalGhostty
- case 1:
- terminal = deps.TerminalKitty
- default:
- terminal = deps.TerminalAlacritty
- }
- }
-
- dependencies, err := detector.DetectDependenciesWithTerminal(context.Background(), wm, terminal)
- return depsDetectedMsg{deps: dependencies, err: err}
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_welcome.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_welcome.go
deleted file mode 100644
index c5ae862..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/tui/views_welcome.go
+++ /dev/null
@@ -1,216 +0,0 @@
-package tui
-
-import (
- "fmt"
- "strings"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/distros"
- tea "github.com/charmbracelet/bubbletea"
- "github.com/charmbracelet/lipgloss"
-)
-
-func (m Model) viewWelcome() string {
- var b strings.Builder
-
- b.WriteString(m.renderBanner())
- b.WriteString("\n")
-
- theme := TerminalTheme()
-
- decorator := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent)).
- Render("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
-
- titleBox := lipgloss.NewStyle().
- Border(lipgloss.RoundedBorder()).
- BorderForeground(lipgloss.Color(theme.Primary)).
- Padding(0, 2).
- MarginBottom(1)
-
- titleText := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- Render("dankinstall")
-
- versionTag := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent)).
- Italic(true).
- Render(" // Dank Linux Installer")
-
- subtitle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Subtle)).
- Italic(true).
- Render("Quickstart for a Dank Desktop")
-
- b.WriteString(decorator)
- b.WriteString("\n")
- b.WriteString(titleBox.Render(titleText + versionTag))
- b.WriteString("\n")
- b.WriteString(subtitle)
- b.WriteString("\n\n")
-
- if m.osInfo != nil {
- if distros.IsUnsupportedDistro(m.osInfo.Distribution.ID, m.osInfo.VersionID) {
- errorBox := lipgloss.NewStyle().
- Border(lipgloss.RoundedBorder()).
- BorderForeground(lipgloss.Color("#FF6B6B")).
- Padding(1, 2).
- MarginBottom(1)
-
- errorTitle := lipgloss.NewStyle().
- Foreground(lipgloss.Color("#FF6B6B")).
- Bold(true).
- Render("⚠ UNSUPPORTED DISTRIBUTION")
-
- var errorMsg string
- switch m.osInfo.Distribution.ID {
- case "ubuntu":
- errorMsg = fmt.Sprintf("Ubuntu %s is not supported.\n\nOnly Ubuntu 25.04+ is supported.\n\nPlease upgrade to Ubuntu 25.04 or later.", m.osInfo.VersionID)
- case "debian":
- errorMsg = fmt.Sprintf("Debian %s is not supported.\n\nOnly Debian 13+ (Trixie) is supported.\n\nPlease upgrade to Debian 13 or later.", m.osInfo.VersionID)
- case "nixos":
- errorMsg = "See the NixOS documentation for installation instructions: https://danklinux.com/docs/dankmaterialshell/nixos."
- default:
- errorMsg = fmt.Sprintf("%s is not supported.\nFeel free to request on https://github.com/AvengeMedia/DankMaterialShell", m.osInfo.PrettyName)
- }
-
- errorMsgStyled := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Text)).
- Render(errorMsg)
-
- b.WriteString(errorBox.Render(errorTitle + "\n\n" + errorMsgStyled))
- b.WriteString("\n\n")
- } else {
- // System info box
- sysBox := lipgloss.NewStyle().
- Border(lipgloss.NormalBorder()).
- BorderForeground(lipgloss.Color(theme.Subtle)).
- Padding(0, 1).
- MarginBottom(1)
-
- // Style the distro name with its color
- distroStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(m.osInfo.Distribution.HexColorCode)).
- Bold(true)
- distroName := distroStyle.Render(m.osInfo.PrettyName)
-
- archStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent))
-
- sysInfo := fmt.Sprintf("System: %s / %s", distroName, archStyle.Render(m.osInfo.Architecture))
- b.WriteString(sysBox.Render(sysInfo))
- b.WriteString("\n")
-
- // Feature list with better styling
- featTitle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- Underline(true).
- Render("WHAT YOU GET")
- b.WriteString(featTitle + "\n\n")
-
- features := []string{
- "[shell] dms (DankMaterialShell)",
- "[wm] niri or Hyprland",
- "[term] Ghostty, kitty, or Alacritty",
- "[style] All the themes, automatically.",
- "[config] DANK defaults - keybindings, rules, animations, etc.",
- }
-
- for i, feat := range features {
- prefix := feat[:9]
- content := feat[10:]
-
- prefixStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Accent)).
- Bold(true)
-
- contentStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Text))
-
- if i == len(features)-1 {
- contentStyle = contentStyle.Bold(true)
- }
-
- fmt.Fprintf(&b, " %s %s\n",
- prefixStyle.Render(prefix),
- contentStyle.Render(content))
- }
-
- b.WriteString("\n")
-
- noteStyle := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Subtle)).
- Italic(true)
- note := noteStyle.Render("* Existing configs can be replaced (and backed up) or preserved")
- b.WriteString(note)
- b.WriteString("\n")
-
- if m.osInfo.Distribution.ID == "gentoo" {
- gentooNote := noteStyle.Render("* Will set per-package USE flags and unmask testing packages as needed")
- b.WriteString(gentooNote)
- b.WriteString("\n")
- }
-
- b.WriteString("\n")
- }
-
- } else if m.isLoading {
- spinner := m.spinner.View()
- loading := m.styles.Normal.Render("Detecting system...")
- fmt.Fprintf(&b, "%s %s\n\n", spinner, loading)
- }
-
- // Footer with better visual separation
- footerDivider := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Subtle)).
- Render("───────────────────────────────────────────────────────────")
- b.WriteString(footerDivider + "\n")
-
- if m.osInfo != nil {
- ctrlKey := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- Render("Ctrl+C")
-
- if distros.IsUnsupportedDistro(m.osInfo.Distribution.ID, m.osInfo.VersionID) {
- b.WriteString(m.styles.Subtle.Render("Press ") + ctrlKey + m.styles.Subtle.Render(" to quit"))
- } else {
- enterKey := lipgloss.NewStyle().
- Foreground(lipgloss.Color(theme.Primary)).
- Bold(true).
- Render("Enter")
-
- b.WriteString(m.styles.Subtle.Render("Press ") + enterKey + m.styles.Subtle.Render(" to choose window manager, ") + ctrlKey + m.styles.Subtle.Render(" to quit"))
- }
- } else {
- help := m.styles.Subtle.Render("Press Enter to continue, Ctrl+C to quit")
- b.WriteString(help)
- }
-
- return b.String()
-}
-
-func (m Model) updateWelcomeState(msg tea.Msg) (tea.Model, tea.Cmd) {
- if completeMsg, ok := msg.(osInfoCompleteMsg); ok {
- m.isLoading = false
- if completeMsg.err != nil {
- m.err = completeMsg.err
- m.state = StateError
- } else {
- m.osInfo = completeMsg.info
- }
- return m, m.listenForLogs()
- }
-
- if keyMsg, ok := msg.(tea.KeyMsg); ok {
- switch keyMsg.String() {
- case "enter":
- if m.osInfo != nil && !distros.IsUnsupportedDistro(m.osInfo.Distribution.ID, m.osInfo.VersionID) {
- m.state = StateSelectWindowManager
- return m, m.listenForLogs()
- }
- }
- }
- return m, m.listenForLogs()
-}