Skip to content

Commit 733a1cd

Browse files
feat: add autostart and dock icon settings to DisplayTab
Introduced new state variables and API calls to manage autostart and dock icon visibility in the DisplayTab component. Added toggle switches for these settings, allowing users to enable or disable them directly from the app's settings. Removed the previous implementation from the SystemTab to streamline functionality. Updated the Tauri backend to handle first-run defaults for autostart behavior. Enhanced the landing page with new visual elements and improved layout for better user experience.
1 parent 26c44b1 commit 733a1cd

10 files changed

Lines changed: 302 additions & 43 deletions

File tree

apps/desktop/src-tauri/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,18 @@ pub fn run() {
115115
// Delivers anything missed while the app was closed, then sleeps
116116
// until the next reminder rather than polling.
117117
commands::notify::spawn_scheduler(app.handle().clone());
118+
119+
// A brand-new install turns on launch-at-login and shows itself
120+
// once. Without the second half, opening Sajilo for the very first
121+
// time appears to do nothing: the window starts hidden and a new
122+
// tray icon is easy to miss among a dozen others.
123+
#[cfg(not(any(target_os = "android", target_os = "ios")))]
124+
if system::autostart::apply_first_run_default(app.handle()) {
125+
if let Some(main) = window::main_window(app.handle()) {
126+
window::show(&main);
127+
}
128+
}
129+
118130
Ok(())
119131
})
120132
.on_window_event(|window, event| match event {

apps/desktop/src-tauri/src/prefs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ pub const RADIO_ENABLED: &str = "radioEnabled";
4747
pub const FOREX_FAVOURITES: &str = "forexFavourites";
4848
pub const LANGUAGE: &str = "language";
4949
pub const SHOWS_DOCK_ICON: &str = "showsDockIcon";
50+
/// Set once, the first time Sajilo runs, when launch-at-login is turned on for
51+
/// the user. Its presence — not its value — is what stops that from happening
52+
/// twice, so switching the toggle off stays switched off.
53+
pub const AUTOSTART_DEFAULTED: &str = "autostartDefaulted";
5054
pub const VEGETABLE_FAVOURITES: &str = "vegetableFavourites";
5155
pub const STOCK_WATCHLIST: &str = "stockWatchlist";
5256
pub const SELECTED_RASHI: &str = "selectedRashi";

apps/desktop/src-tauri/src/system/autostart.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,48 @@
11
//! Launch at login.
22
//!
33
//! A menu-bar calendar that is not running shows nothing, so this is the setting
4-
//! that makes Sajilo useful on the second day. It stays opt-in regardless: an
5-
//! app that adds itself to login items uninvited is one people uninstall.
4+
//! that makes Sajilo useful on the second day. It is therefore on from the
5+
//! first launch — a tray app that quietly stops existing after a reboot is one
6+
//! people conclude is broken. What makes that fair rather than sneaky is that
7+
//! it is done exactly once, and the switch that undoes it sits in Settings
8+
//! under Startup, where someone looking for it will look.
69
7-
use crate::{db, prefs::SHOWS_DOCK_ICON};
10+
use crate::{
11+
db,
12+
prefs::{AUTOSTART_DEFAULTED, SHOWS_DOCK_ICON},
13+
};
814
use tauri::{AppHandle, Wry};
915
use tauri_plugin_autostart::ManagerExt;
1016

1117
type Result<T> = std::result::Result<T, String>;
1218

19+
/// Turns launch-at-login on, once, for an install that has never run before.
20+
///
21+
/// Returns whether this was that first run, so the caller can also show the
22+
/// popover — otherwise the first thing a new user sees after opening the app is
23+
/// nothing at all, the window being hidden and the icon easy to miss.
24+
///
25+
/// Keyed on its own flag rather than on whether autostart is currently enabled:
26+
/// reading the live state would re-enable it every launch for anyone who had
27+
/// deliberately turned it off, which is precisely the behaviour that earns an
28+
/// uninstall.
29+
pub fn apply_first_run_default(app: &AppHandle<Wry>) -> bool {
30+
let already_done = db::get_json(app, AUTOSTART_DEFAULTED)
31+
.ok()
32+
.flatten()
33+
.is_some();
34+
if already_done {
35+
return false;
36+
}
37+
38+
// Recorded first. A registration that fails — a locked-down Mac, a Linux
39+
// desktop with no autostart directory — must not leave this retrying on
40+
// every launch.
41+
let _ = db::set_json(app, AUTOSTART_DEFAULTED, &serde_json::Value::Bool(true));
42+
let _ = app.autolaunch().enable();
43+
true
44+
}
45+
1346
#[tauri::command]
1447
pub fn is_autostart_enabled(app: AppHandle<Wry>) -> Result<bool> {
1548
app.autolaunch().is_enabled().map_err(|e| e.to_string())

apps/desktop/src/features/settings/_components/display-tab.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export function DisplayTab({
4141
const [showFlag, setShowFlag] = useState(true);
4242
const [showYear, setShowYear] = useState(true);
4343
const [showTime, setShowTime] = useState(false);
44+
const [autostart, setAutostart] = useState(false);
45+
const [dockIcon, setDockIcon] = useState(false);
4446

4547
useEffect(() => {
4648
Promise.all([
@@ -56,6 +58,14 @@ export function DisplayTab({
5658
if (time !== null) setShowTime(time);
5759
})
5860
.catch(() => {});
61+
api
62+
.isAutostartEnabled()
63+
.then(setAutostart)
64+
.catch(() => {});
65+
api
66+
.isDockIconVisible()
67+
.then(setDockIcon)
68+
.catch(() => {});
5969
}, []);
6070

6171
const persistFormat = (next: string) => {
@@ -148,6 +158,24 @@ export function DisplayTab({
148158
</>
149159
)}
150160
</SettingsSection>
161+
162+
<SettingsSection title={t("settings.startup")}>
163+
<Toggle
164+
label={t("settings.launch-at-login")}
165+
checked={autostart}
166+
onChange={async (value) => {
167+
setAutostart(await api.setAutostart(value).catch(() => autostart));
168+
}}
169+
/>
170+
<Toggle
171+
label={t("settings.show-dock-icon")}
172+
checked={dockIcon}
173+
onChange={(value) => {
174+
setDockIcon(value);
175+
api.setDockIconVisible(value).catch(() => {});
176+
}}
177+
/>
178+
</SettingsSection>
151179
</div>
152180
);
153181
}

apps/desktop/src/features/settings/_components/system-tab.tsx

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ export function SystemTab() {
1717
installUpdate,
1818
restartToUpdate,
1919
} = useUpdater();
20-
const [autostart, setAutostart] = useState(false);
21-
const [dockIcon, setDockIcon] = useState(false);
2220
const [options, setOptions] = useState<NotificationOptions>({
2321
eveOfPublicHoliday: false,
2422
eveOfFestival: false,
@@ -28,14 +26,6 @@ export function SystemTab() {
2826
const [message, setMessage] = useState<string | null>(null);
2927

3028
useEffect(() => {
31-
api
32-
.isAutostartEnabled()
33-
.then(setAutostart)
34-
.catch(() => {});
35-
api
36-
.isDockIconVisible()
37-
.then(setDockIcon)
38-
.catch(() => {});
3929
api
4030
.getNotificationOptions()
4131
.then(setOptions)
@@ -101,24 +91,6 @@ export function SystemTab() {
10191

10292
return (
10393
<div className="space-y-2.5">
104-
<SettingsSection title={t("settings.startup")}>
105-
<Toggle
106-
label={t("settings.launch-at-login")}
107-
checked={autostart}
108-
onChange={async (value) => {
109-
setAutostart(await api.setAutostart(value).catch(() => autostart));
110-
}}
111-
/>
112-
<Toggle
113-
label={t("settings.show-dock-icon")}
114-
checked={dockIcon}
115-
onChange={(value) => {
116-
setDockIcon(value);
117-
api.setDockIconVisible(value).catch(() => {});
118-
}}
119-
/>
120-
</SettingsSection>
121-
12294
{updaterEnabled && (
12395
<SettingsSection title={t("settings.updates")} footnote={updateNote ?? undefined}>
12496
{updateState === "installed" ? (
-23 Bytes
Loading

apps/landing/assets/screenshot.png

1.42 KB
Loading

apps/landing/index.html

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,27 @@ <h1>All of Nepal, on your menu bar.</h1>
9090
</div>
9191

9292
<div class="hero-shot">
93-
<div class="hero-device" aria-hidden="true">
94-
<div class="hero-device-screen">
95-
<img src="assets/screenshot.png" alt="Sajilo open in the menu bar, showing भदौ २०८३ on the Bikram Sambat calendar, Kathmandu weather, and gold rates">
93+
<div class="menubar-scene">
94+
<div class="menubar" aria-hidden="true">
95+
<span class="menubar-app menubar-app--sajilo">
96+
<span class="deva-mini">भदौ ८, २०८३</span>
97+
</span>
98+
<svg class="menubar-glyph" viewBox="0 0 24 24" aria-hidden="true">
99+
<path d="M2 8.5a15 15 0 0 1 20 0M5 12.2a10 10 0 0 1 14 0M8.4 15.9a5 5 0 0 1 7.2 0" />
100+
<circle cx="12" cy="19.2" r="1.15" class="menubar-glyph-dot" />
101+
</svg>
102+
<svg class="menubar-glyph" viewBox="0 0 24 24" aria-hidden="true">
103+
<rect x="2.5" y="8" width="16" height="8" rx="2.4" />
104+
<path d="M20.6 11v2" />
105+
<rect x="4.4" y="9.9" width="9" height="4.2" rx="1.2" class="menubar-glyph-fill" />
106+
</svg>
107+
<span class="menubar-clock">Mon 24 Aug&nbsp;&nbsp;2:52</span>
108+
</div>
109+
110+
<div class="hero-device" aria-hidden="true">
111+
<div class="hero-device-screen">
112+
<img src="assets/screenshot.png" alt="Sajilo open in the menu bar, showing भदौ २०८३ on the Bikram Sambat calendar, Kathmandu weather, and the NEPSE index">
113+
</div>
96114
</div>
97115
</div>
98116
</div>
@@ -220,7 +238,15 @@ <h2>Get started in a minute</h2>
220238
<div class="install-platforms">
221239
<div class="install-platform">
222240
<div class="install-platform-head">
223-
<span class="install-platform-icon" aria-hidden="true"></span>
241+
<span class="install-platform-icon" aria-hidden="true">
242+
<svg viewBox="0 0 24 24" class="platform-glyph">
243+
<rect x="2.5" y="4" width="19" height="16" rx="2.5" />
244+
<path d="M2.5 8.5h19" />
245+
<circle cx="5.8" cy="6.25" r="0.85" class="glyph-dot glyph-dot--red" />
246+
<circle cx="8.6" cy="6.25" r="0.85" class="glyph-dot glyph-dot--amber" />
247+
<circle cx="11.4" cy="6.25" r="0.85" class="glyph-dot glyph-dot--green" />
248+
</svg>
249+
</span>
224250
<h3>macOS</h3>
225251
</div>
226252
<p>Gatekeeper blocks the app with a two-step warning: drag to Applications, then approve once in System Settings.</p>
@@ -231,14 +257,32 @@ <h3>macOS</h3>
231257
</div>
232258
<div class="install-platform">
233259
<div class="install-platform-head">
234-
<span class="install-platform-icon install-platform-icon--win" aria-hidden="true"></span>
260+
<span class="install-platform-icon install-platform-icon--win" aria-hidden="true">
261+
<svg viewBox="0 0 24 24" class="platform-glyph platform-glyph--solid">
262+
<path d="M3 5.6 10.6 4.5v7.1H3V5.6Z" />
263+
<path d="M11.9 4.3 21 3v8.6h-9.1V4.3Z" />
264+
<path d="M3 12.9h7.6V20L3 18.9v-6Z" />
265+
<path d="M11.9 12.9H21v8.6l-9.1-1.3v-7.3Z" />
266+
</svg>
267+
</span>
235268
<h3>Windows</h3>
236269
</div>
237270
<p>SmartScreen flags the installer. Click <strong>More info → Run anyway</strong> to continue.</p>
238271
</div>
239272
<div class="install-platform">
240273
<div class="install-platform-head">
241-
<span class="install-platform-icon install-platform-icon--linux" aria-hidden="true"></span>
274+
<span class="install-platform-icon install-platform-icon--linux" aria-hidden="true">
275+
<svg viewBox="0 0 24 24" class="platform-glyph platform-glyph--solid">
276+
<ellipse cx="12" cy="14.2" rx="5.6" ry="6.4" />
277+
<ellipse cx="12" cy="7.6" rx="3.7" ry="4.2" />
278+
<ellipse cx="12" cy="15.6" rx="3.2" ry="4.4" class="glyph-belly" />
279+
<circle cx="10.6" cy="7.2" r="0.78" class="glyph-eye" />
280+
<circle cx="13.4" cy="7.2" r="0.78" class="glyph-eye" />
281+
<path d="M12 8.6c1 0 1.7.6 1.7 1.2 0 .7-.8 1.1-1.7 1.1s-1.7-.4-1.7-1.1c0-.6.7-1.2 1.7-1.2Z" class="glyph-beak" />
282+
<ellipse cx="8.8" cy="20.8" rx="2.1" ry="1.1" class="glyph-beak" />
283+
<ellipse cx="15.2" cy="20.8" rx="2.1" ry="1.1" class="glyph-beak" />
284+
</svg>
285+
</span>
242286
<h3>Linux</h3>
243287
</div>
244288
<p>Right-click the AppImage → Properties → allow executing, or run <code>chmod +x</code> before launching.</p>

apps/landing/install.html

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,34 @@ <h1 style="margin-bottom: 6px;">Installing on macOS</h1>
169169
</p>
170170

171171
<div style="text-align: center; margin-top: 36px;">
172-
<img src="assets/install/5-running.png" alt="Sajilo popover open, showing the calendar, weather, and Bazar cards" style="max-width: 280px; border-radius: 16px; border: 1px solid var(--border);">
172+
<img src="assets/install/5-running.png" alt="Sajilo popover open, showing the Bikram Sambat calendar, Kathmandu weather, and the NEPSE index" style="max-width: 280px; border-radius: 16px; border: 1px solid var(--border);">
173173
</div>
174174
</main>
175175

176176
<footer class="site-footer">
177+
<div class="wrap site-footer-inner">
178+
<div class="footer-brand">
179+
<a class="brand" href="index.html">
180+
<img src="assets/icon.png" alt="">
181+
<span>Sajilo</span>
182+
</a>
183+
<p>Nepali daily essentials in your menu bar.</p>
184+
<p class="footer-contact">
185+
Stuck on a step? Email
186+
<a href="mailto:contact@sajilo.fyi">contact@sajilo.fyi</a>
187+
</p>
188+
</div>
189+
<nav class="footer-links" aria-label="Footer">
190+
<a href="index.html">Home</a>
191+
<a href="index.html#download">Download</a>
192+
<a href="https://github.com/adarshaacharya/sajilo" target="_blank" rel="noopener">GitHub</a>
193+
<a href="https://github.com/adarshaacharya/sajilo/releases/latest" target="_blank" rel="noopener">Releases</a>
194+
<a href="https://github.com/adarshaacharya/sajilo/issues" target="_blank" rel="noopener">Report an issue</a>
195+
</nav>
196+
</div>
177197
<div class="wrap footer-bottom">
178-
<p>Sajilo is free and open source. <a href="https://github.com/adarshaacharya/sajilo" target="_blank" rel="noopener">Source on GitHub</a>. Built by <a href="https://adarsha.dev" target="_blank" rel="noopener">Adarsha Acharya</a>. Stuck? Email <a href="mailto:contact@sajilo.fyi">contact@sajilo.fyi</a>.</p>
198+
<p>© Sajilo · Free and open source</p>
199+
<a href="https://adarsha.dev" target="_blank" rel="noopener">Built by Adarsha Acharya</a>
179200
</div>
180201
</footer>
181202

0 commit comments

Comments
 (0)