MVVM pattern finished, adding multiple location provider

This commit is contained in:
2024-02-02 19:56:14 +01:00
parent 8acc18c7fe
commit 53f5984eb5
14 changed files with 360 additions and 354 deletions

View File

@@ -96,7 +96,7 @@ CinnamonDynamicWallpaperExtension.prototype = {
_loop: function () {
if (looping) {
try {
Util.spawnCommandLine("/usr/bin/env python3 " + DIRECTORY.path + "/loop.py")
Util.spawnCommandLine("/usr/bin/env python3 " + DIRECTORY.path + "/src/main.py loop")
} catch(e) {
this.showNotification("Error!",
"Cinnamon Dynamic Wallpaper got an error while running the loop script. Please create an issue on GitHub.")

View File

@@ -1221,6 +1221,7 @@
<object class="GtkComboBox" id="cb_network_provider">
<property name="visible">True</property>
<property name="can-focus">False</property>
<signal name="changed" handler="on_cb_network_provider_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>

View File

@@ -71,6 +71,10 @@
"type": "generic",
"default": 15
},
"network_location_provider": {
"type": "generic",
"default": "geojs.io"
},
"latitude_auto": {
"type": "generic",
"default": 0

View File

@@ -1,5 +1,4 @@
from enum import Enum
class NetworkLocationProvider(Enum):
GEOJS = "https://get.geojs.io/v1/ip/geo.json"
IPAPI = "http://ip-api.com/json/?fields=61439"
class NetworkLocationProvider(enumerate):
GEOJS = "geojs.io"
IPAPI = "ip-api.com"
IPWHOIS = "ipwho.is"

View File

@@ -1,110 +0,0 @@
#!/usr/bin/python3
from scripts.cinnamon_pref_handler import *
from scripts.suntimes import *
from datetime import datetime, time
from enums.PeriodSourceEnum import *
from scripts.location import *
from gi.repository import Gio
from PIL import Image
class Loop():
def __init__(self) -> None:
self.prefs = Cinnamon_Pref_Handler()
self.suntimes = Suntimes()
self.location = Location()
self.background_settings = Gio.Settings.new("org.cinnamon.desktop.background")
# Position should estimate by network
if self.prefs.period_source == PeriodSourceEnum.NETWORKLOCATION:
current_location = self.location.get_location()
self.suntimes.calc_suntimes(float(current_location["latitude"]), float(current_location["longitude"]))
self.start_times = self.suntimes.day_periods
# Position is given by user
elif self.prefs.period_source == PeriodSourceEnum.CUSTOMLOCATION:
self.suntimes.calc_suntimes(float(self.prefs.latitude_custom), float(self.prefs.longitude_custom))
self.start_times = self.suntimes.day_periods
# No position, concrete times
else:
def string_to_time_converter(raw_str: str) -> time:
hour = raw_str[0:raw_str.find(":")]
minute = raw_str[raw_str.find(":") + 1:]
return time(hour=int(hour), minute=int(minute))
self.start_times = [
string_to_time_converter(self.prefs.period_custom_start_time[0]),
string_to_time_converter(self.prefs.period_custom_start_time[1]),
string_to_time_converter(self.prefs.period_custom_start_time[2]),
string_to_time_converter(self.prefs.period_custom_start_time[3]),
string_to_time_converter(self.prefs.period_custom_start_time[4]),
string_to_time_converter(self.prefs.period_custom_start_time[5]),
string_to_time_converter(self.prefs.period_custom_start_time[6]),
string_to_time_converter(self.prefs.period_custom_start_time[7]),
string_to_time_converter(self.prefs.period_custom_start_time[8]),
string_to_time_converter(self.prefs.period_custom_start_time[9])
]
def exchange_image(self):
""" Replace the desktop image
"""
# Get the time of day
time_now = time(datetime.now().hour, datetime.now().minute)
# Assign the last image as fallback
self.current_image_uri = self.prefs.source_folder + self.prefs.period_images[9]
for i in range(0, 9):
# Replace the image URI, if it's not the last time period of the day
if self.start_times[i] <= time_now and time_now < self.start_times[i + 1]:
self.current_image_uri = self.prefs.source_folder + self.prefs.period_images[i]
break
# Set the background
self.background_settings['picture-uri'] = "file://" + self.current_image_uri
# Set background stretching
self.background_settings['picture-options'] = self.prefs.picture_aspect
self.set_background_gradient()
def set_background_gradient(self):
""" Setting a gradient background to hide images, which are not high enough
"""
# Load the image
try:
im = Image.open(self.current_image_uri)
pix = im.load()
# Width and height of the current setted image
width, height = im.size
# Color of the top and bottom pixel in the middle of the image
top_color = pix[width / 2,0]
bottom_color = pix[width / 2, height - 1]
# Create the gradient
self.background_settings['color-shading-type'] = "vertical"
if self.prefs.dynamic_background_color:
self.background_settings['primary-color'] = f"#{top_color[0]:x}{top_color[1]:x}{top_color[2]:x}"
self.background_settings['secondary-color'] = f"#{bottom_color[0]:x}{bottom_color[1]:x}{bottom_color[2]:x}"
else:
self.background_settings['primary-color'] = "#000000"
self.background_settings['secondary-color'] = "#000000"
except:
self.background_settings['primary-color'] = "#000000"
self.background_settings['secondary-color'] = "#000000"
# Needed for JavaScript
if __name__ == "__main__":
l = Loop()
l.exchange_image()

View File

@@ -0,0 +1,17 @@
#!/usr/bin/python3
import sys
from ui.main_window import *
from model.main_view_model import *
if __name__ == "__main__":
if len(sys.argv) == 1:
# Load the configuration window
main = Main_Window()
main.show()
elif sys.argv[1] == "loop":
# Run the methods which updates the data
view_model = Main_View_Model()
view_model.refresh_image()
view_model.set_background_gradient()

View File

@@ -1,10 +1,12 @@
import os, json
from pathlib import Path
from PIL import Image
from gi.repository import Gio
from service.display import *
from service.cinnamon_pref_handler import *
from service.suntimes import *
from service.time_bar_chart import *
from service.location import *
from enums.PeriodSourceEnum import *
class Main_View_Model:
@@ -22,13 +24,16 @@ class Main_View_Model:
# Datasets
self.image_sets = ["aurora", "beach", "bitday", "cliffs", "earth", "gradient", "lakeside", "mountains", "sahara"]
self.picture_aspects = ["centered", "scaled", "stretched", "zoom", "spanned"]
self.network_location_provider = ["geojs.io", "ip-api.com"]
self.network_location_provider = ["geojs.io", "ip-api.com", "ipwho.is"]
# Objects from scripts
self.screen_height = Display().get_screen_height()
self.cinnamon_prefs = Cinnamon_Pref_Handler()
self.time_bar_chart = Time_Bar_Chart()
self.suntimes = Suntimes()
self.location = Location()
self.background_settings = Gio.Settings.new("org.cinnamon.desktop.background")
# Breakpoint for smaller UI
self.breakpoint_ui = 1000
@@ -47,25 +52,15 @@ class Main_View_Model:
if self.cinnamon_prefs.period_source == PeriodSourceEnum.NETWORKLOCATION:
self.suntimes.calc_suntimes(float(self.cinnamon_prefs.latitude_auto), float(self.cinnamon_prefs.longitude_auto))
else:
pass
# todo self.suntimes.calc_suntimes(float(self.ui.etr_latitude.get_text()), float(self.ui.etr_longitude.get_text()))
self.suntimes.calc_suntimes(float(self.cinnamon_prefs.latitude_custom), float(self.cinnamon_prefs.longitude_custom))
# Get all time periods. Store the minutes to the list and print the values to the text views
for i in range(0, 10):
time_range_now = self.suntimes.day_periods[i]
if i != 9:
time_range_next = self.suntimes.day_periods[i + 1]
else:
time_range_next = time(hour=23, minute=59)
# todo self.ui.etr_periods[i].set_text(
# str(time_range_now.hour).rjust(2, '0') + ":" + str(time_range_now.minute).rjust(2, '0') + \
# " - " + str(time_range_next.hour).rjust(2, '0') + ":" + str(time_range_next.minute).rjust(2, '0'))
time_periods_min.append(time_range_now.hour * 60 + time_range_now.minute)
# Create time bar
# Reduce size for small displays
if self.screen_height < self.breakpoint_ui:
@@ -79,3 +74,114 @@ class Main_View_Model:
self.time_bar_chart.create_bar_chart(self.TIMEBAR_URI, bar_width, bar_height, time_periods_min)
def refresh_location(self) -> bool:
""" Updating the location by IP, store the result to cinnamon_prefs
Returns:
bool: Successful or not
"""
current_location = self.location.get_location(self.cinnamon_prefs.network_location_provider)
if current_location['success']:
self.cinnamon_prefs.latitude_auto = current_location['latitude']
self.cinnamon_prefs.longitude_auto = current_location['longitude']
return current_location['success']
def string_to_time_converter(raw_str: str) -> time:
""" Convert a time string like "12:34" to a time object
Args:
raw_str (str): Raw string
Returns:
time: Time object
"""
hour = raw_str[0:raw_str.find(":")]
minute = raw_str[raw_str.find(":") + 1:]
return time(hour=int(hour), minute=int(minute))
def calulate_time_periods(self) -> list:
if self.cinnamon_prefs.period_source == PeriodSourceEnum.CUSTOMTIMEPERIODS:
# User uses custom time periods
return [
self.string_to_time_converter(self.cinnamon_prefs.period_custom_start_time[0]),
self.string_to_time_converter(self.cinnamon_prefs.period_custom_start_time[1]),
self.string_to_time_converter(self.cinnamon_prefs.period_custom_start_time[2]),
self.string_to_time_converter(self.cinnamon_prefs.period_custom_start_time[3]),
self.string_to_time_converter(self.cinnamon_prefs.period_custom_start_time[4]),
self.string_to_time_converter(self.cinnamon_prefs.period_custom_start_time[5]),
self.string_to_time_converter(self.cinnamon_prefs.period_custom_start_time[6]),
self.string_to_time_converter(self.cinnamon_prefs.period_custom_start_time[7]),
self.string_to_time_converter(self.cinnamon_prefs.period_custom_start_time[8]),
self.string_to_time_converter(self.cinnamon_prefs.period_custom_start_time[9])
]
else:
# Time periods have to be estimate by coordinates
if self.cinnamon_prefs.period_source == PeriodSourceEnum.NETWORKLOCATION:
# Get coordinates from the network
self.refresh_location()
self.suntimes.calc_suntimes(self.cinnamon_prefs.latitude_auto, self.cinnamon_prefs.longitude_auto)
elif self.cinnamon_prefs.period_source == PeriodSourceEnum.CUSTOMLOCATION:
# Get coordinates from user input
self.suntimes.calc_suntimes(self.cinnamon_prefs.latitude_custom, self.cinnamon_prefs.longitude_custom)
# Return the time periods
return self.suntimes.day_periods
def refresh_image(self):
""" Replace the desktop image if needed
"""
start_times = self.calulate_time_periods()
# Get the time of day
time_now = time(datetime.now().hour, datetime.now().minute)
# Assign the last image as fallback
self.current_image_uri = self.cinnamon_prefs.source_folder + self.cinnamon_prefs.period_images[9]
for i in range(0, 9):
# Replace the image URI, if it's not the last time period of the day
if start_times[i] <= time_now and time_now < start_times[i + 1]:
self.current_image_uri = self.cinnamon_prefs.source_folder + self.cinnamon_prefs.period_images[i]
break
# Set the background
self.background_settings['picture-uri'] = "file://" + self.current_image_uri
# Set background stretching
self.background_settings['picture-options'] = self.cinnamon_prefs.picture_aspect
def set_background_gradient(self):
""" Setting a gradient background to hide images, which are not high enough
"""
# Load the image
try:
im = Image.open(self.current_image_uri)
pix = im.load()
# Width and height of the current setted image
width, height = im.size
# Color of the top and bottom pixel in the middle of the image
top_color = pix[width / 2,0]
bottom_color = pix[width / 2, height - 1]
# Create the gradient
self.background_settings['color-shading-type'] = "vertical"
if self.cinnamon_prefs.dynamic_background_color:
self.background_settings['primary-color'] = f"#{top_color[0]:x}{top_color[1]:x}{top_color[2]:x}"
self.background_settings['secondary-color'] = f"#{bottom_color[0]:x}{bottom_color[1]:x}{bottom_color[2]:x}"
else:
self.background_settings['primary-color'] = "#000000"
self.background_settings['secondary-color'] = "#000000"
except:
self.background_settings['primary-color'] = "#000000"
self.background_settings['secondary-color'] = "#000000"

View File

@@ -1,57 +0,0 @@
#!/usr/bin/python3
############################################################
# Imports #
############################################################
# Packages
import gi, os, subprocess, time
from datetime import timedelta
# Local scripts
from scripts import cinnamon_pref_handler, dialogs, display, images, location, suntimes, time_bar_chart, ui
from loop import *
from enums.ImageSourceEnum import ImageSourceEnum
from enums.PeriodSourceEnum import PeriodSourceEnum
from enums.NetworkLocationProvider import NetworkLocationProvider
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GdkPixbuf
class Preferences:
""" Preference window class
"""
############################################################
# Lifecycle #
############################################################
def __init__(self) -> None:
# UI helper object
self.ui = ui.UI(self.builder)
# Layout breakpoint for smaller displays
self.smaller_ui_height = 1000
def show(self):
""" Display the window to the screen
"""
self.ui.show_main_window(self.builder, self.smaller_ui_height, self.prefs)
# Time diagram
try:
self.refresh_chart()
except:
self.dialogs.message_dialog("Error on creating time bar!")
if __name__ == "__main__":
Preferences().show()

View File

@@ -11,90 +11,122 @@ class Cinnamon_Pref_Handler:
self.load_preferences()
def extract_json(self, parameter: str) -> str:
""" Get a parameter from the json dictionary safely
Args:
parameter (str): Parameter to request
Returns:
str: Value of the parameter (or "" if not existing)
"""
try:
return self.pref_data[parameter]['value']
except:
return ""
def load_preferences(self):
""" Load the JSON preferences to the Preference object
"""
with open(self.pref_location, "r") as pref_file:
pref_data = json.load(pref_file)
self.pref_data = json.load(pref_file)
self.picture_aspect = pref_data['picture_aspect']['value']
self.dynamic_background_color = pref_data['dynamic_background_color']['value']
self.image_source = pref_data['image_source']['value']
self.selected_image_set = pref_data['selected_image_set']['value']
self.source_folder = pref_data['source_folder']['value']
self.picture_aspect = self.extract_json('picture_aspect')
self.dynamic_background_color = self.extract_json('dynamic_background_color')
self.image_source = self.extract_json('image_source')
self.selected_image_set = self.extract_json('selected_image_set')
self.source_folder = self.extract_json('source_folder')
self.period_images = [
pref_data['period_0_image']['value'],
pref_data['period_1_image']['value'],
pref_data['period_2_image']['value'],
pref_data['period_3_image']['value'],
pref_data['period_4_image']['value'],
pref_data['period_5_image']['value'],
pref_data['period_6_image']['value'],
pref_data['period_7_image']['value'],
pref_data['period_8_image']['value'],
pref_data['period_9_image']['value']
self.extract_json('period_0_image'),
self.extract_json('period_1_image'),
self.extract_json('period_2_image'),
self.extract_json('period_3_image'),
self.extract_json('period_4_image'),
self.extract_json('period_5_image'),
self.extract_json('period_6_image'),
self.extract_json('period_7_image'),
self.extract_json('period_8_image'),
self.extract_json('period_9_image')
]
self.period_source = pref_data['period_source']['value']
self.location_refresh_intervals = pref_data['location_refresh_intervals']['value']
self.latitude_auto = pref_data['latitude_auto']['value']
self.longitude_auto = pref_data['longitude_auto']['value']
self.latitude_custom = pref_data['latitude_custom']['value']
self.longitude_custom = pref_data['longitude_custom']['value']
self.period_source =self.extract_json('period_source')
self.location_refresh_intervals =self.extract_json('location_refresh_intervals')
self.network_location_provider =self.extract_json('network_location_provider')
self.latitude_auto =self.extract_json('latitude_auto')
self.longitude_auto =self.extract_json('longitude_auto')
self.latitude_custom =self.extract_json('latitude_custom')
self.longitude_custom =self.extract_json('longitude_custom')
self.period_custom_start_time = [
pref_data['period_0_custom_start_time']['value'],
pref_data['period_1_custom_start_time']['value'],
pref_data['period_2_custom_start_time']['value'],
pref_data['period_3_custom_start_time']['value'],
pref_data['period_4_custom_start_time']['value'],
pref_data['period_5_custom_start_time']['value'],
pref_data['period_6_custom_start_time']['value'],
pref_data['period_7_custom_start_time']['value'],
pref_data['period_8_custom_start_time']['value'],
pref_data['period_9_custom_start_time']['value']
]
self.extract_json('period_0_custom_start_time'),
self.extract_json('period_1_custom_start_time'),
self.extract_json('period_2_custom_start_time'),
self.extract_json('period_3_custom_start_time'),
self.extract_json('period_4_custom_start_time'),
self.extract_json('period_5_custom_start_time'),
self.extract_json('period_6_custom_start_time'),
self.extract_json('period_7_custom_start_time'),
self.extract_json('period_8_custom_start_time'),
self.extract_json('period_9_custom_start_time')
]
def value_to_json(self, parameter: str, value: str):
""" Storing safely a value to the dictionary
Args:
parameter (str): Parameter to write
value (str): Value to write
"""
try:
self.pref_data[parameter]['value'] = value
except:
self.pref_data[parameter] = {
'type': 'generic',
'value': value
}
print(self.pref_data)
def store_preferences(self):
""" Store the values of the Preference object to the JSON file
"""
with open(self.pref_location, "r") as pref_file:
pref_data = json.load(pref_file)
self.value_to_json('picture_aspect', self.picture_aspect)
self.value_to_json('dynamic_background_color', self.dynamic_background_color)
self.value_to_json('image_source', self.image_source)
self.value_to_json('selected_image_set', self.selected_image_set)
self.value_to_json('source_folder', self.source_folder)
self.value_to_json('period_0_image', self.period_images[0])
self.value_to_json('period_1_image', self.period_images[1])
self.value_to_json('period_2_image', self.period_images[2])
self.value_to_json('period_3_image', self.period_images[3])
self.value_to_json('period_4_image', self.period_images[4])
self.value_to_json('period_5_image', self.period_images[5])
self.value_to_json('period_6_image', self.period_images[6])
self.value_to_json('period_7_image', self.period_images[7])
self.value_to_json('period_8_image', self.period_images[8])
self.value_to_json('period_9_image', self.period_images[9])
self.value_to_json('period_source', self.period_source)
self.value_to_json('location_refresh_intervals', self.location_refresh_intervals)
self.value_to_json('network_location_provider', self.network_location_provider)
self.value_to_json('latitude_auto', self.latitude_auto)
self.value_to_json('longitude_auto', self.longitude_auto)
self.value_to_json('latitude_custom', self.latitude_custom)
self.value_to_json('longitude_custom', self.longitude_custom)
self.value_to_json('period_0_custom_start_time', self.period_custom_start_time[0])
self.value_to_json('period_1_custom_start_time', self.period_custom_start_time[1])
self.value_to_json('period_2_custom_start_time', self.period_custom_start_time[2])
self.value_to_json('period_3_custom_start_time', self.period_custom_start_time[3])
self.value_to_json('period_4_custom_start_time', self.period_custom_start_time[4])
self.value_to_json('period_5_custom_start_time', self.period_custom_start_time[5])
self.value_to_json('period_6_custom_start_time', self.period_custom_start_time[6])
self.value_to_json('period_7_custom_start_time', self.period_custom_start_time[7])
self.value_to_json('period_8_custom_start_time', self.period_custom_start_time[8])
self.value_to_json('period_9_custom_start_time', self.period_custom_start_time[9])
pref_data['picture_aspect']['value'] = self.picture_aspect
pref_data['dynamic_background_color']['value'] = self.dynamic_background_color
pref_data['image_source']['value'] = self.image_source
pref_data['selected_image_set']['value'] = self.selected_image_set
pref_data['source_folder']['value'] = self.source_folder
pref_data['period_0_image']['value'] = self.period_images[0]
pref_data['period_1_image']['value'] = self.period_images[1]
pref_data['period_2_image']['value'] = self.period_images[2]
pref_data['period_3_image']['value'] = self.period_images[3]
pref_data['period_4_image']['value'] = self.period_images[4]
pref_data['period_5_image']['value'] = self.period_images[5]
pref_data['period_6_image']['value'] = self.period_images[6]
pref_data['period_7_image']['value'] = self.period_images[7]
pref_data['period_8_image']['value'] = self.period_images[8]
pref_data['period_9_image']['value'] = self.period_images[9]
pref_data['period_source']['value'] = self.period_source
pref_data['location_refresh_intervals']['value'] = self.location_refresh_intervals
pref_data['latitude_auto']['value'] = self.latitude_auto
pref_data['longitude_auto']['value'] = self.longitude_auto
pref_data['latitude_custom']['value'] = self.latitude_custom
pref_data['longitude_custom']['value'] = self.longitude_custom
pref_data['period_0_custom_start_time']['value'] = self.period_custom_start_time[0]
pref_data['period_1_custom_start_time']['value'] = self.period_custom_start_time[1]
pref_data['period_2_custom_start_time']['value'] = self.period_custom_start_time[2]
pref_data['period_3_custom_start_time']['value'] = self.period_custom_start_time[3]
pref_data['period_4_custom_start_time']['value'] = self.period_custom_start_time[4]
pref_data['period_5_custom_start_time']['value'] = self.period_custom_start_time[5]
pref_data['period_6_custom_start_time']['value'] = self.period_custom_start_time[6]
pref_data['period_7_custom_start_time']['value'] = self.period_custom_start_time[7]
pref_data['period_8_custom_start_time']['value'] = self.period_custom_start_time[8]
pref_data['period_9_custom_start_time']['value'] = self.period_custom_start_time[9]
# Write to file
with open(self.pref_location, "w") as pref_file:
json.dump(pref_data, pref_file, separators=(',', ':'), indent=4)
json.dump(self.pref_data, pref_file, separators=(',', ':'), indent=4)

View File

@@ -4,26 +4,36 @@ from enums.NetworkLocationProvider import NetworkLocationProvider
class Location():
""" Class to handle location requests
"""
def __init__(self):
pass
def get_location(self, provider: NetworkLocationProvider) -> dict:
""" Request the location via network
Returns:
dict: latitude and longitude
"""
request = urllib.request.urlopen(provider.value)
data = json.load(request)
if provider == NetworkLocationProvider.GEOJS:
return {
"latitude": data["latitude"],
"longitude": data["longitude"]
}
url = "http://get.geojs.io/v1/ip/geo.json"
elif provider == NetworkLocationProvider.IPAPI:
url = "http://ip-api.com/json/?fields=61439"
elif provider == NetworkLocationProvider.IPWHOIS:
url = "http://ipwho.is"
try:
request = urllib.request.urlopen(url)
data = json.load(request)
if provider == NetworkLocationProvider.GEOJS or provider == NetworkLocationProvider.IPWHOIS:
param_lat = "latitude"
param_lon = "longitude"
else:
param_lat = "lat"
param_lon = "lon"
return {
"latitude": data["lat"],
"longitude": data["lon"]
"latitude": float(data[param_lat]),
"longitude": float(data[param_lon]),
"success": True
}
except:
return {
"success": False
}

View File

@@ -1,6 +0,0 @@
#!/usr/bin/python3
import ui.main_window
main = ui.main_window.Main_Window()
main.show()

View File

@@ -43,7 +43,7 @@ class Dialogs(Gtk.Window):
return location
def message_dialog(self, message: str):
def message_dialog(self, message: str, type: Gtk.MessageType = Gtk.MessageType.INFO):
""" Displaying a Gtk Message dialog to the user
Args:
@@ -52,7 +52,7 @@ class Dialogs(Gtk.Window):
dialog = Gtk.MessageDialog(
transient_for=self,
flags=0,
message_type=Gtk.MessageType.INFO,
message_type=type,
buttons=Gtk.ButtonsType.OK,
text=message
)

View File

@@ -14,7 +14,6 @@ from datetime import timedelta
# Local scripts
from model.main_view_model import *
from service.images import *
from service.location import *
from service.suntimes import *
from service.time_bar_chart import *
from ui.dialogs import *
@@ -46,7 +45,6 @@ class Main_Window:
# Objects from scripts
self.images = Images()
self.dialogs = Dialogs()
self.location = Location()
self.suntimes = Suntimes()
self.time_bar_chart = Time_Bar_Chart()
@@ -160,6 +158,8 @@ class Main_Window:
def show(self):
""" Display the window to the screen
"""
self.builder.get_object("window_main").show_all()
# Smaller UI handling
@@ -265,9 +265,12 @@ class Main_Window:
image_preview.set_from_pixbuf(pixbuf)
except:
pass
self.dialogs.message_dialog("Error on load images. Please check the configuration!", Gtk.MessageType.ERROR)
def refresh_charts(self):
""" Refresh the charts and put them to the image views
"""
self.view_model.refresh_charts()
# Load to the views
@@ -286,6 +289,20 @@ class Main_Window:
## Image Configuration
def show_image_configuration_entries(self, button_id: int):
self.tb_image_set.set_active(button_id == 1)
self.tb_heic_file.set_active(button_id == 2)
self.tb_source_folder.set_active(button_id == 3)
self.lbr_image_set.set_visible(button_id == 1)
self.lbr_heic_file.set_visible(button_id == 2)
self.lbr_source_folder.set_visible(button_id == 3)
# Make the comboboxes invisible
for combobox in self.cb_periods:
combobox.set_visible(button_id != 1)
# +-----------+-----------+---------------+
# | Image Set | HEIC file | Source Folder |
# +-----------+-----------+---------------+
@@ -298,12 +315,7 @@ class Main_Window:
"""
if button.get_active():
self.view_model.cinnamon_prefs.image_source = ImageSourceEnum.IMAGESET
self.tb_heic_file.set_active(False)
self.tb_source_folder.set_active(False)
self.lbr_image_set.set_visible(True)
self.lbr_heic_file.set_visible(False)
self.lbr_source_folder.set_visible(False)
self.show_image_configuration_entries(1)
self.set_active_combobox_item(self.cb_image_set, self.view_model.cinnamon_prefs.selected_image_set)
@@ -311,10 +323,6 @@ class Main_Window:
selected_image_name = self.view_model.cinnamon_prefs.period_images[i]
self.set_active_combobox_item(combobox, selected_image_name)
# Make the comboboxes invisible
for combobox in self.cb_periods:
combobox.set_visible(False)
def on_toggle_button_heic_file_clicked(self, button: Gtk.ToggleButton):
""" Clicked on ToggleButton "Heic file"
@@ -324,16 +332,7 @@ class Main_Window:
"""
if button.get_active():
self.view_model.cinnamon_prefs.image_source = ImageSourceEnum.HEICFILE
self.tb_image_set.set_active(False)
self.tb_source_folder.set_active(False)
self.lbr_image_set.set_visible(False)
self.lbr_heic_file.set_visible(True)
self.lbr_source_folder.set_visible(False)
# Make the comboboxes visible
for combobox in self.cb_periods:
combobox.set_visible(True)
self.show_image_configuration_entries(2)
# Load images from source folder
files = self.images.get_images_from_folder(self.view_model.cinnamon_prefs.source_folder)
@@ -356,16 +355,7 @@ class Main_Window:
"""
if button.get_active():
self.view_model.cinnamon_prefs.image_source = ImageSourceEnum.SOURCEFOLDER
self.tb_image_set.set_active(False)
self.tb_heic_file.set_active(False)
self.lbr_image_set.set_visible(False)
self.lbr_heic_file.set_visible(False)
self.lbr_source_folder.set_visible(True)
# Make the comboboxes visible
for combobox in self.cb_periods:
combobox.set_visible(True)
self.show_image_configuration_entries(3)
# Load the source folder to the view
# This will update the comboboxes in the preview to contain the right items
@@ -414,8 +404,7 @@ class Main_Window:
# Image sets have the same names for the images:
# 9.jpg = Period 0
# 1.jpg = Period 1
# 2.jpg = Period 2
# and so on....
# 2.jpg = Period 2...
for i in range(0, 10):
self.cb_periods[i].set_active(i + 1)
@@ -446,7 +435,7 @@ class Main_Window:
image_names = self.images.get_images_from_folder(self.view_model.cinnamon_prefs.source_folder)
self.load_image_options_to_combo_boxes(image_names)
else:
self.dialogs.message_dialog("Error during extraction")
self.dialogs.message_dialog("Error during extraction!", Gtk.MessageType.ERROR)
# +------------------------------------------------------------+
@@ -508,6 +497,25 @@ class Main_Window:
## Location & Times
def show_location_times_entries(self, button_id: int):
""" Show or hide parts of the Locations & Times menu
Args:
button_id (int): ID of the button, 1 = Network, 2 = Custom Location, 3 = Custom Time Periods
"""
self.tb_network_location.set_active(button_id == 1)
self.tb_custom_location.set_active(button_id == 2)
self.tb_time_periods.set_active(button_id == 3)
# Show/Hide the right ListBoxRows
self.lbr_network_refresh_time.set_visible(button_id == 1)
self.lbr_network_provider.set_visible(button_id == 1)
self.lbr_current_location.set_visible(button_id == 1)
self.lbr_custom_location_longitude.set_visible(button_id == 2)
self.lbr_custom_location_latitude.set_visible(button_id == 2)
self.lbr_time_periods.set_visible(button_id == 3)
def on_toggle_button_network_location_clicked(self, button: Gtk.ToggleButton):
""" User clicks on the ToggleButton for the network location
@@ -516,26 +524,10 @@ class Main_Window:
"""
if button.get_active():
self.view_model.cinnamon_prefs.period_source = PeriodSourceEnum.NETWORKLOCATION
self.tb_custom_location.set_active(False)
self.tb_time_periods.set_active(False)
self.lbr_network_refresh_time.set_visible(True)
self.lbr_current_location.set_visible(True)
self.lbr_custom_location_longitude.set_visible(False)
self.lbr_custom_location_latitude.set_visible(False)
self.lbr_time_periods.set_visible(False)
self.show_location_times_entries(1)
self.spb_network_refresh_time.set_value(self.view_model.cinnamon_prefs.location_refresh_intervals)
# Display the location in the UI
current_location = self.location.get_location(NetworkLocationProvider.GEOJS)
self.lb_current_location.set_text("Latitude: " + current_location["latitude"] + \
", Longitude: " + current_location["longitude"])
# Store the location to the preferences
self.view_model.cinnamon_prefs.latitude_auto = float(current_location["latitude"])
self.view_model.cinnamon_prefs.longitude_auto = float(current_location["longitude"])
self.set_active_combobox_item(self.cb_network_provider, self.view_model.cinnamon_prefs.network_location_provider)
self.refresh_charts()
@@ -543,14 +535,7 @@ class Main_Window:
def on_toggle_button_custom_location_clicked(self, button: Gtk.ToggleButton):
if button.get_active():
self.view_model.cinnamon_prefs.period_source = PeriodSourceEnum.CUSTOMLOCATION
self.tb_network_location.set_active(False)
self.tb_time_periods.set_active(False)
self.lbr_network_refresh_time.set_visible(False)
self.lbr_current_location.set_visible(False)
self.lbr_custom_location_longitude.set_visible(True)
self.lbr_custom_location_latitude.set_visible(True)
self.lbr_time_periods.set_visible(False)
self.show_location_times_entries(2)
self.etr_latitude.set_text(str(self.view_model.cinnamon_prefs.latitude_custom))
self.etr_longitude.set_text(str(self.view_model.cinnamon_prefs.longitude_custom))
@@ -559,15 +544,7 @@ class Main_Window:
def on_toggle_button_time_periods_clicked(self, button: Gtk.ToggleButton):
if button.get_active():
self.view_model.cinnamon_prefs.period_source = PeriodSourceEnum.CUSTOMTIMEPERIODS
self.tb_network_location.set_active(False)
self.tb_custom_location.set_active(False)
self.lbr_network_refresh_time.set_visible(False)
self.lbr_current_location.set_visible(False)
self.lbr_custom_location_longitude.set_visible(False)
self.lbr_custom_location_latitude.set_visible(False)
self.lbr_time_periods.set_visible(True)
self.show_location_times_entries(3)
for i in range(0, 9):
pref_value = self.view_model.cinnamon_prefs.period_custom_start_time[i + 1]
@@ -577,7 +554,6 @@ class Main_Window:
self.spb_periods_minute[i].set_value(time_parts[1])
def on_spb_period_value_changed(self, spin_button: Gtk.SpinButton):
""" Callback if one of the time spinners (minute or hour) will be clicked
@@ -616,6 +592,28 @@ class Main_Window:
self.view_model.cinnamon_prefs.location_refresh_intervals = spin_button.get_value()
def on_cb_network_provider_changed(self, combobox: Gtk.ComboBox):
""" User changed the provider to estimate the location
Args:
combobox (Gtk.ComboBox): The used ComboBox
"""
tree_iter = combobox.get_active_iter()
if tree_iter is not None:
model = combobox.get_model()
self.view_model.cinnamon_prefs.network_location_provider = model[tree_iter][0]
success = self.view_model.refresh_location()
if success:
self.lb_current_location.set_text(\
"Latitude: " + str(self.view_model.cinnamon_prefs.latitude_auto) + ", Longitude: " + str(self.view_model.cinnamon_prefs.longitude_auto))
else:
self.dialogs.message_dialog("Error during fetching location. Are you connected to the network?", Gtk.MessageType.ERROR)
self.lb_current_location.set_text("Latitude: ?, Longitude: ?")
def on_etr_longitude_changed(self, entry: Gtk.Entry):
""" User changes the value of the longitude Entry
@@ -624,7 +622,7 @@ class Main_Window:
"""
try:
self.view_model.cinnamon_prefs.longitude_custom = float(entry.get_text())
self.refresh_chart()
self.refresh_charts()
except:
pass
@@ -637,7 +635,7 @@ class Main_Window:
"""
try:
self.view_model.cinnamon_prefs.latitude_custom = float(entry.get_text())
self.refresh_chart()
self.refresh_charts()
except:
pass
@@ -645,13 +643,25 @@ class Main_Window:
# Behaviour
def on_cb_picture_aspect_changed(self, combobox: Gtk.ComboBox):
""" User changes the value for the picture aspect ratio
Args:
combobox (Gtk.ComboBox): The used ComboBox
"""
tree_iter = combobox.get_active_iter()
if tree_iter is not None:
model = combobox.get_model()
self.view_model.cinnamon_prefs.picture_aspect = model[tree_iter][0]
def on_sw_dynamic_background_color_state_set(self, switch: Gtk.Switch, state):
def on_sw_dynamic_background_color_state_set(self, _: Gtk.Switch, state: bool):
""" User switches dynamic background on or off
Args:
_ (Gtk.Switch): Used Switch
state (bool): Current state
"""
self.view_model.cinnamon_prefs.dynamic_background_color = state

View File

@@ -1,5 +1,5 @@
{
"external-configuration-app": "src/test.py",
"external-configuration-app": "src/main.py",
"uuid": "cinnamon-dynamic-wallpaper@TobiZog",
"name": "Cinnamon Dynamic Wallpaper",
"description": "Cinnamon extension for dynamic desktop backgrounds based on time and location",