Skip to content
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Commons
import qs.Ui
import "Model.js" as Model

Panel {
  id: root

  moduleName: "notify.desktop"
  ipcTarget: ""
  manageIpc: false

  property var anchorItem: null
  property var hostWidget: null

  readonly property var barIdentity: hostWidget || root
  readonly property color foreground: bar ? bar.foreground : Color.foreground
  readonly property color mutedForeground: Qt.darker(foreground, 1.4)
  readonly property string fontFamily: bar ? bar.fontFamily : Style.font.family
  readonly property string home: Quickshell.env("HOME")
  readonly property string configDir: home + "/.config/notify"
  readonly property string mainConfigPath: configDir + "/notify.json"

  property var profiles: []
  property string activeName: ""
  property string statusMessage: ""
  property bool statusError: false
  readonly property var activeProfile: Model.byName(root.profiles, root.activeName)

  function scanCommand() {
    var dir = Model.shellQuote(root.configDir)
    var main = Model.shellQuote(root.mainConfigPath)
    return "mkdir -p " + dir + "; printf '@@CONFIG\\n'; cat " + main + " 2>/dev/null || true; printf '\\n'; "
      + "for f in " + dir + "/*.json; do "
      + "[ \"$f\" = " + main + " ] && continue; "
      + "[ -f \"$f\" ] || continue; printf '@@FILE %s\\n' \"${f##*/}\"; cat \"$f\"; printf '\\n'; "
      + "done"
  }

  function setStatus(message, error) {
    root.statusMessage = String(message || "")
    root.statusError = error === true
    statusTimer.restart()
  }

  function refresh() {
    if (!scanProc.running) scanProc.running = true
  }

  function parseDump(content) {
    var dump = Model.parseDump(content)
    root.profiles = dump.profiles
    root.activeName = dump.active
    if (root.activeName === "" && root.profiles.length > 0)
      root.activeName = root.profiles[0].name
  }

  function activate(name) {
    var parsed = {}
    try {
      parsed = JSON.parse(mainConfigFile.text() || "{}")
    } catch (e) {
      parsed = {}
    }
    parsed.active = String(name)
    root.activeName = String(name)
    mainConfigFile.setText(JSON.stringify(parsed, null, 2) + "\n")
    root.setStatus("Active profile: " + root.activeName, false)
    root.refresh()
  }

  function openFolder() {
    folderProc.running = true
  }

  function open() {
    root.controller.show()
    Qt.callLater(root.refresh)
  }

  function close() { root.controller.hide() }

  onOpenedChanged: if (opened) root.refresh()

  Component.onCompleted: root.refresh()

  Process {
    id: scanProc
    command: ["sh", "-c", root.scanCommand()]
    stdout: StdioCollector {
      waitForEnd: true
      onStreamFinished: {
        root.parseDump(text)
      }
    }
  }

  FileView {
    id: mainConfigFile
    path: root.mainConfigPath
    atomicWrites: true
    printErrors: false
  }

  Process {
    id: folderProc
    command: ["xdg-open", root.configDir]
  }

  Timer {
    id: statusTimer
    interval: 3500
    onTriggered: root.statusMessage = ""
  }

  KeyboardPanel {
    id: popup
    anchorItem: root.anchorItem
    owner: root.barIdentity
    bar: root.bar
    open: root.opened
    focusTarget: keyCatcher
    contentWidth: popup.fittedContentWidth(Style.space(420))
    contentHeight: popup.fittedContentHeight(contentColumn.implicitHeight)

    PanelKeyCatcher {
      id: keyCatcher
      anchors.fill: parent
      onCloseRequested: root.close()

      Column {
        id: contentColumn
        anchors.fill: parent
        spacing: Style.space(10)

        Column {
          width: parent.width
          spacing: Style.space(3)

          Text {
            text: "Notify profiles"
            color: root.foreground
            font.family: root.fontFamily
            font.pixelSize: Style.font.body
            font.bold: true
          }

          Text {
            text: "Profiles from ~/.config/notify"
            color: root.mutedForeground
            font.family: root.fontFamily
            font.pixelSize: Style.font.caption
          }
        }

        BorderSurface {
          visible: root.activeProfile !== null
          width: parent.width
          implicitHeight: activeSummary.implicitHeight + Style.space(20)
          color: Color.popups.background
          borderSpec: Border.flat(Color.accent, 1)
          radius: Style.cornerRadius

          Column {
            id: activeSummary
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.verticalCenter: parent.verticalCenter
            anchors.leftMargin: Style.space(12)
            anchors.rightMargin: Style.space(12)
            spacing: Style.space(4)

            Text {
              text: "Loaded configuration"
              color: root.mutedForeground
              font.family: root.fontFamily
              font.pixelSize: Style.font.caption
            }

            Text {
              text: root.activeProfile ? root.activeProfile.name + ".json" : ""
              color: root.foreground
              font.family: root.fontFamily
              font.pixelSize: Style.font.body
              font.bold: true
            }
          }
        }

        Text {
          visible: root.profiles.length === 0
          text: "No profiles found. Create a .json file in ~/.config/notify."
          color: root.mutedForeground
          font.family: root.fontFamily
          font.pixelSize: Style.font.bodySmall
          wrapMode: Text.WordWrap
          width: parent.width
        }

        Column {
          width: parent.width
          spacing: Style.space(4)

          Repeater {
            model: root.profiles

            Item {
              id: profileRow
              required property var modelData
              width: parent.width
              implicitHeight: 30

              Button {
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.top: parent.top
                anchors.bottom: parent.bottom
                text: profileRow.modelData.name + "  ·  server configured" + (profileRow.modelData.name === root.activeName ? "  ·  active" : "")
                leftAlign: true
                active: profileRow.modelData.name === root.activeName
                foreground: root.foreground
                fontSize: Style.font.bodySmall
                onClicked: root.activate(profileRow.modelData.name)
              }
            }
          }
        }

        Button {
          width: parent.width
          text: "Open config folder"
          foreground: root.foreground
          fontSize: Style.font.bodySmall
          onClicked: root.openFolder()
        }

        Text {
          visible: root.statusMessage !== ""
          text: root.statusMessage
          color: root.statusError ? Color.urgent : root.mutedForeground
          font.family: root.fontFamily
          font.pixelSize: Style.font.bodySmall
          width: parent.width
        }
      }
    }
  }
}