From 6a6c81ee5a5a3c077c295569d33b8f222928c367 Mon Sep 17 00:00:00 2001
From: Rokosun <rokosun@trom.tf>
Date: Mon, 30 Dec 2024 00:43:26 +0530
Subject: [PATCH] Code refactoring

---
 themeSwitcher.nim | 209 +++++++++++++---------------------------------
 themes.nim        | 111 ++++++++++++++++++++++++
 2 files changed, 169 insertions(+), 151 deletions(-)
 create mode 100644 themes.nim

diff --git a/themeSwitcher.nim b/themeSwitcher.nim
index 466bd3e..a02eba7 100644
--- a/themeSwitcher.nim
+++ b/themeSwitcher.nim
@@ -1,10 +1,9 @@
-from std/osproc import execProcess, ProcessOption, startProcess, waitForExit, close
 from std/os import symlinkExists, getConfigDir, walkDirs, `/`
 from std/envvars import existsEnv, getEnv, delEnv, putEnv
-from std/strutils import split, endsWith, contains
 from std/options import Option, some, get, isNone
 from std/strformat import fmt
-import owlkettle
+import pkg/owlkettle
+import ./themes
 
 const
   # Set the directory path where icons are stored
@@ -25,35 +24,21 @@ const
   padding: 0.4em;
   border-radius: 50%;
 }
-
-#.accent-button.suggested-action {
-#  outline-color: black;
-#  outline-width: 0.05em;
-#  outline-offset: -0.45em;
-}"""
-  appID = "com.tromjaro.ThemeSwitcher"
-  appLogo = "tromjaro-theme-switcher"
-  themeShades = ["Light", "", "Dark"]
-  themeStyles = ["Default", "Nord", "Dracula", "Catppuccin", "Everforest", "Gruvbox"]
-  accentColors = ["Blue", "Red", "Purple", "Pink", "Teal", "Green", "Yellow", "Orange", "Grey"]
+"""
 
 var iconsDirs: seq[string]
 
 for dir in walkDirs(accentIconsDir / "*"):
   iconsDirs.add(dir)
 
-type Theme = tuple[shade: string, style: string, color: string]
-
 # Function prototypes
-proc getCurrentTheme(): Theme
 proc makeThemeButton(shadeName: string, styleName: string): Widget
 proc makeAccentButton(accentColor: string): Widget
-proc runCommand(command: string, args: openArray[string]): bool
-proc setIconTheme(iconName: string)
-proc enableDarkPanels(): bool
-proc setTheme(themeName: string)
+proc accentButtons(): Widget
+proc themeButtons(): Widget
+proc mainGUI(): Widget
 
-# Highlight current theme button
+# Keep track of current theme button
 var currentTheme = getCurrentTheme()
 
 var
@@ -68,6 +53,7 @@ if symlinkExists(getConfigDir() / "gtk-4.0"):
   configDirChanged = true
 
 # Display the GTK-4 GUI using owlkettle
+
 viewable App:
   hooks:
     build:
@@ -79,106 +65,19 @@ viewable App:
           putEnv("XDG_CONFIG_HOME", get(oldConfigDir))
 
 method view(app: AppState): Widget =
-  result = gui:
-    Window:
-      title = "TROMjaro Theme Switcher"
-      # Shrink window to the smallest size
-      defaultSize = (1, 1)
-      iconName = appLogo
-      # Vertical box
-      Box(orient = OrientY, margin = 13, spacing = 10):
-        Label:
-          useMarkup=true
-          text="<span size='large'>STYLE</span>"
-        # Vertical box
-        Box(orient = OrientY, spacing = 5):
-          for shadeName in themeShades:
-            # Horizontal box
-            Box(orient = OrientX, spacing = 5):
-              for styleName in themeStyles:
-                insert(makeThemeButton(shadeName, styleName)) {.vAlign: AlignCenter, hAlign: AlignCenter.}
-        Separator(margin = Margin(top: 5)) {.vAlign: AlignCenter.}
-        Label:
-          useMarkup=true
-          text="<span size='large'>ACCENT COLOR</span>"
-        # Horizontal box
-        Box(orient = OrientX, spacing = 3):
-          for accentColor in accentColors:
-            insert(makeAccentButton(accentColor)) {.vAlign: AlignCenter, hAlign: AlignCenter.}
-        Separator(margin = Margin(top: 12)) {.vAlign: AlignCenter.}
-        # Vertical box
-        Box(orient = OrientY):
-          Label:
-            text="A Theme Switcher for TROMjaro's default theme-set (Colloid) and icon-set (Zafiro)."
-          Label {.vAlign: AlignStart.}:
-            useMarkup = true
-            text="<span size='small'>NOTE: Some apps need to be reopened for the theme to be applied.</span>"
+  result = mainGUI()
 
 brew(appID, gui(App()), icons=iconsDirs, stylesheets=[newStylesheet(gtkCSS)])
 
 
 # Function declarations
 
-proc getCurrentTheme(): Theme =
-  let currentThemeString = execProcess("/usr/bin/xfconf-query",
-    args=["--channel=xsettings", "--property=/Net/ThemeName"],
-    options={})[0 .. ^2]
-
-  let words = currentThemeString.split('-')
-  if words[0] != "Colloid":
-    return
-  var currentTheme: Theme = ("", "Default", "Blue")
-
-  case len(words):
-    of 1: discard
-
-    of 2:
-      let word1 = words[1]
-      if word1 in accentColors:
-        currentTheme.color = word1
-      elif word1 in themeShades:
-        currentTheme.shade = word1
-      elif word1 in themeStyles:
-        currentTheme.style = word1
-      else:
-        return
-
-    of 3:
-      let
-        word1 = words[1]
-        word2 = words[2]
-      if (word1 in accentColors) and (word2 in themeShades):
-        currentTheme.color = word1
-        currentTheme.shade = word2
-      elif (word1 in themeShades) and (word2 in themeStyles):
-        currentTheme.shade = word1
-        currentTheme.style = word2
-      else:
-        return
-
-    of 4:
-      let
-        word1 = words[1]
-        word2 = words[2]
-        word3 = words[3]
-      if (word1 in accentColors) and (word2 in themeShades) and (word3 in themeStyles):
-        currentTheme.color = word1
-        currentTheme.shade = word2
-        currentTheme.style = word3
-      else:
-        return
-
-    else:
-      return
-
-  result = currentTheme
-
 proc makeThemeButton(shadeName: string, styleName: string): Widget =
   let
     shade = if shadeName == "": "" else: fmt"-{shadeName}"
     style = if styleName == "Default": "" else: fmt"-{styleName}"
     color = if currentTheme.color in ["Blue", ""]: "" else: fmt"-{currentTheme.color}"
-    theme = fmt"Colloid{color}{shade}{style}"
+    themeString = fmt"Colloid{color}{shade}{style}"
 
   result = gui:
     Button:
@@ -191,7 +90,7 @@ proc makeThemeButton(shadeName: string, styleName: string): Widget =
         [StyleClass("style-button"), ButtonFlat]
 
       proc clicked() =
-        setTheme(theme)
+        setTheme(themeString)
         # Highlight this button
         currentTheme.shade = shadeName
         currentTheme.style = styleName
@@ -203,7 +102,7 @@ proc makeAccentButton(accentColor: string): Widget =
     shade = if currentTheme.shade == "": "" else: fmt"-{currentTheme.shade}"
     style = if currentTheme.style in ["Default", ""]: "" else: fmt"-{currentTheme.style}"
     color = if accentColor == "Blue": "" else: fmt"-{accentColor}"
-    theme = fmt"Colloid{color}{shade}{style}"
+    themeString = fmt"Colloid{color}{shade}{style}"
 
   result = gui:
     Button:
@@ -215,48 +114,56 @@ proc makeAccentButton(accentColor: string): Widget =
           [StyleClass("accent-button"), ButtonFlat]
 
       proc clicked() =
-        setTheme(theme)
+        setTheme(themeString)
         # Highlight this button
         currentTheme.color = accentColor
         if currentTheme.style == "":
           currentTheme.style = "Default"
 
-proc runCommand(command: string, args: openArray[string]): bool =
-  ## This will run a command with the given args and return true upon success
-  let process = startProcess(command, args=args, options={poParentStreams})
-  result = process.waitForExit() == 0
-  process.close()
+proc themeButtons(): Widget =
+  gui:
+    # Vertical box
+    Box(orient = OrientY, spacing = 5):
+      for shadeName in themeShades:
+        # Horizontal box
+        Box(orient = OrientX, spacing = 5):
+          for styleName in themeStyles:
+            let themeButton = makeThemeButton(shadeName, styleName)
+            insert(themeButton) {.vAlign: AlignCenter, hAlign: AlignCenter.}
 
-proc setIconTheme(iconName: string) =
-  # Change icon theme in XFCE
-  discard runCommand("/usr/bin/xfconf-query",
-    args=["--channel=xsettings", "--property=/Net/IconThemeName", "--create", "--type=string", "--set", iconName])
+proc accentButtons(): Widget =
+  gui:
+    # Horizontal box
+    Box(orient = OrientX, spacing = 3):
+      for accentColor in accentColors:
+        let accentButton = makeAccentButton(accentColor)
+        insert(accentButton) {.vAlign: AlignCenter, hAlign: AlignCenter.}
 
-proc enableDarkPanels(): bool =
-  # Return if dark panels is already enabled
-  if execProcess("/usr/bin/xfconf-query",
-    args=["--channel=xfce4-panel", "--property=/panels/dark-mode"], options={}) == "true\n":
-    return
-  # Try to enable it and return true upon success
-  result = runCommand("/usr/bin/xfconf-query",
-    args=["--channel=xfce4-panel", "--property=/panels/dark-mode", "--create", "--type=bool", "--set=true"])
-
-proc setTheme(themeName: string) =
-
-  var panelNotification: string
-
-  # Set the icon theme and panel color according to the chosen theme
-  if themeName.endsWith("-Dark") or themeName.contains("-Dark-"):
-    setIconTheme("zafiro-dark")
-  else:
-    setIconTheme("zafiro")
-    if enableDarkPanels():
-      panelNotification = " with dark panels"
-
-  # Change the main theme to the chosen one
-  discard runCommand("/usr/bin/xfconf-query",
-    args=["--channel=xsettings", "--property=/Net/ThemeName", "--create", "--type=string", "--set", themeName])
-
-  # Send notification about the theme change
-  sendNotification(appID, "Theme Switcher", fmt"{themeName} theme{panelNotification} is enabled",
-    icon=appLogo)
+proc mainGUI(): Widget =
+  gui:
+    Window:
+      title = "TROMjaro Theme Switcher"
+      # Shrink window to the smallest size
+      defaultSize = (1, 1)
+      iconName = appLogo
+      # Vertical box
+      Box(orient = OrientY, margin = 13, spacing = 10):
+        Label:
+          useMarkup=true
+          text="<span size='large'>STYLE</span>"
+        # Theme buttons
+        insert(themeButtons())
+        Separator(margin = Margin(top: 5)) {.vAlign: AlignCenter.}
+        Label:
+          useMarkup=true
+          text="<span size='large'>ACCENT COLOR</span>"
+        # Accent buttons
+        insert(accentButtons())
+        Separator(margin = Margin(top: 12)) {.vAlign: AlignCenter.}
+        # Vertical box
+        Box(orient = OrientY):
+          Label:
+            text="A Theme Switcher for TROMjaro's default theme-set (Colloid) and icon-set (Zafiro)."
+          Label {.vAlign: AlignStart.}:
+            useMarkup = true
+            text="<span size='small'>NOTE: Some apps need to be reopened for the theme to be applied.</span>"
diff --git a/themes.nim b/themes.nim
new file mode 100644
index 0000000..6dd741e
--- /dev/null
+++ b/themes.nim
@@ -0,0 +1,111 @@
+from std/osproc import execProcess, ProcessOption, startProcess, waitForExit, close
+from std/strutils import split, endsWith, contains
+from std/strformat import fmt
+import pkg/owlkettle
+
+type Theme = tuple[color, shade, style: string]
+
+const
+  themeShades* = ["Light", "", "Dark"]
+  themeStyles* = ["Default", "Nord", "Dracula", "Catppuccin", "Everforest", "Gruvbox"]
+  accentColors* = ["Blue", "Red", "Purple", "Pink", "Teal", "Green", "Yellow", "Orange", "Grey"]
+  appID* = "com.tromjaro.ThemeSwitcher"
+  appLogo* = "tromjaro-theme-switcher"
+
+proc getCurrentTheme*(): Theme =
+  let currentThemeString = execProcess("/usr/bin/xfconf-query",
+    args=["--channel=xsettings", "--property=/Net/ThemeName"],
+    options={})[0 .. ^2]
+
+  # Split the theme string into words
+  let words = currentThemeString.split('-')
+  if words[0] != "Colloid":
+    return
+  var currentTheme: Theme = (color: "Blue", shade: "", style: "Default")
+
+  case len(words):
+    of 1: discard
+
+    # Match against Colloid-Color, Colloid-Shade, Colloid-Style
+    of 2:
+      let word1 = words[1]
+      if word1 in accentColors:
+        currentTheme.color = word1
+      elif word1 in themeShades:
+        currentTheme.shade = word1
+      elif word1 in themeStyles:
+        currentTheme.style = word1
+      else:
+        return
+
+    # Match against Colloid-Color-Shade, Colloid-Shade-Style
+    of 3:
+      let
+        word1 = words[1]
+        word2 = words[2]
+      if (word1 in accentColors) and (word2 in themeShades):
+        currentTheme.color = word1
+        currentTheme.shade = word2
+      elif (word1 in themeShades) and (word2 in themeStyles):
+        currentTheme.shade = word1
+        currentTheme.style = word2
+      else:
+        return
+
+    # Match against Colloid-Color-Shade-Style
+    of 4:
+      let
+        word1 = words[1]
+        word2 = words[2]
+        word3 = words[3]
+      if (word1 in accentColors) and (word2 in themeShades) and (word3 in themeStyles):
+        currentTheme.color = word1
+        currentTheme.shade = word2
+        currentTheme.style = word3
+      else:
+        return
+
+    else:
+      return
+
+  return currentTheme
+
+proc runCommand(command: string, args: openArray[string]): bool =
+  ## This will run a command with the given args and return true upon success
+  let process = startProcess(command, args=args, options={poParentStreams})
+  result = process.waitForExit() == 0
+  process.close()
+
+proc setIconTheme(iconName: string) =
+  # Change icon theme in XFCE
+  discard runCommand("/usr/bin/xfconf-query",
+    args=["--channel=xsettings", "--property=/Net/IconThemeName", "--create", "--type=string", "--set", iconName])
+
+proc enableDarkPanels(): bool =
+  # Return if dark panels is already enabled
+  if execProcess("/usr/bin/xfconf-query",
+    args=["--channel=xfce4-panel", "--property=/panels/dark-mode"], options={}) == "true\n":
+    return
+  # Try to enable it and return true upon success
+  result = runCommand("/usr/bin/xfconf-query",
+    args=["--channel=xfce4-panel", "--property=/panels/dark-mode", "--create", "--type=bool", "--set=true"])
+
+proc setTheme*(themeName: string) =
+
+  var panelNotification: string
+
+  # Set the icon theme and panel color according to the chosen theme
+  if themeName.endsWith("-Dark") or themeName.contains("-Dark-"):
+    setIconTheme("zafiro-dark")
+  else:
+    setIconTheme("zafiro")
+    if enableDarkPanels():
+      panelNotification = " with dark panels"
+
+  # Change the main theme to the chosen one
+  discard runCommand("/usr/bin/xfconf-query",
+    args=["--channel=xsettings", "--property=/Net/ThemeName", "--create", "--type=string", "--set", themeName])
+
+  # Send notification about the theme change
+  sendNotification(appID, "Theme Switcher", fmt"{themeName} theme{panelNotification} is enabled",
+    icon=appLogo)