diff --git a/pika-hyprland-settings/debian/changelog b/pika-hyprland-settings/debian/changelog index 803d7f0..c93a188 100644 --- a/pika-hyprland-settings/debian/changelog +++ b/pika-hyprland-settings/debian/changelog @@ -1,3 +1,9 @@ +pika-hyprland-settings (1.1.3-99pika1) lunar; urgency=medium + + * Add systray + + -- ferrreo Sat, 01 Oct 2022 14:50:00 +0300 + pika-hyprland-settings (1.1.2-99pika1) lunar; urgency=medium * Fix weather diff --git a/pika-hyprland-settings/debian/postinst b/pika-hyprland-settings/debian/postinst index 58115d7..e4c3734 100755 --- a/pika-hyprland-settings/debian/postinst +++ b/pika-hyprland-settings/debian/postinst @@ -11,6 +11,11 @@ cp -f /etc/skel/.config/examples/.profile /etc/skel/ then cp -a /etc/skel/. "${u}/" fi + + if ! test -f "${u}/.config/ags/widgets/systray.js" + then + cp -af /etc/skel/.config/ags/. "${u}/.config/ags/" + fi done mkdir -p /etc/greetd/ diff --git a/pika-hyprland-settings/etc/skel/.config/ags/barConfig.js b/pika-hyprland-settings/etc/skel/.config/ags/barConfig.js new file mode 100644 index 0000000..29ae1b4 --- /dev/null +++ b/pika-hyprland-settings/etc/skel/.config/ags/barConfig.js @@ -0,0 +1,7 @@ +export default { + numberOfWorkspaces: 10, + city: "Stoke-On-Trent", + weatherUpdateInterval: 900, + isAmerican: false, + sysinfoUpdateInterval: "2s", +} \ No newline at end of file diff --git a/pika-hyprland-settings/etc/skel/.config/ags/config.js b/pika-hyprland-settings/etc/skel/.config/ags/config.js index 5ec42a3..f4752f3 100644 --- a/pika-hyprland-settings/etc/skel/.config/ags/config.js +++ b/pika-hyprland-settings/etc/skel/.config/ags/config.js @@ -14,4 +14,4 @@ export default { bar, calendar, ], -} +}; \ No newline at end of file diff --git a/pika-hyprland-settings/etc/skel/.config/ags/lib.js b/pika-hyprland-settings/etc/skel/.config/ags/lib.js new file mode 100644 index 0000000..89824ee --- /dev/null +++ b/pika-hyprland-settings/etc/skel/.config/ags/lib.js @@ -0,0 +1,163 @@ +import barConfig from './barConfig.js'; + +export const getTemp = (temp) => { + if (barConfig?.isAmerican) { + return Math.round((temp * 9 / 5) + 32) + "°F"; + } + return temp + "°C"; +}; + +export const getWeatherSymbol = (weatherCode) => { + const dt = new Date(); + const hour = dt.getHours(); + if (hour < 7 || hour > 21) { + return NIGHT_WEATHER_SYMBOL[WWO_CODE[weatherCode]]; + } + return WEATHER_SYMBOL[WWO_CODE[weatherCode]]; +}; + +export const getFormattedTime = () => { + const date = new Date(); + let hours = date.getHours(); + let minutes = date.getMinutes(); + if (hours < 10) hours = "0" + hours; + if (minutes < 10) minutes = "0" + minutes; + return `${hours}:${minutes}` +} + +export const getFormattedDate = () => { + const date = new Date(); + const day = date.getDay(); + const month = date.getMonth(); + let dayOfMonth = date.getDate(); + switch (dayOfMonth) { + case 1: + case 21: + case 31: + dayOfMonth += "st"; + break; + case 2: + case 22: + dayOfMonth += "nd"; + break; + case 3: + case 23: + dayOfMonth += "rd"; + break; + default: + dayOfMonth += "th"; + } + + return `${days[day]}, ${dayOfMonth} ${months[month]}`; +} + +export const getBattery = (batt) => { + if (batt?.charging) { + return "battery_charging_full"; + } + if (batt?.charged) { + return "battery_full"; + } + + return battIcons[Math.floor(battIcons.length * (batt?.percent / 100))]; +} + +const battIcons = ["battery_0_bar","battery_1_bar","battery_2_bar","battery_3_bar","battery_4_bar","battery_5_bar", "battery_6_bar"]; + +const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; +const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; + +const WWO_CODE = { + "113": "Sunny", + "116": "PartlyCloudy", + "119": "Cloudy", + "122": "VeryCloudy", + "143": "Fog", + "176": "LightShowers", + "179": "LightSleetShowers", + "182": "LightSleet", + "185": "LightSleet", + "200": "ThunderyShowers", + "227": "LightSnow", + "230": "HeavySnow", + "248": "Fog", + "260": "Fog", + "263": "LightShowers", + "266": "LightRain", + "281": "LightSleet", + "284": "LightSleet", + "293": "LightRain", + "296": "LightRain", + "299": "HeavyShowers", + "302": "HeavyRain", + "305": "HeavyShowers", + "308": "HeavyRain", + "311": "LightSleet", + "314": "LightSleet", + "317": "LightSleet", + "320": "LightSnow", + "323": "LightSnowShowers", + "326": "LightSnowShowers", + "329": "HeavySnow", + "332": "HeavySnow", + "335": "HeavySnowShowers", + "338": "HeavySnow", + "350": "LightSleet", + "353": "LightShowers", + "356": "HeavyShowers", + "359": "HeavyRain", + "362": "LightSleetShowers", + "365": "LightSleetShowers", + "368": "LightSnowShowers", + "371": "HeavySnowShowers", + "374": "LightSleetShowers", + "377": "LightSleet", + "386": "ThunderyShowers", + "389": "ThunderyHeavyRain", + "392": "ThunderySnowShowers", + "395": "HeavySnowShowers", +} + +const WEATHER_SYMBOL = { + "Unknown": "air", + "Cloudy": "cloud", + "Fog": "foggy", + "HeavyRain": "rainy", + "HeavyShowers": "rainy", + "HeavySnow": "snowing", + "HeavySnowShowers": "snowing", + "LightRain": "rainy", + "LightShowers": "rainy", + "LightSleet": "rainy", + "LightSleetShowers": "rainy", + "LightSnow": "cloudy_snowing", + "LightSnowShowers": "cloudy_snowing", + "PartlyCloudy": "partly_cloudy_day", + "Sunny": "clear_day", + "ThunderyHeavyRain": "thunderstorm", + "ThunderyShowers": "thunderstorm", + "ThunderySnowShowers": "thunderstorm", + "VeryCloudy": "cloud", +} + +const NIGHT_WEATHER_SYMBOL = { + "Unknown": "air", + "Cloudy": "cloud", + "Fog": "foggy", + "HeavyRain": "rainy", + "HeavyShowers": "rainy", + "HeavySnow": "snowing", + "HeavySnowShowers": "snowing", + "LightRain": "rainy", + "LightShowers": "rainy", + "LightSleet": "rainy", + "LightSleetShowers": "rainy", + "LightSnow": "cloudy_snowing", + "LightSnowShowers": "cloudy_snowing", + "PartlyCloudy": "partly_cloudy_night", + "Sunny": "clear_night", + "ThunderyHeavyRain": "thunderstorm", + "ThunderyShowers": "thunderstorm", + "ThunderySnowShowers": "thunderstorm", + "VeryCloudy": "cloud", +} \ No newline at end of file diff --git a/pika-hyprland-settings/etc/skel/.config/ags/modules/system.js b/pika-hyprland-settings/etc/skel/.config/ags/modules/system.js index 96272c4..e0ab7ee 100644 --- a/pika-hyprland-settings/etc/skel/.config/ags/modules/system.js +++ b/pika-hyprland-settings/etc/skel/.config/ags/modules/system.js @@ -5,6 +5,7 @@ import { Mem } from "../widgets/mem.js"; import { Clock } from "../widgets/clock.js"; import { Weather } from '../widgets/weather.js'; import { Batt } from '../widgets/batt.js'; +import { Systray } from "../widgets/systray.js"; export const System = () => Widget.EventBox({ onPrimaryClick: () => App.toggleWindow('calendar'), @@ -24,6 +25,7 @@ export const System = () => Widget.EventBox({ Mem(), Batt(), Weather(), + Systray(), Clock() ], }), diff --git a/pika-hyprland-settings/etc/skel/.config/ags/modules/workspaces.js b/pika-hyprland-settings/etc/skel/.config/ags/modules/workspaces.js index 8965800..2a40a7d 100644 --- a/pika-hyprland-settings/etc/skel/.config/ags/modules/workspaces.js +++ b/pika-hyprland-settings/etc/skel/.config/ags/modules/workspaces.js @@ -1,6 +1,7 @@ const { Widget } = ags; const { execAsync } = ags.Utils; import { gohypr } from '../services/gohypr.js'; +import barConfig from '../barConfig.js'; export const Workspaces = () => Widget.EventBox({ onScrollUp: () => execAsync('hyprctl dispatch workspace -1'), @@ -10,7 +11,7 @@ export const Workspaces = () => Widget.EventBox({ Widget.Box({ halign: 'center', children: [Widget.Box({ - children: Array.from({ length: 10 }, (_, i) => i + 1).map(i => (Widget.Button({ + children: Array.from({ length: barConfig?.numberOfWorkspaces }, (_, i) => i + 1).map(i => (Widget.Button({ className: 'bar-ws-button', onClicked: () => execAsync(`hyprctl dispatch workspace ${i}`).catch(print), child: Widget.Label({ diff --git a/pika-hyprland-settings/etc/skel/.config/ags/programs/cava b/pika-hyprland-settings/etc/skel/.config/ags/programs/cava index bf07922..e7da394 100755 --- a/pika-hyprland-settings/etc/skel/.config/ags/programs/cava +++ b/pika-hyprland-settings/etc/skel/.config/ags/programs/cava @@ -1,10 +1,10 @@ [general] mode = normal -framerate = 15 -autosens = 0 +framerate = 30 +autosens = 1 ;overshoot = 10 -sensitivity = 750 +;sensitivity = 750 bars = 15 [input] @@ -35,4 +35,4 @@ gradient_color_8 = '#C1838E' [smoothing] monstercat = 1 gravity = 1000000 -noise_reduction = 0.34 +noise_reduction = 34 diff --git a/pika-hyprland-settings/etc/skel/.config/ags/programs/cvjson b/pika-hyprland-settings/etc/skel/.config/ags/programs/cvjson index c06b457..9fcff97 100755 Binary files a/pika-hyprland-settings/etc/skel/.config/ags/programs/cvjson and b/pika-hyprland-settings/etc/skel/.config/ags/programs/cvjson differ diff --git a/pika-hyprland-settings/etc/skel/.config/ags/scss/_bar.scss b/pika-hyprland-settings/etc/skel/.config/ags/scss/_bar.scss index 3f1ea23..a2833b3 100644 --- a/pika-hyprland-settings/etc/skel/.config/ags/scss/_bar.scss +++ b/pika-hyprland-settings/etc/skel/.config/ags/scss/_bar.scss @@ -431,12 +431,17 @@ calendar { } tooltip { - background-color: $background; - color: $onBackground; - border-radius: 5rem; - padding: 1rem; - margin: 1rem; - border: 1px solid $onBackground; + background-color: transparent; + border: none; + + > * > *{ + background-color: $background; + border-radius: 1.5rem; + color: $onBackground; + padding: 1rem; + margin: 0.5rem; + box-shadow: 0.25rem 0 0.25rem 0 $background; + } } .musicbox { @@ -463,4 +468,37 @@ tooltip { border-top-right-radius: 10rem; background-color: $secondaryContainer; } -} \ No newline at end of file +} + +.systray-icon { + margin-right: 0.5rem; + margin-left: 0.25rem; +} + +menu { + background: shade($background, 70%); + border-radius: 12px; + border: 2px solid shade($secondaryContainer, 40%); + margin-top: 2rem; + padding: 1rem 0; + color: $onBackground; + } + + menu > menuitem { + padding: 0.4em 1.5rem; + background: transparent; + transition: 0.2s ease background; + } + + menu > menuitem:hover { + background: rgba(255, 255, 255, 0.4); + } + + menu > menuitem check:checked ~ label { + color: $onBackground; + font-weight: 600; + } + + menubar > menuitem { + margin-left: 0.6rem; + } \ No newline at end of file diff --git a/pika-hyprland-settings/etc/skel/.config/ags/services/gostat.js b/pika-hyprland-settings/etc/skel/.config/ags/services/gostat.js index a90d5e3..6d5b4f5 100644 --- a/pika-hyprland-settings/etc/skel/.config/ags/services/gostat.js +++ b/pika-hyprland-settings/etc/skel/.config/ags/services/gostat.js @@ -1,8 +1,7 @@ const { App } = ags; import { deflisten } from './deflisten.js'; +import barConfig from '../barConfig.js'; -const udpateDelay = "2s"; - -export const gostat = deflisten('gostat', `${App.configDir}/programs/gostat ${udpateDelay}`, (line) => { +export const gostat = deflisten('gostat', `${App.configDir}/programs/gostat ${barConfig.sysinfoUpdateInterval}`, (line) => { return JSON.parse(line); }); \ No newline at end of file diff --git a/pika-hyprland-settings/etc/skel/.config/ags/widgets/batt.js b/pika-hyprland-settings/etc/skel/.config/ags/widgets/batt.js index 4a656fa..1cca375 100644 --- a/pika-hyprland-settings/etc/skel/.config/ags/widgets/batt.js +++ b/pika-hyprland-settings/etc/skel/.config/ags/widgets/batt.js @@ -1,5 +1,6 @@ const { Widget } = ags; const { Battery } = ags.Service; +import { getBattery } from '../lib.js'; export const Batt = () => Widget.Box({ halign: 'end', @@ -34,16 +35,3 @@ export const Batt = () => Widget.Box({ }), ], }); - -function getBattery(batt) { - if (batt?.charging) { - return "battery_charging_full"; - } - if (batt?.charged) { - return "battery_full"; - } - - return battIcons[Math.floor(battIcons.length * (batt?.percent / 100))]; -} - -const battIcons = ["battery_0_bar","battery_1_bar","battery_2_bar","battery_3_bar","battery_4_bar","battery_5_bar", "battery_6_bar"]; \ No newline at end of file diff --git a/pika-hyprland-settings/etc/skel/.config/ags/widgets/clock.js b/pika-hyprland-settings/etc/skel/.config/ags/widgets/clock.js index 66b7129..cb12b38 100644 --- a/pika-hyprland-settings/etc/skel/.config/ags/widgets/clock.js +++ b/pika-hyprland-settings/etc/skel/.config/ags/widgets/clock.js @@ -1,4 +1,5 @@ const { Widget } = ags; +import { getFormattedTime, getFormattedDate } from '../lib.js'; export const Clock = () => Widget.Box({ vertical: true, @@ -22,40 +23,3 @@ export const Clock = () => Widget.Box({ ], }); -function getFormattedTime() { - const date = new Date(); - let hours = date.getHours(); - let minutes = date.getMinutes(); - if (hours < 10) hours = "0" + hours; - if (minutes < 10) minutes = "0" + minutes; - return `${hours}:${minutes}` -} - -function getFormattedDate() { - const date = new Date(); - const day = date.getDay(); - const month = date.getMonth(); - let dayOfMonth = date.getDate(); - switch (dayOfMonth) { - case 1: - case 21: - case 31: - dayOfMonth += "st"; - break; - case 2: - case 22: - dayOfMonth += "nd"; - break; - case 3: - case 23: - dayOfMonth += "rd"; - break; - default: - dayOfMonth += "th"; - } - - return `${days[day]}, ${dayOfMonth} ${months[month]}`; -} - -const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; -const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; diff --git a/pika-hyprland-settings/etc/skel/.config/ags/widgets/cputemp.js b/pika-hyprland-settings/etc/skel/.config/ags/widgets/cputemp.js index 6d4c6bc..ec01d2e 100644 --- a/pika-hyprland-settings/etc/skel/.config/ags/widgets/cputemp.js +++ b/pika-hyprland-settings/etc/skel/.config/ags/widgets/cputemp.js @@ -1,5 +1,6 @@ const { Widget } = ags; import { gostat } from '../services/gostat.js'; +import { getTemp } from '../lib.js'; export const CpuTemp = () => Widget.Box({ halign: 'end', @@ -20,7 +21,7 @@ export const CpuTemp = () => Widget.Box({ className: 'txt-norm txt', connections: [[gostat, label => { if (gostat?.state?.cputemp) { - label.label = gostat?.state?.cputemp + "°C"; + label.label = getTemp(gostat?.state?.cputemp); } }]], }), diff --git a/pika-hyprland-settings/etc/skel/.config/ags/widgets/systray.js b/pika-hyprland-settings/etc/skel/.config/ags/widgets/systray.js new file mode 100644 index 0000000..574de77 --- /dev/null +++ b/pika-hyprland-settings/etc/skel/.config/ags/widgets/systray.js @@ -0,0 +1,29 @@ +const { SystemTray } = ags.Service; +const { Widget } = ags; + +export const Systray = () => Widget.Box({ + className: 'systray', + connections: [[SystemTray, box => { + const arr = SystemTray.items; + box.children = arr.map(item =>{ + const icon = SystemTray.get_icon(item, 24); + if (!icon) { + return; + } + icon.set_margin_left(7); + const btn = Widget.Button({ + //call the Activate function when icon is clicked + //Note: if item.ItemIsMenu is true, left click should open menu + onPrimaryClick: (_, event) => item.ActivateAsync(event.get_root_coords()[1], event.get_root_coords()[2]), + //open menu on right click. + //Note: if item.Menu is not set item.ContextMenuAsync(x, y) should be called. + onSecondaryClick: (_, event) => { + item.AgsMenu.popup_at_widget(btn, 8, 2, event); + }, + //show icon + className: 'systray-icon', + child: icon, + tooltipMarkup: SystemTray.get_tooltip_markup(item) + } ); return btn;}); + }]], +}); \ No newline at end of file diff --git a/pika-hyprland-settings/etc/skel/.config/ags/widgets/visualiser.js b/pika-hyprland-settings/etc/skel/.config/ags/widgets/visualiser.js index 2f97f51..8d50457 100644 --- a/pika-hyprland-settings/etc/skel/.config/ags/widgets/visualiser.js +++ b/pika-hyprland-settings/etc/skel/.config/ags/widgets/visualiser.js @@ -27,7 +27,7 @@ export const Visualiser = () => Widget.Box({ } let count = 0; for (const child of box.get_children()) { - child.fraction = cvjson?.service.state[count] / 1000; + child.fraction = cvjson?.service.state[count] / 1500; count++; } }], diff --git a/pika-hyprland-settings/etc/skel/.config/ags/widgets/weather.js b/pika-hyprland-settings/etc/skel/.config/ags/widgets/weather.js index dd8583a..ec1a608 100644 --- a/pika-hyprland-settings/etc/skel/.config/ags/widgets/weather.js +++ b/pika-hyprland-settings/etc/skel/.config/ags/widgets/weather.js @@ -1,7 +1,7 @@ const { Widget } = ags; -const { exec } = ags.Utils; - -const city = "Stoke-On-Trent"; +const { execAsync } = ags.Utils; +import barConfig from '../barConfig.js'; +import { getWeatherSymbol, getTemp } from '../lib.js'; export const Weather = () => Widget.Box({ halign: 'end', @@ -12,9 +12,9 @@ export const Weather = () => Widget.Box({ Widget.Label({ halign: 'end', valign: 'center', - className: 'txt-larger txt', + className: 'txt-larger txt icon-material', style: 'margin-right: 0.5rem; margin-top: 1px;', - label: '🌦', + label: 'rainy', }), Widget.Label({ halign: 'end', @@ -22,91 +22,16 @@ export const Weather = () => Widget.Box({ className: 'txt-norm txt', }), ], - connections: [[900000, async box => { - try { - // timeout here is to delay enough on boot that network has time to connect - this is a hack but for something that updates so rarely it's fine - setTimeout(() => { - let weather = exec(`curl https://wttr.in/${city}?format=j1`); - weather = JSON.parse(weather); - const weatherCode = weather.current_condition[0].weatherCode; - box.children[0].label = WEATHER_SYMBOL[WWO_CODE[weatherCode]]; - box.children[1].label = weather.current_condition[0].temp_C + "°C"; - }, 5000); - } catch (err) { - console.log(err); - } + connections: [[barConfig?.weatherUpdateInterval * 1000, async box => { + setTimeout(() => { + execAsync(`curl https://wttr.in/${barConfig?.city}?format=j1`) + .then(output => { + const weather = JSON.parse(output); + const weatherCode = weather.current_condition[0].weatherCode; + box.tooltipText = weather.current_condition[0].weatherDesc[0].value; + box.children[0].label = getWeatherSymbol(weatherCode); + box.children[1].label = getTemp(weather.current_condition[0].temp_C); + }).catch(console.error) + }, 5000); }]], }); - -const WWO_CODE = { - "113": "Sunny", - "116": "PartlyCloudy", - "119": "Cloudy", - "122": "VeryCloudy", - "143": "Fog", - "176": "LightShowers", - "179": "LightSleetShowers", - "182": "LightSleet", - "185": "LightSleet", - "200": "ThunderyShowers", - "227": "LightSnow", - "230": "HeavySnow", - "248": "Fog", - "260": "Fog", - "263": "LightShowers", - "266": "LightRain", - "281": "LightSleet", - "284": "LightSleet", - "293": "LightRain", - "296": "LightRain", - "299": "HeavyShowers", - "302": "HeavyRain", - "305": "HeavyShowers", - "308": "HeavyRain", - "311": "LightSleet", - "314": "LightSleet", - "317": "LightSleet", - "320": "LightSnow", - "323": "LightSnowShowers", - "326": "LightSnowShowers", - "329": "HeavySnow", - "332": "HeavySnow", - "335": "HeavySnowShowers", - "338": "HeavySnow", - "350": "LightSleet", - "353": "LightShowers", - "356": "HeavyShowers", - "359": "HeavyRain", - "362": "LightSleetShowers", - "365": "LightSleetShowers", - "368": "LightSnowShowers", - "371": "HeavySnowShowers", - "374": "LightSleetShowers", - "377": "LightSleet", - "386": "ThunderyShowers", - "389": "ThunderyHeavyRain", - "392": "ThunderySnowShowers", - "395": "HeavySnowShowers", -} - -const WEATHER_SYMBOL = { - "Unknown": "✨", - "Cloudy": "☁️", - "Fog": "🌫", - "HeavyRain": "🌧", - "HeavyShowers": "🌧", - "HeavySnow": "❄️", - "HeavySnowShowers": "❄️", - "LightRain": "🌦", - "LightShowers": "🌦", - "LightSleet": "🌧", - "LightSleetShowers": "🌧", - "LightSnow": "🌨", - "LightSnowShowers": "🌨", - "PartlyCloudy": "⛅️", - "Sunny": "☀️", - "ThunderyHeavyRain": "🌩", - "ThunderyShowers": "⛈", - "ThunderySnowShowers": "⛈", - "VeryCloudy": "☁️", -}