diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b097f9c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,58 @@ +name: CI + +on: + pull_request: + types: + - opened + - reopened + - synchronize + +jobs: + flatpak: + name: Flatpak + runs-on: ubuntu-latest + + strategy: + matrix: + arch: [x86_64, aarch64] + # Don't fail the whole workflow if one architecture fails + fail-fast: false + + container: + image: ghcr.io/elementary/flatpak-platform/runtime:6-${{ matrix.arch }} + options: --privileged + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up QEMU for aarch64 emulation + if: ${{ matrix.arch != 'x86_64' }} + uses: docker/setup-qemu-action@v1 + with: + platforms: arm64 + + - name: Build + uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v4 + with: + bundle: com.github.manexim.home.flatpak + manifest-path: com.github.manexim.home.yml + run-tests: true + repository-name: appcenter + repository-url: https://flatpak.elementary.io/repo.flatpakrepo + cache-key: "flatpak-builder-${{ github.sha }}" + arch: ${{ matrix.arch }} + + lint: + name: Lint + runs-on: ubuntu-latest + + container: + image: valalang/lint + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Lint + run: io.elementary.vala-lint -d . diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index f617616..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: CI - -on: [push, pull_request] - -jobs: - lint: - - runs-on: ubuntu-latest - - container: - image: valalang/lint - - steps: - - uses: actions/checkout@v1 - - name: Lint - run: io.elementary.vala-lint -d . diff --git a/.gitignore b/.gitignore index 701cc25..8f00186 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ *~ -build/ -src/Application +build +build-dir +.flatpak-builder +repo/ +*.flatpak +subprojects/flux/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0151138..0000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ ---- - -language: node_js - -node_js: - - 10.17.0 - -sudo: required - -services: - - docker - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - libstdc++-5-dev - -install: - - npm i -g @elementaryos/houston - -script: - - houston ci diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..57738a0 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Build & Run", + "type": "shell", + "command": "./app build && ./app install && ./app run", + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} diff --git a/README.md b/README.md index c3ff94c..ff71115 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@

- - + + @@ -73,6 +73,7 @@ These dependencies must be present before building: - `meson (>=0.40)` - `valac (>=0.40)` - `libgtk-3-dev` + - `libhandy-1-dev` >=1.0.0 - `libjson-glib-dev` - `libgee-0.8-dev` - `libgranite-dev` diff --git a/app b/app new file mode 100755 index 0000000..ca31bff --- /dev/null +++ b/app @@ -0,0 +1,19 @@ +#!/bin/bash + +# fail on first error +set -e + +APP=com.github.manexim.home + +case "$1" in + build) + flatpak-builder --repo=repo build ${APP}.yml --force-clean + flatpak build-bundle repo ${APP}.flatpak --runtime-repo=https://flatpak.elementary.io/repo.flatpakrepo ${APP} master + ;; + install) + flatpak install --user -y ${APP}.flatpak + ;; + run) + flatpak run ${APP} + ;; +esac diff --git a/com.github.manexim.home.yml b/com.github.manexim.home.yml new file mode 100644 index 0000000..8fe9c2f --- /dev/null +++ b/com.github.manexim.home.yml @@ -0,0 +1,19 @@ +app-id: com.github.manexim.home +runtime: io.elementary.Platform +runtime-version: '6' +sdk: io.elementary.Sdk +command: com.github.manexim.home +finish-args: + - '--share=ipc' + - '--share=network' + - '--socket=fallback-x11' + - '--socket=wayland' + + # needed for perfers-color-scheme + - '--system-talk-name=org.freedesktop.Accounts' +modules: + - name: home + buildsystem: meson + sources: + - type: dir + path: . diff --git a/data/com.github.manexim.home.appdata.xml.in b/data/com.github.manexim.home.appdata.xml.in index d60b07a..9bf79b0 100644 --- a/data/com.github.manexim.home.appdata.xml.in +++ b/data/com.github.manexim.home.appdata.xml.in @@ -208,10 +208,11 @@ https://github.com/manexim/home/issues - #fafafa - #333 + #802392 + #fafafa 5 + pk_live_FiCVZObTHO7IaLtSXRETuJiJ00aW6Su9kN none diff --git a/data/icons/symbolic/com.github.manexim.home.logo.lifx-symbolic.svg b/data/icons/symbolic/com.github.manexim.home.logo.lifx-symbolic.svg index fa58df4..040c3fe 100644 --- a/data/icons/symbolic/com.github.manexim.home.logo.lifx-symbolic.svg +++ b/data/icons/symbolic/com.github.manexim.home.logo.lifx-symbolic.svg @@ -2,124 +2,54 @@ - - - - - - - - - - - - - - - + id="svg846" + inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" + sodipodi:docname="com.github.manexim.home.logo.lifx-symbolic.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:i="&#38;ns_ai;"> - - - - image/svg+xml - - - - - + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + + id="layer1"> - - + height="1" /> @@ -143,7 +72,6 @@ id="g8" style="fill:#440294;fill-opacity:1"> @@ -152,7 +80,6 @@ id="g12" style="fill:#440294;fill-opacity:1"> @@ -161,7 +88,6 @@ id="g16" style="fill:#440294;fill-opacity:1"> diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index aafc198..0000000 --- a/debian/changelog +++ /dev/null @@ -1,107 +0,0 @@ -com.github.manexim.home (0.5.0) bionic; urgency=medium - -[NEW] - * Use color picker to set color of smart bulbs -[IMPROVED] - * Show an error page if network is not available -[FIXED] -[TRANSLATIONS] - * Russian (by camellan) - * French (by NathanBnm) - * German (by meisenzahl) - * Japanese (by ryonakano) - * Portuguese (by aimproxy) - * Polish (by oskarkunik) - - -- Marius Meisenzahl Sun, 03 Nov 2019 14:24:03 +0100 - -com.github.manexim.home (0.4.2) bionic; urgency=medium - -[NEW] -[IMPROVED] -[FIXED] - * Fix of overlapping elements -[TRANSLATIONS] - * Russian (by camellan) - * French (by NathanBnm) - * German (by meisenzahl) - * Japanese (by ryonakano) - * Portuguese (by aimproxy) - * Polish (by oskarkunik) - - -- Marius Meisenzahl Wed, 07 Aug 2019 19:43:12 +0200 - -com.github.manexim.home (0.4.1) bionic; urgency=medium - -[NEW] -[IMPROVED] -[FIXED] - * Show loading page if no device is found -[TRANSLATIONS] - * Russian (by camellan) - * French (by NathanBnm) - * German (by meisenzahl) - * Japanese (by ryonakano) - * Portuguese (by aimproxy) - * Polish (by oskarkunik) - - -- Marius Meisenzahl Wed, 07 Aug 2019 06:56:37 +0200 - -com.github.manexim.home (0.4.0) bionic; urgency=medium - -[NEW] - * Set custom device icons - * Set dim level for dimmable bulbs - * Set color for supported bulbs -[IMPROVED] - * UI styling -[FIXED] -[TRANSLATIONS] - * Russian (by camellan) - * French (by NathanBnm) - * German (by meisenzahl) - * Japanese (by ryonakano) - * Portuguese (by aimproxy) - * Polish (by oskarkunik) - - -- Marius Meisenzahl Sun, 04 Aug 2019 12:49:14 +0200 - -com.github.manexim.home (0.3.0) bionic; urgency=medium - -[NEW] - * Add new UI - * Add initial support for Philips Hue devices - * Add discovery for Philips Hue bridges - * Add page to configure Philips Hue bridges - * Add service to save configurations -[IMPROVED] - * Update welcome view - * Add mode switch for dark theme if freedesktop schema is not available -[FIXED] -[TRANSLATIONS] - * French (by NathanBnm) - * German - * Russian (by camellan) - - -- Marius Meisenzahl Thu, 14 Jul 2019 19:40:29 +0200 - -com.github.manexim.home (0.2.0) bionic; urgency=medium - -[NEW] - * Add welcome view for onboarding - * Show loading page if no smart home gadget is found - * Show manufacturer and model of device -[IMPROVED] - * Save and load window settings -[FIXED] - * Remove mention of elementary OS in app description - * Suffix symbolic icon names with -symbolic - * Install all available icon sizes - - -- Marius Meisenzahl Fri, 14 Jun 2019 09:28:04 +0200 - -com.github.manexim.home (0.1.0) bionic; urgency=medium - - * Initial Release. - - -- Marius Meisenzahl Tue, 11 Jun 2019 21:06:00 +0200 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index ec63514..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/debian/control b/debian/control deleted file mode 100644 index 301a63f..0000000 --- a/debian/control +++ /dev/null @@ -1,21 +0,0 @@ -Source: com.github.manexim.home -Section: x11 -Priority: optional -Maintainer: Marius Meisenzahl -Build-Depends: meson, - debhelper (>= 9), - libgtk-3-dev, - libjson-glib-dev, - libgee-0.8-dev, - libgranite-dev, - libsoup2.4-dev, - libxml2-dev, - uuid-dev, - valac -Standards-Version: 3.9.3 - -Package: com.github.manexim.home -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends} -Description: Home - Control your smart home gadgets diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index 65775db..0000000 --- a/debian/copyright +++ /dev/null @@ -1,7 +0,0 @@ -Format: http://dep.debian.net/deps/dep5 -Upstream-Name: com.github.manexim.home -Source: https://github.com/manexim/home - -Files: src/* data/* debian/* -Copyright: 2019 Marius Meisenzahl -License: GPL-3.0+ diff --git a/debian/rules b/debian/rules deleted file mode 100755 index b50d9e9..0000000 --- a/debian/rules +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- -# Sample debian/rules that uses debhelper. -# This file was originally written by Joey Hess and Craig Small. -# As a special exception, when this file is copied by dh-make into a -# dh-make output file, you may use that output file without restriction. -# This special exception was added by Craig Small in version 0.37 of dh-make. - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -%: - dh $@ - -override_dh_auto_clean: - rm -rf debian/build - -override_dh_auto_configure: - mkdir -p debian/build - cd debian/build && meson --prefix=/usr ../.. - -override_dh_auto_build: - cd debian/build && ninja -v - -override_dh_auto_test: - cd debian/build && ninja test - -override_dh_auto_install: - cd debian/build && DESTDIR=${CURDIR}/debian/com.github.manexim.home ninja install diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 89ae9db..0000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (native) diff --git a/meson.build b/meson.build index 34a2406..39d453e 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('com.github.manexim.home', 'vala', 'c') +project('com.github.manexim.home', 'vala', 'c', version: '0.5.0') gnome = import('gnome') i18n = import('i18n') @@ -11,12 +11,14 @@ add_project_arguments( gtk_plus_3_dep = dependency('gtk+-3.0') json_glib_1_dep = dependency('json-glib-1.0') +libhandy_dep = dependency('libhandy-1', version: '>=1.0.0') posix_dep = meson.get_compiler('vala').find_library('posix') gee_dep = dependency('gee-0.8') granite_dep = dependency('granite') soup_dep = dependency('libsoup-2.4') xml_dep = dependency('libxml-2.0') uuid_dep = dependency('uuid') +flux_dep = dependency('flux', fallback : ['flux', 'libflux_dep']) vala_flags = [] enable_demo_mode = get_option('demo_mode') == 'true' diff --git a/src/Application.vala b/src/Application.vala index c2485cc..21b09a4 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -24,12 +24,41 @@ public class Application : Granite.Application { public Application () { Object ( - application_id: Config.APP_ID, + application_id: Constants.APP_ID, flags: ApplicationFlags.FLAGS_NONE ); } + construct { + Intl.setlocale (LocaleCategory.ALL, ""); + Intl.bindtextdomain (Constants.GETTEXT_PACKAGE, Constants.LOCALEDIR); + Intl.bind_textdomain_codeset (Constants.GETTEXT_PACKAGE, "UTF-8"); + Intl.textdomain (Constants.GETTEXT_PACKAGE); + } + protected override void activate () { + // Register Middlewares + Flux.Dispatcher.get_instance ().register_middleware (new LoggingMiddleware ()); + + Flux.Dispatcher.get_instance ().register_middleware (new HueMiddleware ()); + Flux.Dispatcher.get_instance ().register_middleware (new LifxMiddleware ()); + + // Register Stores + Flux.Dispatcher.get_instance ().register_store (new Store ()); + + var granite_settings = Granite.Settings.get_default (); + var gtk_settings = Gtk.Settings.get_default (); + + gtk_settings.gtk_application_prefer_dark_theme = ( + granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK + ); + + granite_settings.notify["prefers-color-scheme"].connect (() => { + gtk_settings.gtk_application_prefer_dark_theme = ( + granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK + ); + }); + window = new MainWindow (this); window.show_all (); diff --git a/src/config/Constants.vala b/src/Constants.vala.in similarity index 71% rename from src/config/Constants.vala rename to src/Constants.vala.in index 1ebc517..83ef9f8 100644 --- a/src/config/Constants.vala +++ b/src/Constants.vala.in @@ -19,9 +19,12 @@ * Authored by: Marius Meisenzahl */ -namespace Config { - public const string APP_ID = "com.github.manexim.home"; - public const string APP_AUTHOR = "Manexim"; - public const string APP_NAME = "Home"; - public const string APP_VERSION = "0.5.0"; +namespace Constants { + private const string APP_ID = "@APP_ID@"; + private const string APP_AUTHOR = "Manexim"; + private const string APP_NAME = "Home"; + private const string APP_VERSION = "@APP_VERSION@"; + + private const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@"; + private const string LOCALEDIR = "@LOCALEDIR@"; } diff --git a/src/Flux/ActionType.vala b/src/Flux/ActionType.vala new file mode 100644 index 0000000..81d47e9 --- /dev/null +++ b/src/Flux/ActionType.vala @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 Manexim (https://github.com/manexim) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * Authored by: Marius Meisenzahl + */ + +namespace ActionType { + const string ADD_DEVICE = "ADD_DEVICE"; + const string UPDATE_DEVICE = "UPDATE_DEVICE"; + const string SET_COLOR = "SET_COLOR"; + const string SET_HUE = "SET_HUE"; + const string SET_SATURATION = "SET_SATURATION"; + const string SET_BRIGHTNESS = "SET_BRIGHTNESS"; + const string SET_HSB = "SET_HSB"; + const string SET_COLOR_TEMPERATURE = "SET_COLOR_TEMPERATURE"; + const string SET_POWER = "SET_POWER"; +} diff --git a/src/Flux/Actions.vala b/src/Flux/Actions.vala new file mode 100644 index 0000000..b908565 --- /dev/null +++ b/src/Flux/Actions.vala @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2021 Manexim (https://github.com/manexim) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * Authored by: Marius Meisenzahl + */ + +public class Actions { + public static void add_device (string id, string name, string manufacturer, string model, Types.Power power, string icon, string? default_icon=null) { + var type = ActionType.ADD_DEVICE; + var payload = new DevicePayload () { + id = id, + name = name, + manufacturer = manufacturer, + model = model, + power = power, + icon = icon, + default_icon = default_icon + }; + var action = new Flux.Action (type, payload); + Flux.Dispatcher.get_instance ().dispatch (action); + } + + public static void update_device (string id, string name, string manufacturer, string model, Types.Power power, string icon, string? default_icon=null) { + var type = ActionType.UPDATE_DEVICE; + var payload = new DevicePayload () { + id = id, + name = name, + manufacturer = manufacturer, + model = model, + power = power, + icon = icon, + default_icon = default_icon + }; + var action = new Flux.Action (type, payload); + Flux.Dispatcher.get_instance ().dispatch (action); + } + + public static void set_color (string id, uint16 hue, uint16 saturation, uint16 brightness, uint16 kelvin, uint32 duration=0) { + var type = ActionType.SET_COLOR; + var payload = new SetColorPayload () { + id = id, + hue = hue, + saturation = saturation, + brightness = brightness, + kelvin = kelvin, + duration = duration + }; + var action = new Flux.Action (type, payload); + Flux.Dispatcher.get_instance ().dispatch (action); + } + + public static void set_hue (string id, uint16 hue) { + var type = ActionType.SET_HUE; + var payload = new SetHuePayload () { + id = id, + hue = hue + }; + var action = new Flux.Action (type, payload); + Flux.Dispatcher.get_instance ().dispatch (action); + } + + public static void set_saturation (string id, uint16 saturation) { + var type = ActionType.SET_SATURATION; + var payload = new SetSaturationPayload () { + id = id, + saturation = saturation + }; + var action = new Flux.Action (type, payload); + Flux.Dispatcher.get_instance ().dispatch (action); + } + + public static void set_brightness (string id, uint16 brightness) { + var type = ActionType.SET_BRIGHTNESS; + var payload = new SetBrightnessPayload () { + id = id, + brightness = brightness + }; + var action = new Flux.Action (type, payload); + Flux.Dispatcher.get_instance ().dispatch (action); + } + + public static void set_hsb (string id, uint16 hue, uint16 saturation, uint16 brightness) { + var type = ActionType.SET_HSB; + var payload = new SetHsbPayload () { + id = id, + hue = hue, + saturation = saturation, + brightness = brightness + }; + var action = new Flux.Action (type, payload); + Flux.Dispatcher.get_instance ().dispatch (action); + } + + public static void set_color_temperature (string id, uint16 color_temperature) { + var type = ActionType.SET_COLOR_TEMPERATURE; + var payload = new SetColorTemperaturePayload () { + id = id, + color_temperature = color_temperature + }; + var action = new Flux.Action (type, payload); + Flux.Dispatcher.get_instance ().dispatch (action); + } + + public static void set_power (string id, bool on) { + var type = ActionType.SET_POWER; + var payload = new SetPowerPayload () { + id = id, + on = on + }; + var action = new Flux.Action (type, payload); + Flux.Dispatcher.get_instance ().dispatch (action); + } +} diff --git a/src/Flux/HueMiddleware.vala b/src/Flux/HueMiddleware.vala new file mode 100644 index 0000000..4c62ac4 --- /dev/null +++ b/src/Flux/HueMiddleware.vala @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2021 Manexim (https://github.com/manexim) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * Authored by: Marius Meisenzahl + */ + +public class HueMiddleware : Flux.Middleware { + public override void process (Flux.Action action) {} +} diff --git a/src/Flux/LifxMiddleware.vala b/src/Flux/LifxMiddleware.vala new file mode 100644 index 0000000..e6e43ed --- /dev/null +++ b/src/Flux/LifxMiddleware.vala @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2021 Manexim (https://github.com/manexim) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * Authored by: Marius Meisenzahl + */ + +public class LifxMiddleware : Flux.Middleware { + public override void process (Flux.Action action) {} +} diff --git a/src/Flux/LoggingMiddleware.vala b/src/Flux/LoggingMiddleware.vala new file mode 100644 index 0000000..896dcf7 --- /dev/null +++ b/src/Flux/LoggingMiddleware.vala @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021 Manexim (https://github.com/manexim) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * Authored by: Marius Meisenzahl + */ + +public class LoggingMiddleware : Flux.Middleware { + public override void process (Flux.Action action) { + debug ("%s: %s", action.action_type, Json.gobject_to_data (action.payload, null)); + } +} diff --git a/src/Flux/Payloads.vala b/src/Flux/Payloads.vala new file mode 100644 index 0000000..c3977c4 --- /dev/null +++ b/src/Flux/Payloads.vala @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021 Manexim (https://github.com/manexim) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * Authored by: Marius Meisenzahl + */ + +public class DevicePayload : Flux.Payload { + public string id { get; set; } + public string name { get; set; } + public string manufacturer { get; set; } + public string model { get; set; } + public Types.Power power { get; set; } + public string icon { get; set; } + public string default_icon { get; set; } +} + +public class SetColorPayload : Flux.Payload { + public string id { get; set; } + public bool on { get; set; } + public uint16 hue { get; set; } + public uint16 saturation { get; set; } + public uint16 brightness { get; set; } + public uint16 kelvin { get; set; } + public uint32 duration { get; set; } +} + +public class SetHuePayload : Flux.Payload { + public string id { get; set; } + public uint16 hue { get; set; } +} + +public class SetSaturationPayload : Flux.Payload { + public string id { get; set; } + public uint16 saturation { get; set; } +} + +public class SetBrightnessPayload : Flux.Payload { + public string id { get; set; } + public uint16 brightness { get; set; } +} + +public class SetHsbPayload : Flux.Payload { + public string id { get; set; } + public uint16 hue { get; set; } + public uint16 saturation { get; set; } + public uint16 brightness { get; set; } +} + +public class SetColorTemperaturePayload : Flux.Payload { + public string id { get; set; } + public uint16 color_temperature { get; set; } +} + +public class SetPowerPayload : Flux.Payload { + public string id { get; set; } + public bool on { get; set; } +} diff --git a/src/Flux/Store.vala b/src/Flux/Store.vala new file mode 100644 index 0000000..8da1109 --- /dev/null +++ b/src/Flux/Store.vala @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021 Manexim (https://github.com/manexim) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * Authored by: Marius Meisenzahl + */ + +public class Store : Flux.Store { + public Gee.List devices; + + public override void process (Flux.Action action) { + switch (action.action_type) { + case ActionType.ADD_DEVICE: + process_add_device (action); + break; + case ActionType.UPDATE_DEVICE: + process_update_device (action); + break; + } + } + + private void process_add_device (Flux.Action action) { + var payload = (DevicePayload) action.payload; + + var device = new Models.Device () { + id = payload.id, + name = payload.name, + manufacturer = payload.manufacturer, + model = payload.model, + power = payload.power, + icon = payload.icon, + default_icon = payload.default_icon + }; + + devices.add (device); + } + + private void process_update_device (Flux.Action action) { + var payload = (DevicePayload) action.payload; + + for (int i = 0; i < devices.size; i++) { + if (devices[i].id == payload.id) { + devices[i] = new Models.Device () { + id = payload.id, + name = payload.name, + manufacturer = payload.manufacturer, + model = payload.model, + power = payload.power, + icon = payload.icon, + default_icon = payload.default_icon + }; + + break; + } + } + } + + public Store () { + devices = new Gee.ArrayList (); + } +} diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 35edb63..1d62b94 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -19,7 +19,7 @@ * Authored by: Marius Meisenzahl */ -public class MainWindow : Gtk.ApplicationWindow { +public class MainWindow : Hdy.Window { private static MainWindow? instance; private Settings settings; private Gtk.Stack stack; @@ -37,37 +37,26 @@ public class MainWindow : Gtk.ApplicationWindow { settings = Settings.get_default (); load_settings (); - var headerbar = new Gtk.HeaderBar (); - headerbar.get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); - headerbar.show_close_button = true; + var headerbar = new Hdy.HeaderBar () { + decoration_layout = "close:", + show_close_button = true, + title = Constants.APP_NAME + }; return_button = new Gtk.Button (); return_button.no_show_all = true; return_button.valign = Gtk.Align.CENTER; - return_button.get_style_context ().add_class ("back-button"); + return_button.get_style_context ().add_class (Granite.STYLE_CLASS_BACK_BUTTON); return_button.clicked.connect (go_back); headerbar.pack_start (return_button); - if (!settings.is_freedesktop_prefers_color_scheme_available ()) { - var gtk_settings = Gtk.Settings.get_default (); - - var mode_switch = new Granite.ModeSwitch.from_icon_name ( - "display-brightness-symbolic", - "weather-clear-night-symbolic" - ); - mode_switch.primary_icon_tooltip_text = _("Light background"); - mode_switch.secondary_icon_tooltip_text = _("Dark background"); - mode_switch.valign = Gtk.Align.CENTER; - mode_switch.bind_property ("active", gtk_settings, "gtk_application_prefer_dark_theme"); - settings.bind ("prefer-dark-style", mode_switch, "active", GLib.SettingsBindFlags.DEFAULT); - headerbar.pack_end (mode_switch); - } + overlay = Widgets.Overlay.instance; - set_titlebar (headerbar); - title = Config.APP_NAME; + var main_layout = new Gtk.Grid (); + main_layout.attach (headerbar, 0, 0); + main_layout.attach (overlay, 0, 1); - overlay = Widgets.Overlay.instance; - add (overlay); + add (main_layout); stack = new Gtk.Stack (); overlay.add (stack); @@ -92,6 +81,10 @@ public class MainWindow : Gtk.ApplicationWindow { }); } + construct { + Hdy.init (); + } + public static MainWindow get_default () { return instance; } diff --git a/src/controllers/DevicesController.vala b/src/controllers/DevicesController.vala index 6fe1937..8766cfe 100644 --- a/src/controllers/DevicesController.vala +++ b/src/controllers/DevicesController.vala @@ -51,12 +51,16 @@ public class Controllers.DevicesController { device.icon = device_loaded_map.get (device.id).icon; } + Actions.add_device (device.id, device.name, device.manufacturer, device.model, device.power, device.icon, device.default_icon); + on_new_device (device); device_list.add (device); }); lifx_service.on_updated_device.connect ((device) => { + Actions.update_device (device.id, device.name, device.manufacturer, device.model, device.power, device.icon, device.default_icon); + on_updated_device (device); }); @@ -67,12 +71,16 @@ public class Controllers.DevicesController { device.icon = device_loaded_map.get (device.id).icon; } + Actions.add_device (device.id, device.name, device.manufacturer, device.model, device.power, device.icon, device.default_icon); + on_new_device (device); device_list.add (device); }); philips_hue_service.on_updated_device.connect ((device) => { + Actions.update_device (device.id, device.name, device.manufacturer, device.model, device.power, device.icon, device.default_icon); + on_updated_device (device); }); } diff --git a/src/lifx/Controller.vala b/src/lifx/Controller.vala index 3518f4f..7d1fd87 100644 --- a/src/lifx/Controller.vala +++ b/src/lifx/Controller.vala @@ -32,6 +32,7 @@ public class Lifx.Controller : Controllers.DeviceController { public override void switch_hue (uint16 hue) { var lamp = device as Lifx.Lamp; + Actions.set_color (device.id, hue, lamp.saturation, lamp.brightness, 0, 0); service.set_color (lamp, hue, lamp.saturation, lamp.brightness, 0, 0); lamp.hue = hue; @@ -39,6 +40,7 @@ public class Lifx.Controller : Controllers.DeviceController { public override void switch_saturation (uint16 saturation) { var lamp = device as Lifx.Lamp; + Actions.set_color (device.id, lamp.hue, saturation, lamp.brightness, 0, 0); service.set_color (lamp, lamp.hue, saturation, lamp.brightness, 0, 0); lamp.saturation = saturation; @@ -46,6 +48,7 @@ public class Lifx.Controller : Controllers.DeviceController { public override void switch_brightness (uint16 brightness) { var lamp = device as Lifx.Lamp; + Actions.set_color (device.id, lamp.hue, lamp.saturation, brightness, lamp.color_temperature, 0); service.set_color (lamp, lamp.hue, lamp.saturation, brightness, lamp.color_temperature, 0); lamp.brightness = brightness; @@ -53,6 +56,7 @@ public class Lifx.Controller : Controllers.DeviceController { public override void switch_hsb (uint16 hue, uint16 saturation, uint16 brightness) { var lamp = device as Lifx.Lamp; + Actions.set_color (device.id, hue, saturation, brightness, 0, 0); service.set_color (lamp, hue, saturation, brightness, 0, 0); lamp.hue = hue; @@ -62,12 +66,14 @@ public class Lifx.Controller : Controllers.DeviceController { public override void switch_color_temperature (uint16 color_temperature) { var lamp = device as Lifx.Lamp; + Actions.set_color (device.id, 0, 0, lamp.brightness, color_temperature, 0); service.set_color (lamp, 0, 0, lamp.brightness, color_temperature, 0); lamp.color_temperature = color_temperature; } public override void switch_power (bool on) { + Actions.set_power (device.id, on); service.set_power (device as Lifx.Lamp, on ? 65535 : 0); _device.power = on ? Types.Power.ON : Types.Power.OFF; diff --git a/src/meson.build b/src/meson.build index f49fff9..52f1830 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,7 +1,18 @@ +config_data = configuration_data() +config_data.set('APP_ID', meson.project_name()) +config_data.set('APP_VERSION', meson.project_version()) +config_data.set('GETTEXT_PACKAGE', meson.project_name()) +config_data.set('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir'))) + +config_file = configure_file( + input: 'Constants.vala.in', + output: '@BASENAME@', + configuration: config_data +) + sources = [ 'colors/HSB.vala', 'colors/RGB.vala', - 'config/Constants.vala', 'controllers/DeviceController.vala', 'controllers/DevicesController.vala', 'lifx/Controller.vala', @@ -39,7 +50,15 @@ sources = [ 'widgets/ColorPicker.vala', 'widgets/IconPopover.vala', 'widgets/Overlay.vala', - 'MainWindow.vala' + 'Flux/Actions.vala', + 'Flux/ActionType.vala', + 'Flux/HueMiddleware.vala', + 'Flux/LifxMiddleware.vala', + 'Flux/LoggingMiddleware.vala', + 'Flux/Payloads.vala', + 'Flux/Store.vala', + 'MainWindow.vala', + config_file, ] executable( @@ -49,12 +68,14 @@ executable( dependencies: [ gtk_plus_3_dep, json_glib_1_dep, + libhandy_dep, posix_dep, gee_dep, granite_dep, soup_dep, xml_dep, - uuid_dep + uuid_dep, + flux_dep, ], install: true ) @@ -70,12 +91,14 @@ foreach test_name : tests dependencies: [ gtk_plus_3_dep, json_glib_1_dep, + libhandy_dep, posix_dep, gee_dep, granite_dep, soup_dep, xml_dep, - uuid_dep + uuid_dep, + flux_dep, ] ) test( diff --git a/src/models/Thing.vala b/src/models/Thing.vala index 4933d83..89258ef 100644 --- a/src/models/Thing.vala +++ b/src/models/Thing.vala @@ -25,6 +25,10 @@ public class Models.Thing : Object { public Thing () { _obj = new Json.Object (); default_icon = "com.github.manexim.home.icon.thing-symbolic"; + id = ""; + name = ""; + manufacturer = ""; + model = ""; } public Thing.from_object (Json.Object object) { diff --git a/src/onboarding/StartView.vala b/src/onboarding/StartView.vala index fc3e151..9446936 100644 --- a/src/onboarding/StartView.vala +++ b/src/onboarding/StartView.vala @@ -24,7 +24,7 @@ public class Onboarding.StartView : Onboarding.AbstractOnboardingView { Object ( description: _("Control your smart home gadgets"), icon_name: "com.github.manexim.home", - title: _("Welcome to %s!").printf (Config.APP_AUTHOR + " " + Config.APP_NAME) + title: _("Welcome to %s!").printf (Constants.APP_AUTHOR + " " + Constants.APP_NAME) ); } } diff --git a/src/pages/AbstractDevicePage.vala b/src/pages/AbstractDevicePage.vala index 68976ff..cafc90c 100644 --- a/src/pages/AbstractDevicePage.vala +++ b/src/pages/AbstractDevicePage.vala @@ -86,7 +86,7 @@ public abstract class Pages.AbstractDevicePage : Granite.SettingsPage { title_label = new Gtk.Label (title); title_label.ellipsize = Pango.EllipsizeMode.END; title_label.xalign = 0; - title_label.get_style_context ().add_class ("h2"); + title_label.get_style_context ().add_class (Granite.STYLE_CLASS_H2_LABEL); var header_area = new Gtk.Grid (); header_area.column_spacing = 12; diff --git a/src/philips/hue/Controller.vala b/src/philips/hue/Controller.vala index c9c1b30..f2cc6b3 100644 --- a/src/philips/hue/Controller.vala +++ b/src/philips/hue/Controller.vala @@ -32,6 +32,7 @@ public class Philips.Hue.Controller : Controllers.DeviceController { public override void switch_hue (uint16 hue) { var lamp = device as Philips.Hue.Lamp; + Actions.set_hue (device.id, hue); controller.switch_light_hue (lamp, hue); lamp.hue = hue; @@ -39,6 +40,7 @@ public class Philips.Hue.Controller : Controllers.DeviceController { public override void switch_saturation (uint16 saturation) { var lamp = device as Philips.Hue.Lamp; + Actions.set_saturation (device.id, saturation); controller.switch_light_saturation (lamp, saturation); lamp.saturation = saturation; @@ -46,6 +48,7 @@ public class Philips.Hue.Controller : Controllers.DeviceController { public override void switch_brightness (uint16 brightness) { var lamp = device as Philips.Hue.Lamp; + Actions.set_brightness (device.id, brightness); controller.switch_light_brightness (lamp, brightness); lamp.brightness = brightness; @@ -53,6 +56,7 @@ public class Philips.Hue.Controller : Controllers.DeviceController { public override void switch_hsb (uint16 hue, uint16 saturation, uint16 brightness) { var lamp = device as Philips.Hue.Lamp; + Actions.set_hsb (device.id, hue, saturation, brightness); controller.switch_light_hsb (lamp, hue, saturation, brightness); lamp.hue = hue; @@ -62,12 +66,14 @@ public class Philips.Hue.Controller : Controllers.DeviceController { public override void switch_color_temperature (uint16 color_temperature) { var lamp = device as Philips.Hue.Lamp; + Actions.set_color_temperature (device.id, color_temperature); controller.switch_light_color_temperature (lamp, color_temperature); lamp.color_temperature = color_temperature; } public override void switch_power (bool on) { + Actions.set_power (device.id, on); controller.switch_light_power (device as Philips.Hue.Lamp, on); _device.power = on ? Types.Power.ON : Types.Power.OFF; diff --git a/src/services/Settings.vala b/src/services/Settings.vala index 52f057a..d1c9caf 100644 --- a/src/services/Settings.vala +++ b/src/services/Settings.vala @@ -114,7 +114,7 @@ public class Settings : Granite.Services.Settings { return; #endif - last_started_app_version = Config.APP_VERSION; + last_started_app_version = Constants.APP_VERSION; var philips_hue_service = Philips.Hue.Service.instance; diff --git a/subprojects/flux.wrap b/subprojects/flux.wrap new file mode 100644 index 0000000..ebc3922 --- /dev/null +++ b/subprojects/flux.wrap @@ -0,0 +1,3 @@ +[wrap-git] +url = https://github.com/manexim/flux.git +revision = add-initial-version