forked from chrisknepper/android-messages-desktop
-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
I couldn't get the application to run unless I unset contextIsolation. So here is the application split into preload and node files. Makes iterop a bit more painful. But everything seems to work, at least as far as I tested. I think the interop stuff makes error logging a bit painful, so I may have missed the mark a bit. I can say for certain that clicking notifications works as expected. The mutation observer stuff I'm a little less clear on. (But the functions are called when I used console.log statements). I completely removed the profileImage stuff, it doesn't appear to be necessary. Maybe its just Linux, but the notification rendered the NotificationsOptions.icon that was provided by the google SPA just fine without all the cache code.
- Loading branch information
1 parent
68dffa3
commit a081158
Showing
9 changed files
with
216 additions
and
174 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,117 +1,142 @@ | ||
import { ipcRenderer } from "electron"; | ||
import path from "path"; | ||
import { contextBridge, ipcRenderer, webFrame } from "electron"; | ||
|
||
import { | ||
INITIAL_ICON_IMAGE, | ||
IS_MAC, | ||
RESOURCES_PATH, | ||
} from "./helpers/constants"; | ||
} from "./preload/constants_preload"; | ||
import { | ||
createRecentThreadObserver, | ||
createUnreadObserver, | ||
focusFunctions, | ||
recentThreadObserver, | ||
} from "./helpers/observers"; | ||
import { getProfileImg } from "./helpers/profileImage"; | ||
|
||
window.addEventListener("load", () => { | ||
if (IS_MAC) { | ||
const titlebarStyle = `#amd-titlebar { | ||
-webkit-app-region: drag; | ||
position: fixed; | ||
width: 100%; | ||
height: 64px; | ||
top: 0; | ||
left: 0; | ||
background: none; | ||
pointer-events: none; | ||
}`; | ||
} from "./preload/observers"; | ||
|
||
document.body.appendChild( | ||
Object.assign(document.createElement("style"), { | ||
textContent: titlebarStyle, | ||
}) | ||
); | ||
|
||
const titlebar = document.createElement("div"); | ||
titlebar.id = "amd-titlebar"; | ||
document.querySelector("mw-app")?.parentNode?.prepend(titlebar); | ||
declare global { | ||
interface Window { | ||
interop: any; | ||
} | ||
|
||
const conversationListObserver = new MutationObserver(() => { | ||
if (document.querySelector("mws-conversations-list") != null) { | ||
createUnreadObserver(); | ||
createRecentThreadObserver(); | ||
|
||
// keep trying to get an image that isnt blank until they load | ||
const interval = setInterval(() => { | ||
const conversation = document.body.querySelector( | ||
"mws-conversation-list-item" | ||
); | ||
if (conversation) { | ||
const canvas = conversation.querySelector( | ||
"a div.avatar-container canvas" | ||
) as HTMLCanvasElement | null; | ||
|
||
if (canvas != null && canvas.toDataURL() != INITIAL_ICON_IMAGE) { | ||
recentThreadObserver(); | ||
// refresh for profile image loads after letter loads. | ||
setTimeout(recentThreadObserver, 3000); | ||
clearInterval(interval); | ||
} | ||
} | ||
}, 250); | ||
conversationListObserver.disconnect(); | ||
} | ||
|
||
const preload_init = () => { | ||
|
||
if (IS_MAC) { | ||
const titlebarStyle = `#amd-titlebar { | ||
-webkit-app-region: drag; | ||
position: fixed; | ||
width: 100%; | ||
height: 64px; | ||
top: 0; | ||
left: 0; | ||
background: none; | ||
pointer-events: none; | ||
}`; | ||
document.body.appendChild( | ||
Object.assign(document.createElement("style"), { | ||
textContent: titlebarStyle, | ||
}) | ||
); | ||
|
||
const titlebar = document.createElement("div"); | ||
titlebar.id = "amd-titlebar"; | ||
document.querySelector("mw-app")?.parentNode?.prepend(titlebar); | ||
} | ||
|
||
const conversationListObserver = new MutationObserver(() => { | ||
if (document.querySelector("mws-conversations-list") != null) { | ||
createUnreadObserver(); | ||
createRecentThreadObserver(); | ||
|
||
// keep trying to get an image that isnt blank until they load | ||
const interval = setInterval(() => { | ||
const conversation = document.body.querySelector( | ||
"mws-conversation-list-item" | ||
); | ||
if (conversation) { | ||
const canvas = conversation.querySelector( | ||
"a div.avatar-container canvas" | ||
) as HTMLCanvasElement | null; | ||
|
||
if (canvas != null && canvas.toDataURL() != INITIAL_ICON_IMAGE) { | ||
recentThreadObserver(); | ||
// refresh for profile image loads after letter loads. | ||
setTimeout(recentThreadObserver, 3000); | ||
clearInterval(interval); | ||
} | ||
} | ||
}, 250); | ||
conversationListObserver.disconnect(); | ||
} | ||
|
||
const title = document.head.querySelector("title"); | ||
if (title != null) { | ||
title.innerText = "Android Messages"; | ||
} | ||
}); | ||
|
||
conversationListObserver.observe(document.body, { | ||
attributes: false, | ||
subtree: true, | ||
childList: true, | ||
}); | ||
} | ||
|
||
const title = document.head.querySelector("title"); | ||
if (title != null) { | ||
title.innerText = "Android Messages"; | ||
} | ||
}); | ||
|
||
conversationListObserver.observe(document.body, { | ||
attributes: false, | ||
subtree: true, | ||
childList: true, | ||
}); | ||
ipcRenderer.on("focus-conversation", (event, i) => { | ||
focusFunctions[i](); | ||
}); | ||
|
||
const OldNotification = window.Notification; | ||
|
||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
// @ts-ignore | ||
window.Notification = function (title: string, options: NotificationOptions) { | ||
const icon = getProfileImg(title); | ||
|
||
const hideContent = ipcRenderer.sendSync("should-hide-notification-content"); | ||
|
||
const notificationOpts: NotificationOptions = hideContent | ||
? { | ||
body: "Click to open", | ||
icon: path.resolve(RESOURCES_PATH, "icons", "64x64.png"), | ||
} | ||
: { | ||
icon: icon?.toDataURL(), | ||
body: options.body || "", | ||
}; | ||
|
||
const newTitle = hideContent ? "New Message" : title; | ||
const notification = new OldNotification(newTitle, notificationOpts); | ||
notification.addEventListener("click", () => { | ||
contextBridge.exposeInMainWorld("interop", { | ||
show_main_window: () => { | ||
ipcRenderer.send("show-main-window"); | ||
document.dispatchEvent(new Event("focus")); | ||
}, | ||
flash_main: () => { | ||
ipcRenderer.send("flash-main-window-if-not-focused"); | ||
}, | ||
should_hide: () => { | ||
return ipcRenderer.sendSync("should-hide-notification-content"); | ||
}, | ||
get_icon: async () => { | ||
const data = await ipcRenderer.invoke("get-icon"); | ||
return `data:image/png;base64,${data}`; | ||
}, | ||
preload_init, | ||
}); | ||
webFrame.executeJavaScript(` | ||
window.addEventListener("load", async () => { | ||
window.interop.preload_init(); | ||
window.icon_data_uri = await window.interop.get_icon(); | ||
}); | ||
ipcRenderer.send("flash-main-window-if-not-focused"); | ||
return notification; | ||
`); | ||
webFrame.executeJavaScript(`window.OldNotification = window.Notification; | ||
window.Notification = function (title, options) { | ||
try { | ||
const hideContent = window.interop.should_hide(); | ||
const notificationOpts = hideContent | ||
? { | ||
body: "Click to open", | ||
icon: window.icon_data_uri | ||
} | ||
: { | ||
body: options?.body || "", | ||
icon: options?.icon | ||
}; | ||
const newTitle = hideContent ? "New Message" : title; | ||
const notification = new window.OldNotification(newTitle, notificationOpts); | ||
notification.addEventListener("click", () => { | ||
window.interop.show_main_window(); | ||
document.dispatchEvent(new Event("focus")); | ||
}); | ||
window.interop.flash_main(); | ||
return notification; | ||
} catch (e) { | ||
console.error(e); | ||
console.trace(); | ||
} | ||
}; | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
//@ts-ignore | ||
window.Notification.permission = "granted"; | ||
window.Notification.requestPermission = async () => "granted"; | ||
|
||
window.module.exports = null; | ||
|
||
ipcRenderer.on("focus-conversation", (event, i) => { | ||
focusFunctions[i](); | ||
}); | ||
`); | ||
contextBridge.exposeInMainWorld("module", {exports: null}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
|
||
/** | ||
* Initial image AMD loads for icons. Used to check against and ignore when populating tray context menu. | ||
*/ | ||
export const INITIAL_ICON_IMAGE = | ||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAAAXNSR0IArs4c6QAABGJJREFUeF7t1AEJAAAMAsHZv/RyPNwSyDncOQIECEQEFskpJgECBM5geQICBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAgQdWMQCX4yW9owAAAABJRU5ErkJggg=="; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// Can't use constants.ts in bridge.ts because of context isolation | ||
|
||
export const IS_MAC = window.navigator.userAgent.indexOf("Macintosh") > -1; | ||
|
||
export const RECENT_CONVERSATION_TRAY_COUNT = 3; | ||
|
||
export {INITIAL_ICON_IMAGE} from "../helpers/constants_shared"; |
Oops, something went wrong.