Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Startup time + stuttering #375

Merged
merged 1 commit into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions vanilla_installer/core/timezones.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import datetime
import logging

import requests
from gi.repository import GnomeDesktop
from gi.repository import GWeather
from gi.repository import GLib, GWeather
from zoneinfo import ZoneInfo

regions = {}
logger = logging.getLogger("VanillaInstaller::Timezones")

regions: dict[str, dict[str, dict[str, str]]] = {}
world = GWeather.Location.get_world()
parents = []
base = world
Expand All @@ -20,7 +22,9 @@
regions[current_region][child.get_name()] = {}
current_country = child.get_name()
elif child.get_level() == GWeather.LocationLevel.CITY:
regions[current_region][current_country][child.get_city_name()] = child.get_timezone_str()
regions[current_region][current_country][child.get_city_name()] = (
child.get_timezone_str()
)

if child.next_child(None) is not None:
parents.append(child)
Expand All @@ -34,21 +38,37 @@

all_timezones = dict(sorted(regions.items()))

def get_location():

def get_location(callback=None):
logger.info("Trying to retrieve timezone automatically")
try:
res = requests.get("http://ip-api.com/json?fields=49344", timeout=3).json()
if res["status"] != "success":
raise Exception(f"get_location: request failed with message '{res['message']}'")
nearest = world.find_nearest_city(res["lat"], res["lon"])
except Exception as e:
print(e)
logger.error(f"Failed to retrieve timezone: {e}")
nearest = None

return nearest
logger.info("Done retrieving timezone")

if callback:
logger.info("Running callback")
GLib.idle_add(callback, nearest)

def get_timezone_preview(tzname):
timezone = ZoneInfo(tzname)
now = datetime.datetime.now(timezone)

return now.strftime("%H:%M"), now.strftime("%A, %d %B %Y")
tz_preview_cache: dict[str, tuple[str, str]] = {}


def get_timezone_preview(tzname):
if tzname in tz_preview_cache:
return tz_preview_cache[tzname]
else:
timezone = ZoneInfo(tzname)
now = datetime.datetime.now(timezone)
now_str = (
"%02d:%02d" % (now.hour, now.minute),
now.strftime("%A, %d %B %Y"),
)
tz_preview_cache[tzname] = now_str
return now_str
2 changes: 1 addition & 1 deletion vanilla_installer/defaults/disk.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ def __init__(self, window, partition_recipe, **kwargs):
)
)
self.group_partitions.add(entry)

if "auto" in partition_recipe:
for vg in partition_recipe["auto"]["vgs_to_remove"]:
entry = Adw.ActionRow()
Expand Down
20 changes: 10 additions & 10 deletions vanilla_installer/defaults/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from operator import attrgetter
from threading import Lock, Timer

from gi.repository import NM, NMA4, Adw, Gtk, GLib
from gi.repository import NM, NMA4, Adw, GLib, Gtk

from vanilla_installer.utils.run_async import RunAsync

Expand Down Expand Up @@ -115,9 +115,7 @@ def refresh_ui(self):
if not secure:
self.secure_icon.set_from_icon_name("warning-small-symbolic")
else:
self.secure_icon.set_from_icon_name(
"network-wireless-encrypted-symbolic"
)
self.secure_icon.set_from_icon_name("network-wireless-encrypted-symbolic")

self.secure_icon.set_visible(secure is not None)
if tooltip is not None:
Expand Down Expand Up @@ -254,6 +252,7 @@ def __init__(self, window, distro_info, key, step, **kwargs):
self.__key = key
self.__step = step
self.__nm_client = NM.Client.new()
self.__step_num = step["num"]

self.__devices = []
self.__wired_children = []
Expand All @@ -280,9 +279,12 @@ def __init__(self, window, distro_info, key, step, **kwargs):
self.__nm_client.connect("device-added", self.__add_new_device)
self.__nm_client.connect("device-added", self.__remove_device)
self.btn_next.connect("clicked", self.__window.next)
self.connect("realize", self.__try_skip_page)
self.__window.carousel.connect("page-changed", self.__try_skip_page)

def __try_skip_page(self, carousel=None, idx=None):
if idx is not None and idx != self.__step_num:
return

def __try_skip_page(self, data):
# Skip page if already connected to the internet
if self.has_eth_connection or self.has_wifi_connection:
self.__window.next()
Expand Down Expand Up @@ -316,9 +318,7 @@ def __get_network_devices(self):
eth_devices += 1
elif device_type == NM.DeviceType.WIFI:
device.connect("state-changed", self.__on_state_changed)
self.has_wifi_connection = (
device.get_active_connection() is not None
)
self.has_wifi_connection = device.get_active_connection() is not None
self.__refresh_wifi_list(device)
wifi_devices += 1
else:
Expand Down Expand Up @@ -419,7 +419,7 @@ def __poll_wifi_scan(self, conn: NM.DeviceWifi, last_known_scan: int):
GLib.idle_add(self.__refresh_wifi_list, conn)

def __refresh_wifi_list(self, conn: NM.DeviceWifi):
networks = {}
networks: dict[str, list[NM.AccessPoint]] = {}
for ap in conn.get_access_points():
ssid = ap.get_ssid()
if ssid is None:
Expand Down
140 changes: 65 additions & 75 deletions vanilla_installer/defaults/timezone.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import logging
import re
import threading
import unicodedata

from gi.repository import Adw, Gtk, GLib
from gettext import gettext as _

from gi.repository import Adw, GLib, Gtk

from vanilla_installer.core.timezones import (
all_timezones,
get_location,
get_timezone_preview,
)
from vanilla_installer.utils.run_async import RunAsync

logger = logging.getLogger("VanillaInstaller::Timezone")


@Gtk.Template(resource_path="/org/vanillaos/Installer/gtk/widget-timezone.ui")
Expand All @@ -35,30 +38,22 @@ class TimezoneRow(Adw.ActionRow):
select_button = Gtk.Template.Child()
country_label = Gtk.Template.Child()

def __init__(self, title, subtitle, tz_name, parent, **kwargs):
def __init__(self, title, subtitle, tz_name, toggled_callback, parent_expander, **kwargs):
super().__init__(**kwargs)
self.title = title
self.subtitle = subtitle
self.parent = parent
self.tz_name = tz_name

tz_time, tz_date = get_timezone_preview(tz_name)
self.parent_expander = parent_expander

self.set_title(title)
self.set_subtitle(f"{tz_time} • {tz_date}")
self.country_label.set_label(tz_name)

self.select_button.connect("toggled", self.__on_check_button_toggled)
self.select_button.connect("toggled", toggled_callback, self)
self.parent_expander.connect("notify::expanded", self.update_time_preview)

def __on_check_button_toggled(self, widget):
tz_split = self.tz_name.split("/", 1)
self.parent.selected_timezone["region"] = tz_split[0]
self.parent.selected_timezone["zone"] = tz_split[1]
self.parent.current_tz_label.set_label(self.tz_name)
self.parent.current_location_label.set_label(
_("(at %s, %s)") % (self.title, self.subtitle)
)
self.parent.timezone_verify()
def update_time_preview(self, *args):
tz_time, tz_date = get_timezone_preview(self.tz_name)
self.set_subtitle(f"{tz_time} • {tz_date}")


@Gtk.Template(resource_path="/org/vanillaos/Installer/gtk/default-timezone.ui")
Expand All @@ -74,18 +69,23 @@ class VanillaDefaultTimezone(Adw.Bin):
search_controller = Gtk.EventControllerKey.new()
selected_timezone = {"region": "Europe", "zone": None}

expanders_list = {
country: region
for region, countries in all_timezones.items()
for country in countries.keys()
}
expanders_list = dict(
sorted(
{
country: region
for region, countries in all_timezones.items()
for country in countries.keys()
}.items()
)
)

def __init__(self, window, distro_info, key, step, **kwargs):
super().__init__(**kwargs)
self.__window = window
self.__distro_info = distro_info
self.__key = key
self.__step = step
self.__step_num = step["num"]

self.__expanders = []
self.__tz_entries = []
Expand All @@ -98,12 +98,24 @@ def __init__(self, window, distro_info, key, step, **kwargs):
self.search_controller.connect("key-released", self.__on_search_key_pressed)
self.entry_search_timezone.add_controller(self.search_controller)

def timezone_verify(self, *args):
valid = (
self.selected_timezone["region"]
and self.selected_timezone["zone"] is not None
)
self.btn_next.set_sensitive(valid)
def timezone_verify(self, carousel=None, idx=None):
if idx is not None and idx != self.__step_num:
return

def timezone_verify_callback(result, *args):
if result:
current_city = result.get_city_name()
current_country = result.get_country_name()
for entry in self.__tz_entries:
if current_city == entry.title and current_country == entry.subtitle:
self.selected_timezone["zone"] = current_city
self.selected_timezone["region"] = current_country
entry.select_button.set_active(True)
return
self.btn_next.set_sensitive(True)

thread = threading.Thread(target=get_location, args=(timezone_verify_callback,))
thread.start()

def get_finals(self):
try:
Expand All @@ -118,11 +130,7 @@ def get_finals(self):

def __on_search_key_pressed(self, *args):
def remove_accents(msg: str):
out = (
unicodedata.normalize("NFD", msg)
.encode("ascii", "ignore")
.decode("utf-8")
)
out = unicodedata.normalize("NFD", msg).encode("ascii", "ignore").decode("utf-8")
return str(out)

search_entry = self.entry_search_timezone.get_text().lower()
Expand All @@ -147,48 +155,30 @@ def remove_accents(msg: str):
visible_entries = 0
current_country = entry.subtitle
current_expander += 1
visible_entries += 1 if match else 0
visible_entries += match

def __on_row_toggle(self, __check_button, widget):
tz_split = widget.tz_name.split("/", 1)
self.selected_timezone["region"] = tz_split[0]
self.selected_timezone["zone"] = tz_split[1]
self.current_tz_label.set_label(widget.tz_name)
self.current_location_label.set_label(_("(at %s, %s)") % (widget.title, widget.subtitle))
self.btn_next.set_sensitive(True)

def __generate_timezone_list_widgets(self):
def __populate_expanders():
widgets = {}
first_elem = None
for country, region in dict(sorted(self.expanders_list.items())).items():
if len(all_timezones[region][country]) > 0:
country_tz_expander_row = Adw.ExpanderRow.new()
country_tz_expander_row.set_title(country)
country_tz_expander_row.set_subtitle(region)
widgets[country_tz_expander_row] = []
for city, tzname in sorted(all_timezones[region][country].items()):
timezone_row = TimezoneRow(city, country, tzname, self)
if first_elem is None:
first_elem = timezone_row
else:
timezone_row.select_button.set_group(
first_elem.select_button
)
widgets[country_tz_expander_row].append(timezone_row)
return widgets

def __set_located_timezone(result, *args):
if not result:
return
current_city = result.get_city_name()
current_country = result.get_country_name()
for entry in self.__tz_entries:
if current_city == entry.title and current_country == entry.subtitle:
self.selected_timezone["zone"] = current_city
self.selected_timezone["region"] = current_country
entry.select_button.set_active(True)
return

def __callback(widgets, *args):
for expander, timezone_rows in widgets.items():
def __populate_expander(expander, region, country, *args):
for city, tzname in all_timezones[region][country].items():
timezone_row = TimezoneRow(city, country, tzname, self.__on_row_toggle, expander)
self.__tz_entries.append(timezone_row)
if len(self.__tz_entries) > 0:
timezone_row.select_button.set_group(self.__tz_entries[0].select_button)
expander.add_row(timezone_row)

for country, region in self.expanders_list.items():
if len(all_timezones[region][country]) > 0:
expander = Adw.ExpanderRow.new()
expander.set_title(country)
expander.set_subtitle(region)
self.all_timezones_group.add(expander)
self.__expanders.append(expander)
for timezone_row in timezone_rows:
expander.add_row(timezone_row)
self.__tz_entries.append(timezone_row)
RunAsync(get_location, __set_located_timezone)

RunAsync(__populate_expanders, __callback)
GLib.idle_add(__populate_expander, expander, region, country)
3 changes: 2 additions & 1 deletion vanilla_installer/defaults/welcome.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from vanilla_installer.windows.dialog_recovery import VanillaRecoveryDialog
from vanilla_installer.windows.dialog_poweroff import VanillaPoweroffDialog


@Gtk.Template(resource_path="/org/vanillaos/Installer/gtk/default-welcome.ui")
class VanillaDefaultWelcome(Adw.Bin):
__gtype_name__ = "VanillaDefaultWelcome"
Expand All @@ -37,7 +38,7 @@ def __init__(self, window, distro_info, key, step, **kwargs):

distro_name = self.__distro_info.get("name", "Vanilla OS")
distro_logo = self.__distro_info.get("logo", "org.vanillaos.Installer-flower")

self.status_page.set_icon_name(distro_logo)
self.status_page.set_title(f"Welcome to {distro_name}!")

Expand Down
Loading