Refactored db setup; extended layout to add header widget zone

This commit is contained in:
itdominator 2023-11-19 15:37:11 -06:00
parent f9707c8d6e
commit 1986bab879
10 changed files with 155 additions and 41 deletions

View File

@ -8,6 +8,8 @@ A template project for Python with Gtk applications.
* sqlmodel (SQL databases and is powered by Pydantic and SQLAlchemy)
### Note
* Move respetive sub folder content under user_config to the same places in Linux. Though, user/share/<app name> can go to ~/.config folder if prefered.
* In additiion, place the plugins folder in the same app folder you moved to /usr/share/<app name> or ~/.config/<app name> .
There are a "\<change_me\>" strings and files that need to be set according to your app's name located at:
* \_\_builtins\_\_.py
* user_config/bin/app_name
@ -18,4 +20,4 @@ There are a "\<change_me\>" strings and files that need to be set according to y
For the user_config, after changing names and files, copy all content to their respective destinations.
The logic follows Debian Dpkg packaging and its placement logic.
The logic follows Debian Dpkg packaging and its placement logic.

View File

@ -6,7 +6,7 @@ import sys
# Lib imports
# Application imports
from utils.models import engine
from utils.db import DB
from utils.event_system import EventSystem
from utils.endpoint_registry import EndpointRegistry
from utils.keybindings import Keybindings
@ -18,13 +18,17 @@ from utils.settings_manager.manager import SettingsManager
# NOTE: Threads WILL NOT die with parent's destruction.
def threaded_wrapper(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
thread = threading.Thread(target = fn, args = args, kwargs = kwargs, daemon = False)
thread.start()
return thread
return wrapper
# NOTE: Threads WILL die with parent's destruction.
def daemon_threaded_wrapper(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
thread = threading.Thread(target = fn, args = args, kwargs = kwargs, daemon = True)
thread.start()
return thread
return wrapper
@ -32,12 +36,12 @@ def daemon_threaded_wrapper(fn):
# NOTE: Just reminding myself we can add to builtins two different ways...
# __builtins__.update({"event_system": Builtins()})
builtins.app_name = "<change_me>"
builtins.db = engine
builtins.keybindings = Keybindings()
builtins.event_system = EventSystem()
builtins.endpoint_registry = EndpointRegistry()
builtins.settings_manager = SettingsManager()
builtins.db = DB()
settings_manager.load_settings()
@ -58,4 +62,4 @@ def custom_except_hook(exc_type, exc_value, exc_traceback):
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
sys.excepthook = custom_except_hook
sys.excepthook = custom_except_hook

View File

@ -15,6 +15,7 @@ class AppLaunchException(Exception):
...
class Application(IPCServer):
""" docstring for Application. """
@ -30,7 +31,7 @@ class Application(IPCServer):
message = f"FILE|{arg}"
self.send_ipc_message(message)
raise AppLaunchException(f"{app_name} IPC Server Exists: Will send path(s) to it and close...")
raise AppLaunchException(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...")
self.setup_debug_hook()
Window(args, unknownargs)
@ -56,4 +57,4 @@ class Application(IPCServer):
)
except ValueError:
# Typically: ValueError: signal only works in main thread
...
...

View File

@ -6,9 +6,8 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from .left_container import LeftContainer
from .center_container import CenterContainer
from .right_container import RightContainer
from .header_container import HeaderContainer
from .body_container import BodyContainer
@ -38,12 +37,11 @@ class BaseContainer(Gtk.Box):
event_system.subscribe("remove_transparency", self._remove_transparency)
def _load_widgets(self):
self.add(LeftContainer())
self.add(CenterContainer())
self.add(RightContainer())
self.add(HeaderContainer())
self.add(BodyContainer())
def _update_transparency(self):
self.ctx.add_class(f"mw_transparency_{settings.theming.transparency}")
def _remove_transparency(self):
self.ctx.remove_class(f"mw_transparency_{settings.theming.transparency}")
self.ctx.remove_class(f"mw_transparency_{settings.theming.transparency}")

View File

@ -0,0 +1,44 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from .left_container import LeftContainer
from .center_container import CenterContainer
from .right_container import RightContainer
class BodyContainer(Gtk.Box):
def __init__(self):
super(BodyContainer, self).__init__()
self.ctx = self.get_style_context()
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show_all()
def _setup_styling(self):
self.set_orientation(Gtk.Orientation.HORIZONTAL)
self.ctx.add_class("body-container")
self.set_homogeneous(True)
def _setup_signals(self):
...
def _subscribe_to_events(self):
...
def _load_widgets(self):
self.add(LeftContainer())
self.add(CenterContainer())
self.add(RightContainer())

View File

@ -6,7 +6,7 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from ..widgets.transparency_scale import TransparencyScale
class CenterContainer(Gtk.Box):
@ -35,21 +35,12 @@ class CenterContainer(Gtk.Box):
def _load_widgets(self):
glade_box = self._builder.get_object("glade_box")
glade_box = self._builder.get_object("glade_box")
button = Gtk.Button(label = "Interactive Debug")
button2 = Gtk.Button(label = "Click Me!")
button = Gtk.Button(label = "Click Me!")
button.connect("clicked", self._interactive_debug)
button2.connect("clicked", self._hello_world)
button.connect("clicked", self._hello_world)
self.add(TransparencyScale())
self.add(button)
self.add(button2)
self.add(glade_box)
def _interactive_debug(self, widget = None, eve = None):
event_system.emit("load_interactive_debug")
def _hello_world(self, widget = None, eve = None):
logger.debug("Hello, World!")
logger.debug("Hello, World!")

View File

@ -0,0 +1,46 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from ..widgets.transparency_scale import TransparencyScale
class HeaderContainer(Gtk.Box):
def __init__(self):
super(HeaderContainer, self).__init__()
self.ctx = self.get_style_context()
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show_all()
def _setup_styling(self):
self.set_orientation(Gtk.Orientation.HORIZONTAL)
self.ctx.add_class("header-container")
def _setup_signals(self):
...
def _subscribe_to_events(self):
...
def _load_widgets(self):
button = Gtk.Button(label = "Interactive Debug")
button.connect("clicked", self._interactive_debug)
self.add(TransparencyScale())
self.add(button)
def _interactive_debug(self, widget = None, eve = None):
event_system.emit("load_interactive_debug")

View File

@ -26,7 +26,7 @@ class TransparencyScale(Gtk.Scale):
self.set_digits(0)
self.set_value_pos(Gtk.PositionType.RIGHT)
self.add_mark(50.0, Gtk.PositionType.TOP, "50%")
self.set_hexpand(True)
def _setup_signals(self):
self.connect("value-changed", self._update_transparency)
@ -45,4 +45,4 @@ class TransparencyScale(Gtk.Scale):
event_system.emit("remove_transparency")
tp = int(range.get_value())
settings.theming.transparency = tp
event_system.emit("update_transparency")
event_system.emit("update_transparency")

38
src/utils/db.py Normal file
View File

@ -0,0 +1,38 @@
# Python imports
from typing import Optional
from os import path
# Lib imports
from sqlmodel import Session, create_engine
# Application imports
from .models import SQLModel, User
class DB:
def __init__(self):
super(DB, self).__init__()
self.create_engine()
# NOTE: for sake of example we create an admin user with no password set.
self.add_user_entry(name = "Admin", password = "", email = "admin@domain.com")
def create_engine(self):
db_path = f"sqlite:///{settings_manager.get_home_config_path()}/database.db"
self.engine = create_engine(db_path)
SQLModel.metadata.create_all(self.engine)
def _add_entry(self, entry):
with Session(self.engine) as session:
session.add(entry)
session.commit()
def add_user_entry(self, name = None, password = None, email = None):
if not name or not password or not email: return
user = User(name, password, email)
self._add_entry(user)

View File

@ -2,7 +2,7 @@
from typing import Optional
# Lib imports
from sqlmodel import Field, Session, SQLModel, create_engine
from sqlmodel import SQLModel, Field
# Application imports
@ -13,13 +13,3 @@ class User(SQLModel, table = True):
name: str
password: str
email: Optional[str] = None
# NOTE: for sake of example we create an admin user with no password set.
user = User(name = "Admin", password = "", email = "admin@domain.com")
engine = create_engine("sqlite:///database.db")
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
session.add(user)
session.commit()