License WIP
This commit is contained in:
parent
484b420e40
commit
2d867a83d0
|
|
@ -1 +1 @@
|
|||
Subproject commit b2cdc8cc5fc593ab04015cec08a8e97b103ffa63
|
||||
Subproject commit 0f438e4d2d489745059d260fe55a553a038e6e0f
|
||||
|
|
@ -2,6 +2,9 @@
|
|||
<gresources>
|
||||
<gresource prefix="/com/xronlinux/BreezyDesktop">
|
||||
<file preprocess="xml-stripblanks">gtk/connected-device.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/license-dialog.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/license-feature-row.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/license-tier-row.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/no-device.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/no-extension.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/shortcut-dialog.ui</file>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<property name="column-spacing">4</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="device_label">
|
||||
<property name="label">VITURE One</property>
|
||||
<property name="label"></property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="LicenseDialog" parent="GtkDialog">
|
||||
<property name="modal">1</property>
|
||||
<property name="default_width">440</property>
|
||||
<property name="default_height">200</property>
|
||||
<child internal-child="content_area">
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="AdwBanner" id="license_action_needed_banner">
|
||||
<property name="revealed">0</property>
|
||||
<property name="title" translatable="yes">Some features expire soon</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="vexpand">1</property>
|
||||
<property name="label" translatable="yes">Tier Status</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="tiers">
|
||||
<property name="orientation">vertical</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="vexpand">1</property>
|
||||
<property name="label" translatable="yes">Feature Availability</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="features">
|
||||
<property name="orientation">vertical</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<property name="title-widget">
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">License Details</property>
|
||||
<property name="single-line-mode">1</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<property name="width-chars">5</property>
|
||||
<style>
|
||||
<class name="title"/>
|
||||
</style>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEventControllerKey" id="event_controller" />
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="LicenseFeatureRow" parent="GtkGrid">
|
||||
<property name="margin-start">16</property>
|
||||
<property name="margin-end">16</property>
|
||||
<property name="margin-top">16</property>
|
||||
<property name="margin-bottom">16</property>
|
||||
<property name="row-spacing">2</property>
|
||||
<property name="column-spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="feature_name">
|
||||
<property name="vexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="feature_status">
|
||||
<property name="vexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="feature_funds_needed_usd">
|
||||
<property name="vexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="LicenseTierRow" parent="GtkGrid">
|
||||
<property name="margin-start">16</property>
|
||||
<property name="margin-end">16</property>
|
||||
<property name="margin-top">16</property>
|
||||
<property name="margin-bottom">16</property>
|
||||
<property name="row-spacing">2</property>
|
||||
<property name="column-spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="tier_name">
|
||||
<property name="vexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="tier_status">
|
||||
<property name="vexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="tier_funds_needed_usd">
|
||||
<property name="vexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
|
|
@ -26,9 +26,24 @@
|
|||
</child>
|
||||
</object>
|
||||
</property>
|
||||
<property name="child">
|
||||
<object class="GtkBox" id="main_content">
|
||||
<child>
|
||||
<object class="AdwBanner" id="license_action_needed_banner">
|
||||
<property name="revealed">0</property>
|
||||
<property name="title" translatable="yes">Some features expire soon</property>
|
||||
<property name="button-label" translatable="yes">Update your license</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
<menu id="primary_menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">License Details</attribute>
|
||||
<attribute name="action">app.license</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_About BreezyDesktop</attribute>
|
||||
<attribute name="action">app.about</attribute>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
from gi.repository import Gtk
|
||||
from .statemanager import StateManager
|
||||
from .licensetierrow import LicenseTierRow
|
||||
from .licensefeaturerow import LicenseFeatureRow
|
||||
|
||||
@Gtk.Template(resource_path='/com/xronlinux/BreezyDesktop/gtk/license-dialog.ui')
|
||||
class LicenseDialog(Gtk.Dialog):
|
||||
__gtype_name__ = 'LicenseDialog'
|
||||
|
||||
tiers = Gtk.Template.Child()
|
||||
features = Gtk.Template.Child()
|
||||
|
||||
def __init__(self):
|
||||
super(Gtk.Dialog, self).__init__()
|
||||
self.init_template()
|
||||
|
||||
self.state_manager = StateManager.get_instance()
|
||||
self._handle_license();
|
||||
|
||||
def _handle_license(self):
|
||||
license_view = self.state_manager.state['ui_view']['license']
|
||||
for tier_name, tier_details in license_view['tiers'].items():
|
||||
self.tiers.append(LicenseTierRow(tier_name, tier_details))
|
||||
|
||||
for feature_name, feature_details in license_view['features'].items():
|
||||
self.features.append(LicenseFeatureRow(feature_name, feature_details))
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
from gi.repository import Gtk
|
||||
|
||||
@Gtk.Template(resource_path='/com/xronlinux/BreezyDesktop/gtk/license-feature-row.ui')
|
||||
class LicenseFeatureRow(Gtk.Grid):
|
||||
__gtype_name__ = 'LicenseFeatureRow'
|
||||
|
||||
def __init__(self, feature_name, feature_details):
|
||||
super(Gtk.Grid, self).__init__()
|
||||
self.init_template()
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
from gi.repository import Gtk
|
||||
|
||||
tier_names = {
|
||||
'supporter': 'Gaming Supporter Tier',
|
||||
'subscriber': 'Productivity Tier',
|
||||
'subscriber_pro': 'Productivity Pro Tier',
|
||||
}
|
||||
|
||||
period_names = {
|
||||
'monthly': 'Monthly renewal',
|
||||
'yearly': 'Yearly renewal',
|
||||
'lifetime': 'Lifetime access',
|
||||
}
|
||||
|
||||
@Gtk.Template(resource_path='/com/xronlinux/BreezyDesktop/gtk/license-tier-row.ui')
|
||||
class LicenseTierRow(Gtk.Grid):
|
||||
__gtype_name__ = 'LicenseTierRow'
|
||||
|
||||
tier_name = Gtk.Template.Child()
|
||||
tier_status = Gtk.Template.Child()
|
||||
tier_funds_needed_usd = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, tier, tier_details):
|
||||
super(Gtk.Grid, self).__init__()
|
||||
self.init_template()
|
||||
|
||||
self.tier_name.set_markup(f"<b>{tier_names[tier]}</b>")
|
||||
|
||||
active_period = tier_details.get('active_period')
|
||||
funds_needed_in_seconds = tier_details.get('funds_needed_in_seconds')
|
||||
|
||||
status = 'Active' if active_period else 'Inactive'
|
||||
details = ''
|
||||
if active_period:
|
||||
details += f"({period_names[active_period]})"
|
||||
if funds_needed_in_seconds is not None and funds_needed_in_seconds > 0:
|
||||
time_remaining = time_remaining_text(funds_needed_in_seconds)
|
||||
if time_remaining: details += f", {time_remaining} remaining"
|
||||
self.tier_status.set_markup(f" - <i>{status}</i> {details}")
|
||||
|
||||
funds_needed_markup = ''
|
||||
first_period = True
|
||||
for period, amount in tier_details['funds_needed_by_period'].items():
|
||||
if not first_period:
|
||||
funds_needed_markup += ', '
|
||||
amount_text = f"${amount}USD" if amount > 0 else 'Already funded'
|
||||
funds_needed_markup += f"{period}: {amount_text}"
|
||||
first_period = False
|
||||
self.tier_funds_needed_usd.set_markup(funds_needed_markup)
|
||||
|
||||
def time_remaining_text(seconds):
|
||||
if not seconds:
|
||||
return
|
||||
|
||||
if seconds < 60 * 60:
|
||||
return 'less than an hour'
|
||||
elif seconds / 60 * 60 < 24:
|
||||
time_remaining = seconds / 60 * 60
|
||||
return '1 hour' if time_remaining == 1 else f'{time_remaining} hours'
|
||||
elif seconds / 24 * 60 * 60 < 30:
|
||||
time_remaining = seconds / 24 * 60 * 60
|
||||
return '1 day' if time_remaining == 1 else f'{time_remaining} days'
|
||||
else:
|
||||
return
|
||||
|
|
@ -25,6 +25,7 @@ gi.require_version('Adw', '1')
|
|||
gi.require_version('Gio', '2.0')
|
||||
|
||||
from gi.repository import Adw, Gtk, Gio
|
||||
from .licensedialog import LicenseDialog
|
||||
from .statemanager import StateManager
|
||||
from .window import BreezydesktopWindow
|
||||
|
||||
|
|
@ -36,6 +37,7 @@ class BreezydesktopApplication(Adw.Application):
|
|||
flags=Gio.ApplicationFlags.DEFAULT_FLAGS)
|
||||
self.create_action('quit', self.on_quit_action, ['<primary>q'])
|
||||
self.create_action('about', self.on_about_action)
|
||||
self.create_action('license', self.on_license_action)
|
||||
|
||||
def do_activate(self):
|
||||
"""Called when the application is activated.
|
||||
|
|
@ -61,6 +63,11 @@ class BreezydesktopApplication(Adw.Application):
|
|||
copyright='© 2024 Wayne Heaney')
|
||||
about.present()
|
||||
|
||||
def on_license_action(self, widget, _):
|
||||
dialog = LicenseDialog()
|
||||
dialog.set_transient_for(self.props.active_window)
|
||||
dialog.present()
|
||||
|
||||
def create_action(self, name, callback, shortcuts=None):
|
||||
"""Add an application action.
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ breezydesktop_sources = [
|
|||
'__init__.py',
|
||||
'connecteddevice.py',
|
||||
'extensionsmanager.py',
|
||||
'licensedialog.py',
|
||||
'licensefeaturerow.py',
|
||||
'licensetierrow.py',
|
||||
'main.py',
|
||||
'nodevice.py',
|
||||
'noextension.py',
|
||||
|
|
|
|||
|
|
@ -11,11 +11,13 @@ class Logger:
|
|||
|
||||
class StateManager(GObject.GObject):
|
||||
__gsignals__ = {
|
||||
'device-update': (GObject.SIGNAL_RUN_FIRST, None, (str,))
|
||||
'device-update': (GObject.SIGNAL_RUN_FIRST, None, (str,)),
|
||||
'license-action-needed': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
|
||||
}
|
||||
|
||||
__gproperties__ = {
|
||||
'follow-mode': (bool, 'Follow Mode', 'Whether the follow mode is enabled', False, GObject.ParamFlags.READWRITE)
|
||||
'follow-mode': (bool, 'Follow Mode', 'Whether the follow mode is enabled', False, GObject.ParamFlags.READWRITE),
|
||||
'license-action-needed-date': (int, 'License Action Needed Date', 'The date, in seconds, when the license action was needed', 0, 1024000, 0, GObject.ParamFlags.READWRITE),
|
||||
}
|
||||
|
||||
_instance = None
|
||||
|
|
@ -44,6 +46,8 @@ class StateManager(GObject.GObject):
|
|||
GObject.GObject.__init__(self)
|
||||
self.ipc = XRDriverIPC.get_instance()
|
||||
self.connected_device_name = None
|
||||
self.license_action_needed = False
|
||||
self.license_action_needed_seconds = 0
|
||||
|
||||
self.start()
|
||||
|
||||
|
|
@ -61,7 +65,16 @@ class StateManager(GObject.GObject):
|
|||
self.connected_device_name = new_device_name
|
||||
self.emit('device-update', self.connected_device_name)
|
||||
|
||||
license_view = self.state['ui_view']['license']
|
||||
action_needed_seconds = license_view.get('action_needed_seconds')
|
||||
action_needed = action_needed_seconds is not None
|
||||
if (action_needed != self.license_action_needed):
|
||||
self.license_action_needed = action_needed
|
||||
self.license_action_needed_seconds = action_needed_seconds
|
||||
self.emit('license-action-needed', action_needed_seconds)
|
||||
|
||||
self.set_property('follow-mode', self.state.get('breezy_desktop_smooth_follow_enabled'))
|
||||
self.set_property('license-action-needed-date', self.license_action_needed_seconds)
|
||||
|
||||
if self.running: threading.Timer(1.0, self._refresh_state).start()
|
||||
|
||||
|
|
|
|||
|
|
@ -28,28 +28,43 @@ from .noextension import NoExtension
|
|||
class BreezydesktopWindow(Gtk.ApplicationWindow):
|
||||
__gtype_name__ = 'BreezydesktopWindow'
|
||||
|
||||
main_content = Gtk.Template.Child()
|
||||
license_action_needed_banner = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.state_manager = StateManager.get_instance()
|
||||
self.state_manager.connect('device-update', self._handle_device_update)
|
||||
self.state_manager.connect('license-action-needed', self._handle_device_update)
|
||||
|
||||
self.connected_device = ConnectedDevice()
|
||||
self.no_device = NoDevice()
|
||||
self.no_extension = NoExtension()
|
||||
|
||||
self._handle_device_update(self.state_manager, StateManager.device_name(self.state_manager.state))
|
||||
self.license_action_needed_banner.connect('button-clicked', self._on_license_action_needed_button_clicked)
|
||||
|
||||
self._handle_device_update(self.state_manager, None)
|
||||
|
||||
self.connect("destroy", self._on_window_destroy)
|
||||
|
||||
def _handle_device_update(self, state_manager, connected_device_name):
|
||||
def _handle_device_update(self, state_manager, val):
|
||||
for child in self.main_content:
|
||||
self.main_content.remove(child)
|
||||
|
||||
if state_manager.license_action_needed:
|
||||
self.main_content.append(self.no_license)
|
||||
|
||||
if not ExtensionsManager.get_instance().is_installed():
|
||||
self.set_child(self.no_extension)
|
||||
elif connected_device_name:
|
||||
self.set_child(self.connected_device)
|
||||
self.connected_device.set_device_name(connected_device_name)
|
||||
self.main_content.append(self.no_extension)
|
||||
elif state_manager.connected_device_name:
|
||||
self.main_content.append(self.connected_device)
|
||||
self.connected_device.set_device_name(state_manager.connected_device_name)
|
||||
else:
|
||||
self.set_child(self.no_device)
|
||||
self.main_content.append(self.no_device)
|
||||
|
||||
def _on_license_action_needed_button_clicked(self, widget):
|
||||
self.state_manager.ipc.show_license()
|
||||
|
||||
def _on_window_destroy(self, widget):
|
||||
self.state_manager.disconnect_by_func(self._handle_device_update)
|
||||
Loading…
Reference in New Issue