Skip to content

Commit

Permalink
✨ Store zoom state across browser starts
Browse files Browse the repository at this point in the history
  • Loading branch information
trickypr committed Jan 5, 2024
1 parent 86d3219 commit ab0ab52
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 9 deletions.
1 change: 1 addition & 0 deletions apps/content/src/browser/lib/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export const resource = lazyESModuleGetters({
NetUtil: 'resource://gre/modules/NetUtil.sys.mjs',
PageThumbs: 'resource://gre/modules/PageThumbs.sys.mjs',
WindowTracker: 'resource://app/modules/BrowserWindowTracker.sys.mjs',
ZoomStore: 'resource://app/modules/ZoomStore.sys.mjs',
})
36 changes: 28 additions & 8 deletions apps/content/src/browser/lib/window/tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { type ViewableWritable, viewableWritable } from '@experiment/shared'
import mitt from 'mitt'
import { type Writable, get, writable } from 'svelte/store'

import type { ZoomStoreEvents } from 'resource://app/modules/ZoomStore.sys.mjs'

import { type BookmarkTreeNode, search } from '@shared/ExtBookmarkAPI'

import { resource } from '../resources'
Expand Down Expand Up @@ -61,18 +63,27 @@ export class Tab {
this.goToUri(uri)
this.title.set(uri.asciiHost)

this.zoom.subscribe(
(newZoom) =>
this.browserElement.browsingContext &&
(this.browserElement.fullZoom = newZoom),
)
this.zoom.subscribe((newZoom) => {
if (
!this.browserElement.browsingContext ||
this.browserElement.fullZoom === newZoom
) {
return
}

this.browserElement.fullZoom = newZoom
resource.ZoomStore.setZoomForUri(this.uri.readOnce(), newZoom)
})
this.uri.subscribe(async (uri) =>
this.bookmarkInfo.set(
await search({ url: uri.spec }).then((r) =>
r.length > 0 ? (r[0] as BookmarkTreeNode) : null,
),
),
)

// Remember to unsubscribe from any listeners you register here!
resource.ZoomStore.events.on('setZoom', this.zoomChange)
}

public getId(): number {
Expand Down Expand Up @@ -154,6 +165,13 @@ export class Tab {
this.useProgressListener()
}

zoomChange = (event: ZoomStoreEvents['setZoom']) => {
try {
if (this.uri.readOnce().host != event.host) return
this.zoom.set(event.zoom)
} catch {}
}

protected useProgressListener() {
this.progressListener.events.on('locationChange', (event) => {
if (!event.aWebProgress.isTopLevel) return
Expand All @@ -163,9 +181,8 @@ export class Tab {
this.uri.set(event.aLocation)
this.canGoBack.set(this.browserElement.canGoBack)
this.canGoForward.set(this.browserElement.canGoForward)
this.zoom.set(
this.browserElement.browsingContext ? this.browserElement.fullZoom : 1,
)

this.zoom.set(resource.ZoomStore.getZoomForUri(event.aLocation))
})

this.progressListener.events.on('progressPercent', this.loadingProgress.set)
Expand All @@ -188,6 +205,9 @@ export class Tab {
}

public destroy() {
this.removeEventListeners()
resource.ZoomStore.events.off('setZoom', this.zoomChange)

this.browserElement.remove()
}

Expand Down
101 changes: 101 additions & 0 deletions apps/modules/lib/ZoomStore.sys.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// @ts-check
/// <reference types="@browser/link" />
import mitt from 'resource://app/modules/mitt.sys.mjs'

const ZOOM_STORE_FILE = PathUtils.join(PathUtils.profileDir, 'zoomstore.json')

/** @typedef {import("resource://app/modules/ZoomStore.sys.mjs").ZoomStoreInterface} ZoomStoreInterface */

/** @implements {ZoomStoreInterface} */
class ZoomStoreImpl {
/**
* @private
* @type {Map<string, number> | null}
*/
zoomPages = null

/** @type {import('resource://app/modules/mitt.sys.mjs').Emitter<import('resource://app/modules/ZoomStore.sys.mjs').ZoomStoreEvents>} */
events = mitt()

constructor() {
this.init()
}

/** @protected */
async init() {
if (this.zoomPages) {
return
}

if (!(await IOUtils.exists(ZOOM_STORE_FILE))) {
this.zoomPages = new Map()
return
}

try {
const pages = await IOUtils.readJSON(ZOOM_STORE_FILE)
if (this.zoomPages) {
return
}

this.zoomPages = new Map(pages)
} catch (e) {
console.error('Failed to load zoomStore from file: ', e)
return
}
}

/** @private */
async save() {
if (!this.zoomPages) {
return
}

const toWrite = Array.from(this.zoomPages.entries())
try {
await IOUtils.writeJSON(ZOOM_STORE_FILE, toWrite)
} catch (e) {
console.error('Failed to write zoomStore to file:', e)
return
}
}

/**
* @param {nsIURIType} uri The uri to check zoom for
* @returns {number}
*/
getZoomForUri(uri) {
try {
return this.zoomPages?.get(uri.host) || 1
} catch {
return 1
}
}

/**
* @param {nsIURIType} uri
* @param {number} zoom The zoom to store. If set to 1, will delete any stored values
*/
setZoomForUri(uri, zoom) {
try {
uri.host
} catch {
return
}

if (zoom === 1) {
this.zoomPages?.delete(uri.host)
return
}

this.zoomPages?.set(uri.host, Math.round(zoom * 100) / 100)

// @ts-ignore
Services.tm.dispatchToMainThread(() => {
this.events.emit('setZoom', { host: uri.host, zoom })
this.save()
})
}
}

export const ZoomStore = new ZoomStoreImpl()
1 change: 1 addition & 0 deletions libs/link/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"license": "ISC",
"dependencies": {
"gecko-types": "github:quark-platform/gecko-types",
"gecko-types@latest": "link:quark-platform/gecko-types@latest",
"mitt": "^3.0.1"
}
}
1 change: 1 addition & 0 deletions libs/link/types/_link.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
/// <reference path="./modules/mitt.d.ts" />
/// <reference path="./modules/PlacesUtils.d.ts" />
/// <reference path="./modules/typedImport.d.ts" />
/// <reference path="./modules/ZoomStore.d.ts" />
24 changes: 24 additions & 0 deletions libs/link/types/modules/ZoomStore.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
declare module 'resource://app/modules/ZoomStore.sys.mjs' {
import { Emitter } from 'mitt'

export type ZoomStoreEvents = {
setZoom: { host: string; zoom: number }
}

export const ZoomStore: {
events: Emitter<ZoomStoreEvents>

getZoomForUri(uri: nsIURIType): number
setZoomForUri(uri: nsIURIType, zoom: number): void
}

export type ZoomStoreInterface = typeof ZoomStore
}

declare interface MozESMExportFile {
ZoomStore: 'resource://app/modules/ZoomStore.sys.mjs'
}

declare interface MozESMExportType {
ZoomStore: typeof import('resource://app/modules/ZoomStore.sys.mjs').ZoomStore
}
12 changes: 11 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ab0ab52

Please sign in to comment.