Skip to content

Commit 89faf53

Browse files
committed
new file with both backend and display code for quickmenu. can be separated into existing files if preferred.
1 parent daff3c3 commit 89faf53

1 file changed

Lines changed: 225 additions & 0 deletions

File tree

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
#!/usr/bin/python3
2+
3+
# Quickstart dialog — shown on first launch (no webapps installed).
4+
# Offers to create a default suite of Email, Notes, Reminders, and Contacts
5+
# for the Google, Apple, or Microsoft ecosystem in one click.
6+
7+
import os
8+
import gi
9+
gi.require_version("Gtk", "3.0")
10+
from gi.repository import Gtk
11+
12+
_ = lambda s: s # i18n passthrough; real gettext is wired in the main module
13+
14+
# ---------------------------------------------------------------------------
15+
# Ecosystem definitions
16+
# Each entry lists the four web apps that will be created.
17+
# ---------------------------------------------------------------------------
18+
ECOSYSTEMS = [
19+
{
20+
"key": "google",
21+
"label": "Google",
22+
"icon": "web-google", # falls back gracefully if absent
23+
"color": "#4285F4",
24+
"apps": [
25+
{"name": "Gmail", "url": "https://mail.google.com", "icon": "web-google-gmail", "desc": "Google email"},
26+
{"name": "Google Keep", "url": "https://keep.google.com", "icon": "web-google", "desc": "Google notes"},
27+
{"name": "Google Tasks", "url": "https://tasks.google.com", "icon": "web-google", "desc": "Google reminders"},
28+
{"name": "Google Contacts", "url": "https://contacts.google.com", "icon": "web-google", "desc": "Google contacts"},
29+
],
30+
},
31+
{
32+
"key": "apple",
33+
"label": "Apple",
34+
"icon": "web-apple",
35+
"color": "#555555",
36+
"apps": [
37+
{"name": "iCloud Mail", "url": "https://www.icloud.com/mail", "icon": "web-apple", "desc": "iCloud email"},
38+
{"name": "iCloud Notes", "url": "https://www.icloud.com/notes", "icon": "web-apple", "desc": "iCloud notes"},
39+
{"name": "iCloud Reminders", "url": "https://www.icloud.com/reminders", "icon": "web-apple", "desc": "iCloud reminders"},
40+
{"name": "iCloud Contacts", "url": "https://www.icloud.com/contacts", "icon": "web-apple", "desc": "iCloud contacts"},
41+
],
42+
},
43+
{
44+
"key": "microsoft",
45+
"label": "Microsoft",
46+
"icon": "web-microsoft",
47+
"color": "#00A4EF",
48+
"apps": [
49+
{"name": "Outlook Mail", "url": "https://outlook.live.com/mail", "icon": "web-microsoft", "desc": "Outlook email"},
50+
{"name": "OneNote", "url": "https://www.onenote.com/notebooks", "icon": "web-microsoft", "desc": "Microsoft notes"},
51+
{"name": "Microsoft To Do", "url": "https://to-do.office.com", "icon": "web-microsoft", "desc": "Microsoft reminders"},
52+
{"name": "Outlook People", "url": "https://outlook.live.com/people", "icon": "web-microsoft", "desc": "Outlook contacts"},
53+
],
54+
},
55+
]
56+
57+
APP_LABELS = ["Email", "Notes", "Reminders", "Contacts"]
58+
59+
60+
class QuickstartDialog:
61+
"""
62+
Modal dialog shown when the user has no web apps installed.
63+
Presents three ecosystem choices; clicking one creates all four apps
64+
automatically. Cancel dismisses without creating anything.
65+
"""
66+
67+
def __init__(self, parent_window, manager):
68+
self.manager = manager
69+
self.chosen_ecosystem = None
70+
71+
# Resolve the first available browser once up-front
72+
self.browser = None
73+
for b in manager.get_supported_browsers():
74+
if os.path.exists(b.test_path):
75+
self.browser = b
76+
break
77+
78+
# ------------------------------------------------------------------ #
79+
# Dialog shell
80+
# ------------------------------------------------------------------ #
81+
self.dialog = Gtk.Dialog()
82+
self.dialog.set_transient_for(parent_window)
83+
self.dialog.set_modal(True)
84+
self.dialog.set_resizable(False)
85+
self.dialog.set_title(_("Welcome to Web Apps"))
86+
self.dialog.set_default_size(560, -1)
87+
self.dialog.set_border_width(0)
88+
89+
content = self.dialog.get_content_area()
90+
content.set_spacing(0)
91+
92+
outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=20)
93+
outer.set_border_width(28)
94+
content.pack_start(outer, True, True, 0)
95+
96+
# ------------------------------------------------------------------ #
97+
# Header
98+
# ------------------------------------------------------------------ #
99+
header = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
100+
header.set_halign(Gtk.Align.CENTER)
101+
102+
app_icon = Gtk.Image.new_from_icon_name("webapp-manager", Gtk.IconSize.DIALOG)
103+
header.pack_start(app_icon, False, False, 0)
104+
105+
title = Gtk.Label()
106+
title.set_markup("<span size='x-large' weight='bold'>%s</span>" % _("Welcome to Web Apps"))
107+
header.pack_start(title, False, False, 0)
108+
109+
subtitle = Gtk.Label()
110+
subtitle.set_markup(
111+
"<span color='#777777'>%s</span>" %
112+
_("Pick an ecosystem to get Email, Notes, Reminders and Contacts\n"
113+
"installed as apps in one click.")
114+
)
115+
subtitle.set_justify(Gtk.Justification.CENTER)
116+
subtitle.set_line_wrap(True)
117+
header.pack_start(subtitle, False, False, 0)
118+
119+
outer.pack_start(header, False, False, 0)
120+
121+
# ------------------------------------------------------------------ #
122+
# Ecosystem cards
123+
# ------------------------------------------------------------------ #
124+
cards_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12)
125+
cards_box.set_halign(Gtk.Align.CENTER)
126+
127+
icon_theme = Gtk.IconTheme.get_default()
128+
129+
for eco in ECOSYSTEMS:
130+
btn = self._make_card(eco, icon_theme)
131+
cards_box.pack_start(btn, False, False, 0)
132+
133+
outer.pack_start(cards_box, False, False, 0)
134+
135+
# ------------------------------------------------------------------ #
136+
# "Maybe later" cancel link
137+
# ------------------------------------------------------------------ #
138+
cancel_btn = Gtk.Button(label=_("Maybe later"))
139+
cancel_btn.set_halign(Gtk.Align.CENTER)
140+
cancel_btn.set_relief(Gtk.ReliefStyle.NONE)
141+
cancel_btn.connect("clicked", lambda w: self.dialog.destroy())
142+
outer.pack_start(cancel_btn, False, False, 0)
143+
144+
self.dialog.show_all()
145+
146+
# ---------------------------------------------------------------------- #
147+
# Helpers
148+
# ---------------------------------------------------------------------- #
149+
150+
def _make_card(self, eco, icon_theme):
151+
"""Return a styled button representing one ecosystem."""
152+
btn = Gtk.Button()
153+
btn.set_relief(Gtk.ReliefStyle.NONE)
154+
btn.set_sensitive(self.browser is not None)
155+
btn.set_tooltip_text(
156+
_("Create %s apps") % eco["label"] if self.browser
157+
else _("No supported browser detected.")
158+
)
159+
btn.connect("clicked", self._on_ecosystem_clicked, eco)
160+
161+
card = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
162+
card.set_border_width(14)
163+
164+
# Ecosystem icon — graceful fallback
165+
icon_name = eco["icon"] if icon_theme.has_icon(eco["icon"]) else "web-browser"
166+
if not icon_theme.has_icon(icon_name):
167+
icon_name = "webapp-manager"
168+
eco_icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.DIALOG)
169+
card.pack_start(eco_icon, False, False, 0)
170+
171+
# Ecosystem name
172+
name_lbl = Gtk.Label()
173+
name_lbl.set_markup("<b>%s</b>" % eco["label"])
174+
card.pack_start(name_lbl, False, False, 0)
175+
176+
# Four app labels
177+
for app_label in APP_LABELS:
178+
lbl = Gtk.Label()
179+
lbl.set_markup("<span size='small' color='#888888'>%s</span>" % app_label)
180+
card.pack_start(lbl, False, False, 0)
181+
182+
btn.add(card)
183+
return btn
184+
185+
def _on_ecosystem_clicked(self, _widget, eco):
186+
"""Create all four apps for the chosen ecosystem then close."""
187+
if not self.browser:
188+
return
189+
190+
icon_theme = Gtk.IconTheme.get_default()
191+
192+
for app in eco["apps"]:
193+
# Resolve icon: prefer the specified one, fall back to webapp-manager
194+
icon = app["icon"]
195+
if not icon_theme.has_icon(icon):
196+
icon = "webapp-manager"
197+
198+
self.manager.create_webapp(
199+
name=app["name"],
200+
desc=app["desc"],
201+
url=app["url"],
202+
icon=icon,
203+
category="Network",
204+
browser=self.browser,
205+
custom_parameters="",
206+
isolate_profile=True,
207+
navbar=False,
208+
privatewindow=False,
209+
)
210+
211+
self.chosen_ecosystem = eco["key"]
212+
self.dialog.destroy()
213+
214+
# ---------------------------------------------------------------------- #
215+
# Public API
216+
# ---------------------------------------------------------------------- #
217+
218+
def run(self):
219+
"""
220+
Show the dialog and block until it closes.
221+
Returns the chosen ecosystem key ("google" / "apple" / "microsoft"),
222+
or None if the user cancelled.
223+
"""
224+
self.dialog.run()
225+
return self.chosen_ecosystem

0 commit comments

Comments
 (0)