;;-----------------------------------------------------
;; POLLING VARIABEL
;;-----------------------------------------------------
(defvar wifi_list_visible false)
(defvar bluetooth_list_visible false)
(defvar control_center_visible false)
(defpoll wifi_networks :interval "5s"
:initial "[]"
:run-while wifi_list_visible
`~/.config/eww/scripts/scan_wifi.sh`)
(defpoll bluetooth_devices_listen :interval "2s"
:initial "[]"
:run-while bluetooth_list_visible
`~/.config/eww/scripts/scan_bluetooth.sh`)
;; Pindahkan bluetooth_status poll ke sini
(defpoll bluetooth_status :interval "2s"
:initial "no"
:run-while control_center_visible
`bluetoothctl show | grep "Powered:" | awk '{print $2}' || echo "no"`)
(defpoll wifi_status :interval "3s"
:initial "disabled"
:run-while control_center_visible
`nmcli radio wifi || echo "disabled"`)
;; Poll untuk WiFi networks list
(defpoll wifi_ssid :interval "3s"
:initial ""
:run-while control_center_visible
`nmcli -t -f active,ssid dev wifi | grep '^yes' | cut -d':' -f2 || echo "Not Connected"`)
;; Polls sistem
;; VOLUME LISTENER (Real-time)
(deflisten volume_level :initial "50"
`~/.config/eww/scripts/get_volume_listen.sh`)
;; BRIGHTNESS LISTENER (Real-time)
(deflisten brightness_level :initial "50"
`~/.config/eww/scripts/get_brightness_listen.sh`)
(defpoll night_mode_status :interval "2s"
:initial "off"
:run-while control_center_visible
`[ -f /tmp/night_mode_status ] && cat /tmp/night_mode_status || echo "off"`)
;; Poll untuk Notifikasi (Dunst) - UPDATED
(defpoll notification_count :interval "2s"
:initial "0"
`dunstctl count history || echo 0`)
(defpoll notification_history :interval "2s"
:initial "[]"
:run-while control_center_visible
`~/.config/eww/scripts/get_notifications.sh`)
;; CALENDAR
(defpoll DATE_HEADER :interval "30s"
"date +'%A, %d %B'")
(defpoll clock_time :interval "10s"
"date +'%H:%M'")
(defpoll clock_date :interval "1h"
"date +'%A, %B %d'")
;;---------------------------------------------------------
;; WIDGET CONTROL CENTER WINDOWS (UTAMA)
;;---------------------------------------------------------
;; ========================================
;; WIDGET BLUETOOTH ITEM (untuk list)
;; ========================================
(defwidget bluetooth_device_item [name mac connected paired type]
(box :class "bt-device-item ${connected ? 'bt-connected' : ''}"
:orientation "h"
:spacing 10
:space-evenly false
;; Type icon - CONVERT type text jadi icon di widget
(label :class "bt-type-icon"
:text {type == "phone" ? " " :
type == "headphone" ? " " :
type == "computer" ? " " :
type == "keyboard" ? " " :
type == "mouse" ? " " : " "})
;; Device name
(label :class "bt-name-label"
:text name
:xalign 0
:limit-width 25
:hexpand true)
(box :spacing 5
;; Connect/Disconnect button
(button :class "bt-action-btn"
:onclick "~/.config/eww/scripts/connect_bluetooth.sh '${mac}' toggle && sleep 1"
(label :text {connected ? " " : "Connect"}))
;; Unpair button
(button :class "bt-action-btn bt-unpair"
:visible {paired}
:onclick "~/.config/eww/scripts/connect_bluetooth.sh '${mac}' unpair && sleep 1"
(label :text ""))
)
)
)
;; ========================================
;; WIDGET WIFI ITEM (untuk list)
;; ========================================
(defwidget wifi_network_item [ssid signal secured connected sig_icon sec_icon]
(button :class "wifi-network-item ${connected == 'true' ? 'wifi-connected' : ''}"
:onclick "~/.config/eww/scripts/connect_wifi.sh '${ssid}' &"
(box :orientation "h"
:spacing 10
:space-evenly false
;; Signal icon
(label :class "wifi-signal-icon"
:text sig_icon)
;; SSID
(label :class "wifi-ssid-label"
:text ssid
:xalign 0
:limit-width 25
:hexpand true)
;; Security icon
(label :class "wifi-security-icon"
:text sec_icon
:visible {secured == "true"})
;; Connected indicator
(label :class "wifi-connected-icon"
:text "✓"
:visible {connected == "true"})
)
)
)
;; ----------------------------------------
;; WIDGET TOGGLE
;; ----------------------------------------
(defwidget toggle_widget [icon label ?onclick ?active_class]
(box :class "toggle-widget"
:orientation "v"
:spacing 0
:valign "center"
:halign "fill"
(button :class "toggle-icon ${active_class}"
:onclick {onclick != "" ? onclick : ""}
(box :width 30 :height 30 :halign "center" :valign "center"
(label :text icon :style "font-size: 20px;")
)
)
(label :class "toggle-label"
:text label
:xalign 0.5 )
)
)
;; ----------------------------------------
;; WIDGET UNTUK SATU ITEM NOTIFIKASI - FIXED
;; ----------------------------------------
(defwidget notification_item [appname summary id icon_path]
(box :class "notification-item"
:orientation "h"
:spacing 10
:space-evenly false
;; Ikon Notifikasi
(box :class "notification-icon-container"
:visible {icon_path != "" && icon_path != "null"}
(label :text " " :style "font-size: 24px;"))
;; Teks Notifikasi
(box :class "notification-text-container"
:orientation "v"
:halign "start"
:valign "center"
:hexpand true
:space-evenly false
(label :class "notification-appname"
:text appname
:xalign 0
:limit-width 35)
(label :class "notification-summary"
:text summary
:xalign 0
:wrap true
:limit-width 35))
;; Button close yang berfungsi
(button :class "notification-close-btn"
:onclick "dunstctl history-rm ${id} && eww update notification_history=$(~/.config/eww/scripts/get_notifications.sh)"
(label :text "✕"))
)
)
;; ----------------------------------------
;; WIDGET QUICK TOGGLES (UPDATED)
;; ----------------------------------------
(defwidget quick_toggles []
(box :class "quick-toggles-container"
:orientation "v"
:spacing -5
:space-evenly false
;; Row pertama: 3 toggle buttons (WiFi, BT, Night)
(box :class "quick-toggles-row"
:orientation "h"
:spacing 10
:halign "fill"
:valign "center"
:space-evenly true
;; 1. WiFi - ONCLICK TOGGLE EXPAND
(toggle_widget :icon {wifi_status == "enabled" ? " " : ""}
:label {wifi_status == "enabled" ? "On" : "Off"}
:onclick "eww update bluetooth_list_visible=false wifi_list_visible=${!wifi_list_visible}"
:active_class {wifi_status == "enabled" ? "wifi-active" : ""})
;; 2. Bluetooth Mode
(toggle_widget :icon {bluetooth_status == "yes" ? "" : ""}
:label {bluetooth_status == "yes" ? "On" : "Off"}
:onclick "eww update wifi_list_visible=false bluetooth_list_visible=${!bluetooth_list_visible}"
:active_class {bluetooth_status == "yes" ? "bt-active" : ""})
;; 3. Night Mode (UPDATED)
(toggle_widget :icon "🌙"
:label {night_mode_status == "on" ? "On" : "Off"}
:onclick "~/.config/eww/scripts/toggle_night_mode.sh"
:active_class {night_mode_status == "on" ? "night-active" : ""})
)
;; EXPANDABLE WIFI LIST (dibawah toggle buttons)
(revealer :reveal wifi_list_visible
:transition "slidedown"
:duration "400ms"
(box :class "wifi-expanded-panel"
:orientation "v"
:spacing 5
:space-evenly false
;; Scan button
(button :class "wifi-scan-btn"
:onclick "eww update wifi_networks=$(~/.config/eww/scripts/scan_wifi.sh)"
(label :text " Refresh Networks"))
;; Networks list
(scroll :class "wifi-networks-scroll"
:height 180
:vscroll true
:hscroll false
(box :orientation "v"
:spacing 3
:space-evenly false
;; Loop through networks
(for network in wifi_networks
(wifi_network_item
:ssid {network.ssid}
:signal {network.signal}
:secured {network.secured}
:connected {network.connected}
:sig_icon {network.sig_icon}
:sec_icon {network.sec_icon}
)
)
;; No networks message
(label :class "wifi-no-networks"
:text "No networks found"
:visible {wifi_networks == "[]" || wifi_status != "enabled"})
)
)
;; WiFi Power toggle at bottom
(button :class "wifi-power-toggle"
:onclick "~/.config/eww/scripts/toggle_wifi.sh && sleep 1 && eww update wifi_networks=$(~/.config/eww/scripts/scan_wifi.sh)"
(label :text {wifi_status == "enabled" ? "Turn Off WiFi" : "Turn On WiFi"}))
)
) ;; TUTUP revealer wifi
(revealer :reveal bluetooth_list_visible
:transition "slidedown"
:duration "400ms"
(box :class "bt-expanded-panel"
:orientation "v"
:spacing 5
:space-evenly false
;; Scan button
(button :class "bt-scan-btn"
:onclick "eww update bluetooth_devices_listen=$(~/.config/eww/scripts/scan_bluetooth.sh)"
(label :text " Refresh Devices"))
;; Devices list
(scroll :class "bt-devices-scroll"
:height 180
:vscroll true
:hscroll false
(box :orientation "v"
:spacing 3
:space-evenly false
;; Loop through devices
(for device in bluetooth_devices_listen
(bluetooth_device_item
:name {device.name}
:mac {device.mac}
:connected {device.connected}
:paired {device.paired}
:type {device.type} ;; Ganti dari type_icon
)
)
;; No devices message
(label :class "bt-no-devices"
:text "No devices found"
:visible {bluetooth_devices_listen == "[]" || bluetooth_status != "yes"})
)
)
;; Bluetooth Power toggle at bottom
(button :class "bt-power-toggle"
:onclick "~/.config/eww/scripts/toggle_bluetooth.sh && sleep 1 && eww update bluetooth_devices=$(~/.config/eww/scripts/scan_bluetooth.sh)"
(label :text {bluetooth_status == "yes" ? "Turn Off Bluetooth" : "Turn On Bluetooth"}))
)
)
)
)
;; ----------------------------------------
;; WIDGET UNTUK PUSAT NOTIFIKASI - FIXED
;; ----------------------------------------
(defwidget notification_center []
(box :class "notification-center-container"
:orientation "v"
:space-evenly false
:spacing 0
;; Header Notifikasi - FIXED
(box :class "notification-header"
:orientation "h"
:space-evenly false
:hexpand true
(label :class "notification-header-title"
:text "Notifications"
:halign "start"
:hexpand true)
(button :class "clear-all-btn"
:onclick "dunstctl history-clear && eww update notification_history='[]'"
(label :xalign 1 :text "Clear")))
(separator)
;; Daftar Notifikasi (dengan scroll)
(scroll :class "notification-list-scroll"
:height 150
:vscroll true
:hscroll false
(box :class "notification-list"
:orientation "v"
:spacing 8
:valign {notification_count == 0 ? "center" : "start"}
:vexpand true
;; Loop melalui hasil script
(for notification in notification_history
(notification_item
:appname {notification.appname}
:summary {notification.summary}
:id {notification.id}
:icon_path {notification.icon}
)
)
;; Footer di DALAM scroll - tampil saat tidak ada notifikasi
(box :class "notification-footer"
:halign "center"
:valign "center"
:vexpand true
:visible {notification_count == 0}
(label :text "No new notifications"))
)
)
))
;; ----------------------------------------
;; WIDGET SEPARATOR
;; ----------------------------------------
(defwidget separator []
(box :class "separator" :hexpand true))
;; ----------------------------------------
;; WIDGET SLIDER
;; ----------------------------------------
(defwidget slider_row [icon_left value onchange]
(box :class "slider-row"
:spacing 15
:space-evenly false
:valign "center"
(label :class "slider-icon" :text icon_left)
(scale :class "system-slider"
:min 0
:max 101
:value value
:orientation "h"
:onchange onchange
:hexpand true)
(label :class "slider-percentage"
:text "${value}%"
:style "min-width: 35px;")
)
)
;; ----------------------------------------
;; WIDGET CONTROL CENTER UTAMA
;; ----------------------------------------
(defwidget control_center []
(box :class "control-center-container"
:orientation "v"
:spacing 0
:space-evenly false
:valign "start"
;; Quick toggles (sudah include WiFi expandable)
(quick_toggles)
;; CONDITIONAL: Separator hanya muncul jika WiFi dan BT list TIDAK visible
(revealer :reveal {!wifi_list_visible && !bluetooth_list_visible}
:transition "slideup"
:duration "400ms"
(separator))
;; CONDITIONAL: Sliders hanya muncul jika WiFi dan BT list TIDAK visible
(revealer :reveal {!wifi_list_visible && !bluetooth_list_visible}
:transition "slideup"
:duration "400ms"
(box :class "sliders-container"
:orientation "v"
:spacing 0
:space-evenly false
(slider_row :icon_left " "
:value brightness_level
:onchange "brightnessctl s {}%")
(slider_row :icon_left " "
:value volume_level
:onchange "pactl set-sink-volume @DEFAULT_SINK@ {}%")
))
;; CONDITIONAL: Separator hanya muncul jika WiFi dan BT list TIDAK visible
(revealer :reveal {!wifi_list_visible && !bluetooth_list_visible}
:transition "slideup"
:duration "400ms"
(separator))
;; CONDITIONAL: Notification Center hanya muncul jika WiFi dan BT list TIDAK visible
(revealer :reveal {!wifi_list_visible && !bluetooth_list_visible}
:transition "slideup"
:duration "400ms"
(notification_center))
))
;; ----------------------------------------
;; JENDELA UTAMA
;; ----------------------------------------
(defwindow control_center_window
:monitor 0
:geometry (geometry :x "-80px" :y "45px" :anchor "top right")
:stacking "overlay"
:exclusive true
:focusable false
:windowtype "dialog"
:wm-ignore true
(control_center))