diff --git a/src/host_info.py b/src/host_info.py index 1db56d1..dbf1395 100644 --- a/src/host_info.py +++ b/src/host_info.py @@ -238,6 +238,7 @@ class HostInfo: icon_theme.add_search_path(f"{i}/exports/share/icons") flatpaks = [] + id_to_flatpak = {} ref_to_flatpak = {} remotes = {} installations = [] @@ -248,6 +249,7 @@ class HostInfo: def get_flatpaks(this, callback=None): # Callback is a function to run after the host flatpaks are found this.flatpaks.clear() + this.id_to_flatpak.clear() this.ref_to_flatpak.clear() this.remotes.clear() this.installations.clear() @@ -336,6 +338,7 @@ class HostInfo: for i in lines: package = Flatpak(i.split("\t")) this.flatpaks.append(package) + this.id_to_flatpak[package.info["id"]] = package this.ref_to_flatpak[package.info["ref"]] = package # Dependant Runtimes diff --git a/src/main_window/window.py b/src/main_window/window.py index 9825f1e..1197e6d 100644 --- a/src/main_window/window.py +++ b/src/main_window/window.py @@ -63,12 +63,14 @@ class WarehouseWindow(Adw.ApplicationWindow): page.instance.start_loading() def end_loading(self, *args): - for _, page in self.pages.items(): - if page.instance: - page.instance.end_loading() + for _, page in self.pages.items(): + if page.instance: + page.instance.end_loading() + self.refresh_button.set_sensitive(True) def refresh_handler(self, *args): self.start_loading() + self.refresh_button.set_sensitive(False) HostInfo.get_flatpaks(callback=self.end_loading) def __init__(self, **kwargs): diff --git a/src/meson.build b/src/meson.build index e1a2b70..139d30d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,8 +12,7 @@ blueprints = custom_target('blueprints', 'properties_page/properties_page.blp', 'user_data_page/data_box.blp', 'user_data_page/user_data_page.blp', - 'user_data_page/active_data_page.blp', - 'user_data_page/leftover_data_page.blp', + 'user_data_page/data_subpage.blp', 'change_version_page/change_version_page.blp', ), output: '.', @@ -66,8 +65,7 @@ warehouse_sources = [ 'change_version_page/change_version_page.py', 'user_data_page/data_box.py', 'user_data_page/user_data_page.py', - 'user_data_page/active_data_page.py', - 'user_data_page/leftover_data_page.py', + 'user_data_page/data_subpage.py', '../data/style.css', ] diff --git a/src/user_data_page/active_data_page.blp b/src/user_data_page/active_data_page.blp deleted file mode 100644 index 2040566..0000000 --- a/src/user_data_page/active_data_page.blp +++ /dev/null @@ -1,41 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $ActiveDataPage : ScrolledWindow { - Box { - orientation: vertical; - Box { - orientation: vertical; - margin-start: 24; - margin-end: 24; - Label { - label: _("Active User Data"); - styles ["title-1"] - hexpand: true; - halign: start; - } - Label { - label: "32 Items - 39.7 GB"; - styles ["title-3"] - hexpand: true; - halign: start; - } - } - Separator { - margin-start: 12; - margin-end: 12; - margin-top: 9; - margin-bottom: 6; - } - FlowBox flow_box { - styles ["boxed-list"] - homogeneous: true; - valign: start; - selection-mode: none; - max-children-per-line: 6; - margin-start: 12; - margin-end: 12; - margin-bottom: 12; - } - } -} \ No newline at end of file diff --git a/src/user_data_page/active_data_page.py b/src/user_data_page/active_data_page.py deleted file mode 100644 index 04ca401..0000000 --- a/src/user_data_page/active_data_page.py +++ /dev/null @@ -1,31 +0,0 @@ -from gi.repository import Adw, Gtk, GLib, Gio, Pango -from .host_info import HostInfo -from .error_toast import ErrorToast -from .data_box import DataBox -import pathlib, os - -@Gtk.Template(resource_path="/io/github/flattool/Warehouse/user_data_page/active_data_page.ui") -class ActiveDataPage(Gtk.ScrolledWindow): - __gtype_name__ = 'ActiveDataPage' - gtc = Gtk.Template.Child - - flow_box = gtc() - - def generate_list(self, *args): - data = f"{HostInfo.home}/.var/app" - for folder in os.listdir(data): - print(folder) - - def __init__(self, main_window, data_page, **kwargs): - super().__init__(**kwargs) - - self.generate_list() - - # self.select_button.connect("toggled", lambda *_: self.set_selection_mode(self.select_button.get_active())) - # self.flow_box.connect("child-activated", lambda _, item: (cb := (row := item.get_child()).check_button).set_active((not cb.get_active()) if row.get_activatable() else False)) - - # Extra Object Creation - - # Apply - - # Connections \ No newline at end of file diff --git a/src/user_data_page/data_box.blp b/src/user_data_page/data_box.blp index 695d814..05ac3bf 100644 --- a/src/user_data_page/data_box.blp +++ b/src/user_data_page/data_box.blp @@ -13,7 +13,7 @@ template $DataBox : ListBox { Box title_box { margin-top: 12; margin-bottom: 12; - Image app_icon { + Image image { margin-start: 12; margin-end: 12; icon-name: "application-x-executable-symbolic"; @@ -31,7 +31,7 @@ template $DataBox : ListBox { } Label subtitle_label { label: "No subtitle set"; - hexpand: true; + // hexpand: true; halign: start; ellipsize: middle; margin-end: 12; @@ -43,6 +43,9 @@ template $DataBox : ListBox { margin-start: 12; margin-end: 6; margin-bottom: 6; + Spinner spinner { + spinning: true; + } Label size_label { label: "No size set"; halign: start; diff --git a/src/user_data_page/data_box.py b/src/user_data_page/data_box.py index 6dac6f7..c73cb89 100644 --- a/src/user_data_page/data_box.py +++ b/src/user_data_page/data_box.py @@ -1,13 +1,32 @@ from gi.repository import Adw, Gtk, GLib, Gio, Pango from .host_info import HostInfo +import subprocess @Gtk.Template(resource_path="/io/github/flattool/Warehouse/user_data_page/data_box.ui") class DataBox(Gtk.ListBox): __gtype_name__ = 'DataBox' gtc = Gtk.Template.Child + image = gtc() title_label = gtc() + subtitle_label = gtc() + size_label = gtc() check_button = gtc() - def __init__(self, main_window, path, **kwargs): - super().__init__(**kwargs) \ No newline at end of file + def idle_stuff(self): + self.title_label.set_label(self.title) + self.subtitle_label.set_label(self.subtitle) + if self.icon_path: + self.image.add_css_class("icon-dropshadow") + self.image.set_from_file(self.icon_path) + + def __init__(self, title, subtitle, data_path, icon_path=None, callback=None, **kwargs): + super().__init__(**kwargs) + + self.title = title + self.subtitle = subtitle + self.icon_path = icon_path + self.data_path = data_path + self.callback = callback + + self.idle_stuff() diff --git a/src/user_data_page/data_subpage.blp b/src/user_data_page/data_subpage.blp new file mode 100644 index 0000000..01f1e40 --- /dev/null +++ b/src/user_data_page/data_subpage.blp @@ -0,0 +1,60 @@ +using Gtk 4.0; +using Adw 1; + +template $DataSubpage : ScrolledWindow { + Box { + orientation: vertical; + Box { + orientation: vertical; + margin-start: 24; + margin-end: 24; + Label title { + label: _("No Title Set"); + styles ["title-1"] + hexpand: true; + halign: start; + } + Box { + Label subtitle { + label: "No Subtutle Set"; + styles ["title-3"] + } + Image { + icon-name: "dot-symbolic"; + margin-start: 6; + margin-end: 6; + margin-top: 3; + valign: center; + } + Spinner spinner { + spinning: true; + valign: center; + margin-top: 3; + margin-end: 6; + } + Label size_label { + label: _("Loading Size…"); + styles ["title-3"] + hexpand: true; + halign: start; + } + } + } + Separator { + margin-start: 12; + margin-end: 12; + margin-top: 9; + margin-bottom: 6; + } + FlowBox flow_box { + styles ["boxed-list"] + homogeneous: true; + valign: start; + selection-mode: none; + max-children-per-line: 6; + margin-start: 12; + margin-end: 12; + margin-bottom: 12; + } + } +} \ No newline at end of file diff --git a/src/user_data_page/data_subpage.py b/src/user_data_page/data_subpage.py new file mode 100644 index 0000000..be3c645 --- /dev/null +++ b/src/user_data_page/data_subpage.py @@ -0,0 +1,86 @@ +from gi.repository import Adw, Gtk, GLib, Gio, Pango +from .host_info import HostInfo +from .error_toast import ErrorToast +from .data_box import DataBox +from .host_info import HostInfo +import subprocess + +@Gtk.Template(resource_path="/io/github/flattool/Warehouse/user_data_page/data_subpage.ui") +class DataSubpage(Gtk.ScrolledWindow): + __gtype_name__ = 'DataSubpage' + gtc = Gtk.Template.Child + + title = gtc() + subtitle = gtc() + spinner = gtc() + size_label = gtc() + flow_box = gtc() + + def human_readable_size(self, size): + units = ['KB', 'MB', 'GB', 'TB'] + # size *= 1024 + for unit in units: + if size < 1024: + return f"~ {round(size)} {unit}" + size /= 1024 + return f"~ {round(size)} PB" + + def get_size(self, path): + sed = "sed 's/K/ KB/; s/M/ MB/; s/G/ GB/; s/T/ TB/; s/P/ PB/;'" + self.total_size += int(subprocess.run(['du', '-s', path], capture_output=True, text=True).stdout.split("\t")[0]) + + def show_size(self, data): + for folder in data: + self.get_size(f"{HostInfo.home}/.var/app/{folder}") + + self.size_label.set_label(self.human_readable_size(self.total_size)) + self.spinner.set_visible(False) + + def generate_list(self, sort_mode, data=None, paks=None): + self.total_size = 0 + Gio.Task().run_in_thread(lambda *_: self.show_size(data)) + self.flow_box.remove_all() + total = len(data) + GLib.idle_add(lambda *_z: self.subtitle.set_label(_("{} Items").format(total))) + self.boxes.clear() + + def thread(sort_mode, data, paks): + if paks: + for package in paks: + folder = package.info["id"] + box = DataBox(package.info["name"], folder, f"{HostInfo.home}/.var/app/{folder}", package.icon_path) + self.boxes.append(box) + else: + for folder in data: + box = DataBox(folder.split('.')[-1], folder, f"{HostInfo.home}/.var/app/{folder}") + self.boxes.append(box) + + def callback(sort_mode): + if sort_mode == "name": + self.boxes = sorted(self.boxes, key=lambda box: box.title) + elif sort_mode == "id": + self.boxes = sorted(self.boxes, key=lambda box: box.subtitle) + else: + pass + + for box in self.boxes: + self.flow_box.append(box) + + Gio.Task.new(None, None, lambda *_: callback(sort_mode)).run_in_thread(lambda *_: thread(sort_mode, data, paks)) + + def __init__(self, title, main_window, **kwargs): + super().__init__(**kwargs) + + GLib.idle_add(lambda *_: self.title.set_label(title)) + + # self.select_button.connect("toggled", lambda *_: self.set_selection_mode(self.select_button.get_active())) + # self.flow_box.connect("child-activated", lambda _, item: (cb := (row := item.get_child()).check_button).set_active((not cb.get_active()) if row.get_activatable() else False)) + + # Extra Object Creation + self.main_window = main_window + self.total_size = 0 + self.boxes = [] + + # Apply + + # Connections \ No newline at end of file diff --git a/src/user_data_page/leftover_data_page.blp b/src/user_data_page/leftover_data_page.blp deleted file mode 100644 index 2e6aa44..0000000 --- a/src/user_data_page/leftover_data_page.blp +++ /dev/null @@ -1,41 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $LeftoverDataPage : ScrolledWindow { - Box { - orientation: vertical; - Box { - orientation: vertical; - margin-start: 24; - margin-end: 24; - Label { - label: _("Leftover User Data"); - styles ["title-1"] - hexpand: true; - halign: start; - } - Label { - label: "25 Items - 18.6 GB"; - styles ["title-3"] - hexpand: true; - halign: start; - } - } - Separator { - margin-start: 12; - margin-end: 12; - margin-top: 9; - margin-bottom: 6; - } - FlowBox { - styles ["boxed-list"] - homogeneous: true; - valign: start; - selection-mode: none; - max-children-per-line: 6; - margin-start: 12; - margin-end: 12; - margin-bottom: 12; - } - } -} \ No newline at end of file diff --git a/src/user_data_page/leftover_data_page.py b/src/user_data_page/leftover_data_page.py deleted file mode 100644 index 84d0c0c..0000000 --- a/src/user_data_page/leftover_data_page.py +++ /dev/null @@ -1,18 +0,0 @@ -from gi.repository import Adw, Gtk, GLib, Gio, Pango -from .host_info import HostInfo -from .error_toast import ErrorToast -from .data_box import DataBox - -@Gtk.Template(resource_path="/io/github/flattool/Warehouse/user_data_page/leftover_data_page.ui") -class LeftoverDataPage(Gtk.ScrolledWindow): - __gtype_name__ = 'LeftoverDataPage' - gtc = Gtk.Template.Child - - def __init__(self, main_window, data_page, **kwargs): - super().__init__(**kwargs) - - # Extra Object Creation - - # Apply - - # Connections \ No newline at end of file diff --git a/src/user_data_page/user_data_page.py b/src/user_data_page/user_data_page.py index 4424db5..aa0fdd4 100644 --- a/src/user_data_page/user_data_page.py +++ b/src/user_data_page/user_data_page.py @@ -1,7 +1,9 @@ from gi.repository import Adw, Gtk, GLib, Gio, Pango from .error_toast import ErrorToast -from .active_data_page import ActiveDataPage -from .leftover_data_page import LeftoverDataPage +from .data_box import DataBox +from .data_subpage import DataSubpage +from .host_info import HostInfo +import os @Gtk.Template(resource_path="/io/github/flattool/Warehouse/user_data_page/user_data_page.ui") class UserDataPage(Adw.BreakpointBin): @@ -47,11 +49,33 @@ class UserDataPage(Adw.BreakpointBin): # elif self.switcher_bar.get_reveal(): # self.header_bar.set_show_title(False) + def sort_data(self, *args): + self.data_flatpaks.clear() + self.active_data.clear() + self.leftover_data.clear() + # paks = dict(HostInfo.id_to_flatpak) + + for folder in os.listdir(f"{HostInfo.home}/.var/app"): + try: + self.data_flatpaks.append(HostInfo.id_to_flatpak[folder]) + self.active_data.append(folder) + except KeyError: + self.leftover_data.append(folder) + def start_loading(self, *args): + self.adp.size_label.set_label("Loading Size…") + self.adp.spinner.set_visible(True) + self.ldp.size_label.set_label("Loading Size…") + self.ldp.spinner.set_visible(True) pass def end_loading(self, *args): - pass + self.sort_mode = "id" + def callback(*args): + self.adp.generate_list(self.sort_mode, data=self.active_data, paks=self.data_flatpaks) + self.ldp.generate_list(self.sort_mode, data=self.leftover_data) + + Gio.Task.new(None, None, callback).run_in_thread(self.sort_data) def __init__(self, main_window, **kwargs): super().__init__(**kwargs) @@ -59,16 +83,22 @@ class UserDataPage(Adw.BreakpointBin): # Extra Object Creation self.__class__.instance = self # self.adj = self.scrolled_window.get_vadjustment() + self.adp = DataSubpage(_("Active Data"), main_window) + self.ldp = DataSubpage(_("Leftover Data"), main_window) + self.data_flatpaks = [] + self.active_data = [] + self.leftover_data = [] + self.total_items = 0 # Apply self.stack.add_titled_with_icon( - child=ActiveDataPage(main_window, self), + child=self.adp, name="active", title=_("Active Data"), icon_name="file-manager-symbolic", ) self.stack.add_titled_with_icon( - child=LeftoverDataPage(main_window, self), + child=self.ldp, name="leftover", title=_("Leftover Data"), icon_name="folder-templates-symbolic", diff --git a/src/warehouse.gresource.xml b/src/warehouse.gresource.xml index 5403771..775fd45 100644 --- a/src/warehouse.gresource.xml +++ b/src/warehouse.gresource.xml @@ -11,8 +11,7 @@ change_version_page/change_version_page.ui user_data_page/data_box.ui user_data_page/user_data_page.ui - user_data_page/active_data_page.ui - user_data_page/leftover_data_page.ui + user_data_page/data_subpage.ui