Skip to content

Commit

Permalink
feat: webview 交互
Browse files Browse the repository at this point in the history
  • Loading branch information
luke358 committed Jan 20, 2024
1 parent b650e89 commit 9647464
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 20 deletions.
13 changes: 11 additions & 2 deletions preload/recipe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,29 @@ class RecipeController {
'initialize-recipe': 'loadRecipeModule',
'find-in-page': 'openFindInPage',
}
constructor() {
this.initialize();
}

async initialize() {
for (const channel of Object.keys(this.ipcEvents)) {
ipcRenderer.on(channel, (...args) => {
this[this.ipcEvents[channel]](...args);
});
}
setTimeout(() => {
ipcRenderer.sendToHost('hello')
}, 100);

}

loadRecipeModule(_event, config, recipe) {
const modulePath = join(recipe.path, 'webview.js');
console.log(recipe, 'reeeeee')
// const modulePath = join(recipe.path, 'webview.js');
// debug('module path', modulePath);
// Delete module from cache
// delete require.cache[require.resolve(modulePath)];
console.log(modulePath, 'modulePath')
// console.log(modulePath, 'modulePath')
try {
// this.recipe = new RecipeWebview(
// badgeHandler,
Expand All @@ -62,4 +70,5 @@ class RecipeController {
}
}

console.log('new RecipeController();')
new RecipeController();
2 changes: 1 addition & 1 deletion src/components/AddServiceDrawer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ async function submit(formEl: FormInstance | undefined) {
// setTimeout(() => {
// innerDrawer.value = false
// }, 1000)
services.addService(service.value)
services.addService(service.value as Service)
})
}
Expand Down
26 changes: 18 additions & 8 deletions src/components/WebView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,34 @@ const emits = defineEmits(['setWebview', 'didFinishLoad', 'didFailLoad'])
const services = useServiceStore()
const webViewRef = ref<ElectronWebView | null>(null)
const didFinishLoad = () => emits('didFinishLoad')
const didFinishLoad = () => {
service.isLoading = false;
service.isError = false;
console.log('did-finish-load')
emits('didFinishLoad')
}
const didFailLoad = () => emits('didFailLoad')
const didAttach = () => {
services.setWebviewReference({ serviceId: service.id, webview: webViewRef.value! as ElectronWebView })
}
onMounted(() => {
webViewRef.value?.addEventListener('did-finish-load', didFinishLoad)
webViewRef.value?.addEventListener('did-attach', didAttach)
webViewRef.value?.addEventListener('did-fail-load', didFailLoad)
webViewRef.value?.addEventListener('media-started-playing', () => services.didMediaPlaying({ serviceId: service.id }))
webViewRef.value?.addEventListener('media-paused', () => services.didMediaPaused({ serviceId: service.id }))
webViewRef.value?.addEventListener('dom-ready', () => {
console.log('dom-ready')
webViewRef.value?.openDevTools()
})
console.log(webViewRef.value)
webViewRef.value?.addEventListener('ipc-message', (e: any) => {
console.log('ipc-message')
if (e.channel === 'data') {
console.log(e)
}
})
// console.log(webViewRef.value)
// webViewRef.value?.addEventListener('ipc-message', (e: any) => {
// console.log('ipc-message')
// if (e.channel === 'data') {
// console.log(e)
// }
// })
})
onBeforeUnmount(() => {
webViewRef.value?.removeEventListener('did-finish-load', didFinishLoad)
Expand Down
148 changes: 148 additions & 0 deletions src/models/Service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { ElectronWebView, IService } from "@/types";
import { Recipe } from "@/types/recipe";

export default class Service {
recipe: Recipe
isMediaPlaying = false
id: string
preload: boolean = false
lastUsed: number
lastHibernated: number | null
isActive: boolean = false
name: string
hasCrashed = false
isLoading = true
isError = false
isFirstLoad = true
errorMessage: string = ''
isHibernationEnabled = false
_webview: ElectronWebView | null = null

constructor(data: IService, recipe: Recipe) {
if (!data) {
throw new Error('Service config not valid');
}

if (!recipe) {
throw new Error('Service recipe not valid');
}

this.id = data.id
this.name = data.name
this.preload = data.preload
this.lastUsed = Date.now()
this.lastHibernated = null
this.isActive = false

/**
url: 'https://discord.com/app',
preload: true,
name: 'Discord',
_webview: undefined,
lastUsed: Date.now(),
lastHibernated: null,
isActive: false,
timer: null,
isMuted: false,
id: nanoid(),
serviceId: 'discord',
iconUrl: 'xxx',
isFirstLoad: true,
isError: false,
isLoading: true,
enable: true,
isNotificationEnabled: true,
isSoundsEnabled: true,
isShowNameInTabEnabled: true,
isHibernateEnabled: false,
isHibernating: false,
isMediaPlaying: false,
sorted: 0,
isUnreadInTabEnabled: true,
isUnreadInGlobalEnabled: true,
linkHandling: LinkHandling.Default,
timestamp: Date.now(),
*/

this.recipe = recipe
}

get canHibernate(): boolean {
return this.isHibernationEnabled && !this.isMediaPlaying;
}

get webview(): ElectronWebView | null {
return this._webview;
}

set webview(webview) {
this._webview = webview;
}

// initializeWebViewEvents({ handleIPCMessage, openWindow, stores }): viod {
// this.webview?.addEventListener('ipc-message', async e => {
// if (e.channel === 'inject-js-unsafe') {
// await Promise.all(
// e.args.map(script =>
// this.webview?.executeJavaScript(
// `"use strict"; (() => { ${script} })();`,
// ),
// ),
// );
// } else {
// handleIPCMessage({
// serviceId: this.id,
// channel: e.channel,
// args: e.args,
// });
// }
// });
// }

_initializeServiceRecipeInWebview(serviceId: string) {
// const service = this.one(serviceId);
// if (service && service._webview) {
// service._webview.send('initialize-recipe', {
// version: '1.1'
// }, service.recipe)
// }
}

_didStartLoading(): void {
this.hasCrashed = false;
this.isLoading = true;
this.isError = false;
}

_didStopLoading(): void {
this.isLoading = false;
}

_didFailLoad(event: { errorDescription: string }): void {
this.isError = false;
this.errorMessage = event.errorDescription;
this.isLoading = false;
}

_hasCrashed(): void {
this.hasCrashed = true;
}

_didLoad(): void {
this.isLoading = false;

if (!this.isError) {
this.isFirstLoad = false;
}
}


_didMediaPlaying(): void {
this.isMediaPlaying = true;
}

_didMediaPaused(): void {
this.isMediaPlaying = false;
}
}
55 changes: 49 additions & 6 deletions src/store/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { defineStore } from 'pinia'
import { nanoid } from 'nanoid'
import ms from 'ms'
import { debounce } from 'lodash-es'
import type { Service, ServiceStore } from '../types'
import type { ElectronWebView, Service, ServiceStore } from '../types'

export const useServiceStore = defineStore({
id: 'services',
Expand All @@ -20,7 +20,7 @@ export const useServiceStore = defineStore({
return (this.allServices as Service[]).sort((a, b) => a.sorted - b.sorted)
},
enabledServices(): Service[] {
return this.allServices.filter(service => service.enable)
return (this.allServices as Service[]).filter(service => service.enable)
},
},
actions: {
Expand Down Expand Up @@ -113,12 +113,55 @@ export const useServiceStore = defineStore({
one(id: string): Service {
return this.allServices.find(service => service.id === id) as Service;
},
setWebviewReference({ serviceId, webview }: { serviceId: string, webview: ElectronWebView }) {
const service = this.one(serviceId)
if (service) {
service._webview = webview;
this.initializeWebViewEvents(service)
// service.initializeWebViewEvents({
// handleIPCMessage: this.actions.service.handleIPCMessage,
// openWindow: this.actions.service.openWindow,
// stores: this.stores,
// });
// service.initializeWebViewListener();

}

},
initializeWebViewEvents(service: Service) {
service._webview?.addEventListener('ipc-message', (e) => {
this._handleIPCMessage({
serviceId: service.id,
channel: e.channel,
args: e.args,
});
})
},
_handleIPCMessage({ serviceId, channel, args }: { serviceId: string, channel: string, args: any }) {
switch (channel) {
case 'hello': {
// this._initRecipePolling(service.id);
this._initializeServiceRecipeInWebview(serviceId);
// this._shareSettingsWithServiceProcess();

break;
}
}
},
_initializeServiceRecipeInWebview(serviceId: string) {
const service = this.one(serviceId);
if(service && service._webview) {
// service._webview.send('initialize-recipe', {
// version: '1.1'
// }, service.recipe)
if (service && service._webview) {
service._webview.send('initialize-recipe', {
version: '1.1'
}, {
"featured": true,
"id": "discord",
"name": "Discord",
"version": "1.8.2",
"icons": {
"svg": "https://cdn.jsdelivr.net/gh/ferdium/ferdium-recipes/recipes/discord/icon.svg"
}
})
}
}
},
Expand Down
2 changes: 2 additions & 0 deletions src/types/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export interface Service {
timestamp: number
}

export type IService = Service

export interface ServiceStore {
allServices: Service[]
teardown: DebouncedFunc<() => void> | null
Expand Down
2 changes: 1 addition & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function getDomain(sourceUrl: string | undefined) {
return domain
}

export function createInitialService(isCustom = true) {
export function createInitialService(isCustom = true): Service {
const initialService: Service = {
url: '',
preload: false,
Expand Down
2 changes: 0 additions & 2 deletions src/views/home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ const SETTING_HEIGHT = 45 * settings.length + 60
<ServiceView
v-if="service.preload || service.isActive || serviceUsed.has(service.id)"
:service="service"
@set-webview="(webView) => (service._webview = webView)"
@did-finish-load="() => { service.isLoading = false;service.isError = false; }"
@did-fail-load="() => { service.isError = true; service.isLoading = false }"
/>
</div>
Expand Down

0 comments on commit 9647464

Please sign in to comment.