${translate('tabmenu.tm39')}
@@ -551,12 +558,6 @@ class ShowPlugin extends connect(store)(LitElement) {
return true
}
- openDevDialog() {
- this.shadowRoot.getElementById('domainInput').value = ''
- this.shadowRoot.getElementById('portInput').value = ''
- this.shadowRoot.querySelector("#addDevDialog").show()
- }
-
async getProxyPort() {
this.proxyPort = 0
let framework = ''
@@ -733,11 +734,9 @@ class ShowPlugin extends connect(store)(LitElement) {
const myPlugObj = plugArr.find(pagePlug => {
return pagePlug.url === this.url
})
-
if (this.tabs.length === 0) {
this.addTab({
- url: this.url,
- myPlugObj,
+ url: "",
id: this.uid()
})
} else {
@@ -780,7 +779,7 @@ class ShowPlugin extends connect(store)(LitElement) {
}
if (split[0] === '' && split[1] === 'app' && split[2] === undefined) {
- newUrl = 'wallet'
+ newUrl = ''
newLinkParam = ''
} else if (split.length === 5 && split[1] === 'app') {
newUrl = split[2]
@@ -792,7 +791,6 @@ class ShowPlugin extends connect(store)(LitElement) {
newUrl = '404'
newLinkParam = ''
}
-
if (newUrl !== this.url) {
this.url = newUrl
}
@@ -838,6 +836,9 @@ class ShowPlugin extends connect(store)(LitElement) {
//clear newTab
}
}
+ if(state.app.isOpenDevDialog){
+ this.isOpenDevDialog = state.app.isOpenDevDialog
+ }
}
}
diff --git a/core/src/notifications/controller.js b/core/src/notifications/controller.js
index f0b01060..20d4994d 100644
--- a/core/src/notifications/controller.js
+++ b/core/src/notifications/controller.js
@@ -1,7 +1,7 @@
import config from './config'
import { dispatcher } from './dispatcher'
import snackbar from '../functional-components/snackbar.js'
-import { NEW_MESSAGE, NEW_MESSAGE_NOTIFICATION_QAPP } from './types'
+import { NEW_MESSAGE, NEW_MESSAGE_NOTIFICATION_QAPP, NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL } from './types'
let initial = 0
let _state
@@ -43,8 +43,8 @@ const notificationCheck = function () {
*/
export const doNewMessage = function (req) {
-
const newMessage = () => {
+
let data
if (req.type && req.type === 'qapp') {
data = req
@@ -73,10 +73,16 @@ export const doNewMessage = function (req) {
} else {
_state = notificationState
}
- }
-
+ }
const page = window.top.location.href
- if (!document.hasFocus()) {
+ if(req.type && req.type === 'qapp-local-notification'){
+ try {
+ dispatcher({ type: NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL, data: req })
+
+ } catch (error) {
+ console.log('error', error)
+ }
+ }else if (!document.hasFocus()) {
newMessage()
} else {
if (page.includes(req.url) === false) {
diff --git a/core/src/notifications/dispatcher.js b/core/src/notifications/dispatcher.js
index b74e11e1..b0c7713e 100644
--- a/core/src/notifications/dispatcher.js
+++ b/core/src/notifications/dispatcher.js
@@ -1,5 +1,5 @@
-import { NEW_MESSAGE, NEW_MESSAGE_NOTIFICATION_QAPP } from './types'
-import { newMessage, newMessageNotificationQapp } from './notification-actions'
+import { NEW_MESSAGE, NEW_MESSAGE_NOTIFICATION_QAPP, NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL } from './types'
+import { newMessage, newMessageNotificationQapp, newMessageNotificationQappLocal } from './notification-actions'
export const dispatcher = function (notificationState) {
@@ -8,6 +8,8 @@ export const dispatcher = function (notificationState) {
return newMessage(notificationState.data)
case NEW_MESSAGE_NOTIFICATION_QAPP:
return newMessageNotificationQapp(notificationState.data)
+ case NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL:
+ return newMessageNotificationQappLocal(notificationState.data)
default:
}
}
diff --git a/core/src/notifications/notification-actions/index.js b/core/src/notifications/notification-actions/index.js
index 02faea66..cc2f8937 100644
--- a/core/src/notifications/notification-actions/index.js
+++ b/core/src/notifications/notification-actions/index.js
@@ -1 +1 @@
-export { newMessage, newMessageNotificationQapp } from './new-message'
+export { newMessage, newMessageNotificationQapp, newMessageNotificationQappLocal } from './new-message'
diff --git a/core/src/notifications/notification-actions/new-message.js b/core/src/notifications/notification-actions/new-message.js
index 26803216..932da937 100644
--- a/core/src/notifications/notification-actions/new-message.js
+++ b/core/src/notifications/notification-actions/new-message.js
@@ -1,6 +1,9 @@
import { store } from '../../store.js'
import { doPageUrl, setNewTab } from '../../redux/app/app-actions.js'
import isElectron from 'is-electron'
+import ShortUniqueId from 'short-unique-id';
+
+const uid = new ShortUniqueId()
export const newMessage = (data) => {
const alert = playSound(data.sound)
@@ -101,6 +104,157 @@ export const newMessageNotificationQapp = (data) => {
}
}
+}
+
+ const extractComponents= async (url)=> {
+ if (!url.startsWith("qortal://")) {
+ return null;
+ }
+
+ url = url.replace(/^(qortal\:\/\/)/, "");
+ if (url.includes("/")) {
+ let parts = url.split("/");
+ const service = parts[0].toUpperCase();
+ parts.shift();
+ const name = parts[0];
+ parts.shift();
+ let identifier;
+
+ if (parts.length > 0) {
+ identifier = parts[0]; // Do not shift yet
+ // Check if a resource exists with this service, name and identifier combination
+ let responseObj = await parentEpml.request('apiCall', {
+ url: `/arbitrary/resource/status/${service}/${name}/${identifier}?apiKey=${this.getApiKey()}`
+ })
+
+ if (responseObj.totalChunkCount > 0) {
+ // Identifier exists, so don't include it in the path
+ parts.shift();
+ }
+ else {
+ identifier = null;
+ }
+ }
+
+ const path = parts.join("/");
+
+ const components = {};
+ components["service"] = service;
+ components["name"] = name;
+ components["identifier"] = identifier;
+ components["path"] = path;
+ return components;
+ }
+
+ return null;
+}
+
+export const newMessageNotificationQappLocal = (data) => {
+ const alert = playSound(data.sound)
+
+ // Should I show notification ?
+ if (store.getState().user.notifications.q_chat.showNotification) {
+
+ // Yes, I can but should I play sound ?
+ if (store.getState().user.notifications.q_chat.playSound) {
+
+ const notify = new Notification(data.title, data.options)
+
+ notify.onshow = (e) => {
+ alert.play()
+ }
+
+ notify.onclick = async(e) => {
+ const url = data?.url
+ const value = url
+ let newQuery = value;
+ if (newQuery.endsWith('/')) {
+ newQuery = newQuery.slice(0, -1);
+ }
+ const res = await extractComponents(newQuery)
+ if (!res) return
+ const { service, name, identifier, path } = res
+ let query = `?service=${service}`
+ if (name) {
+ query = query + `&name=${name}`
+ }
+ if (identifier) {
+ query = query + `&identifier=${identifier}`
+ }
+ if (path) {
+ query = query + `&path=${path}`
+ }
+ const tab = {
+ url: `qdn/browser/index.html${query}`,
+ id: uid(),
+ myPlugObj: {
+ "url": service === 'WEBSITE' ? "websites" : "qapps",
+ "domain": "core",
+ "page": `qdn/browser/index.html${query}`,
+ "title": name,
+ "icon": service === 'WEBSITE' ? 'vaadin:desktop' : 'vaadin:external-browser',
+ "mwcicon": service === 'WEBSITE' ? 'desktop_mac' : 'open_in_browser',
+ "menus": [],
+ "parent": false
+ }
+ }
+ store.dispatch(setNewTab(tab))
+ if (!isElectron()) {
+ window.focus();
+ } else {
+ window.electronAPI.focusApp()
+ }
+
+ }
+ } else {
+
+ const notify = new Notification(data.title, data.options)
+
+ notify.onclick = async(e) => {
+ const url = data?.url
+ const value = url
+ let newQuery = value;
+ if (newQuery.endsWith('/')) {
+ newQuery = newQuery.slice(0, -1);
+ }
+ const res = await extractComponents(newQuery)
+ if (!res) return
+ const { service, name, identifier, path } = res
+ let query = `?service=${service}`
+ if (name) {
+ query = query + `&name=${name}`
+ }
+ if (identifier) {
+ query = query + `&identifier=${identifier}`
+ }
+ if (path) {
+ query = query + `&path=${path}`
+ }
+ const tab = {
+ url: `qdn/browser/index.html${query}`,
+ id: uid(),
+ myPlugObj: {
+ "url": service === 'WEBSITE' ? "websites" : "qapps",
+ "domain": "core",
+ "page": `qdn/browser/index.html${query}`,
+ "title": name,
+ "icon": service === 'WEBSITE' ? 'vaadin:desktop' : 'vaadin:external-browser',
+ "mwcicon": service === 'WEBSITE' ? 'desktop_mac' : 'open_in_browser',
+ "menus": [],
+ "parent": false
+ }
+ }
+ store.dispatch(setNewTab(tab))
+ if (!isElectron()) {
+ window.focus();
+ } else {
+ window.electronAPI.focusApp()
+ }
+
+ }
+ }
+ }
+
}
const playSound = (soundUrl) => {
diff --git a/core/src/notifications/types.js b/core/src/notifications/types.js
index 0f8b1c05..f50b3ec7 100644
--- a/core/src/notifications/types.js
+++ b/core/src/notifications/types.js
@@ -1,2 +1,3 @@
export const NEW_MESSAGE = 'NEW_MESSAGE'
export const NEW_MESSAGE_NOTIFICATION_QAPP = 'NEW_MESSAGE_NOTIFICATION_QAPP'
+export const NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL = 'NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL'
diff --git a/core/src/redux/app/actions/app-core.js b/core/src/redux/app/actions/app-core.js
index 8ed9455f..7c7ab9bd 100644
--- a/core/src/redux/app/actions/app-core.js
+++ b/core/src/redux/app/actions/app-core.js
@@ -1,5 +1,5 @@
// Core App Actions here...
-import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS } from '../app-action-types.js'
+import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG } from '../app-action-types.js'
export const doUpdateBlockInfo = (blockObj) => {
return (dispatch, getState) => {
@@ -126,7 +126,12 @@ export const setNewTab = (payload) => {
payload
}
}
-
+export const setIsOpenDevDialog = (payload)=> {
+ return {
+ type: IS_OPEN_DEV_DIALOG,
+ payload
+ }
+}
export const addTabInfo = (payload) => {
return {
type: ADD_TAB_INFO,
diff --git a/core/src/redux/app/app-action-types.js b/core/src/redux/app/app-action-types.js
index 31f9b246..ba2cde2a 100644
--- a/core/src/redux/app/app-action-types.js
+++ b/core/src/redux/app/app-action-types.js
@@ -27,4 +27,5 @@ export const SET_CHAT_LAST_SEEN = 'SET_CHAT_LAST_SEEN'
export const ADD_CHAT_LAST_SEEN = 'ADD_CHAT_LAST_SEEN'
export const SET_NEW_TAB = 'SET_NEW_TAB'
export const ADD_TAB_INFO = 'ADD_TAB_INFO'
-export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS'
\ No newline at end of file
+export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS'
+export const IS_OPEN_DEV_DIALOG = 'IS_OPEN_DEV_DIALOG'
\ No newline at end of file
diff --git a/core/src/redux/app/app-reducer.js b/core/src/redux/app/app-reducer.js
index 0fd3c2cc..11e77486 100644
--- a/core/src/redux/app/app-reducer.js
+++ b/core/src/redux/app/app-reducer.js
@@ -1,6 +1,6 @@
// Loading state, login state, isNavDrawOpen state etc. None of this needs to be saved to localstorage.
import { loadStateFromLocalStorage, saveStateToLocalStorage } from '../../localStorageHelpers.js'
-import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS } from './app-action-types.js'
+import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG } from './app-action-types.js'
import { initWorkersReducer } from './reducers/init-workers.js'
import { loginReducer } from './reducers/login-reducer.js'
import { setNode, addNode } from './reducers/manage-node.js'
@@ -49,7 +49,8 @@ const INITIAL_STATE = {
qAPPAutoLists: loadStateFromLocalStorage('qAPPAutoLists') || false,
chatLastSeen: [],
newTab: null,
- tabInfo: {}
+ tabInfo: {},
+ isOpenDevDialog: false
}
export default (state = INITIAL_STATE, action) => {
@@ -231,6 +232,12 @@ export default (state = INITIAL_STATE, action) => {
newTab: action.payload
}
}
+ case IS_OPEN_DEV_DIALOG: {
+ return {
+ ...state,
+ isOpenDevDialog: action.payload
+ }
+ }
case ADD_TAB_INFO: {
const newTabInfo = action.payload
if (state.tabInfo[newTabInfo.id] && state.tabInfo[newTabInfo.id].name && newTabInfo.name === state.tabInfo[newTabInfo.id].name) break
diff --git a/core/src/redux/app/version.js b/core/src/redux/app/version.js
index 91ebdadc..51e897a7 100644
--- a/core/src/redux/app/version.js
+++ b/core/src/redux/app/version.js
@@ -1 +1 @@
-export const UI_VERSION = "4.0.4";
+export const UI_VERSION = "4.3.0";
diff --git a/electron.js b/electron.js
index dea2efa6..eabb96eb 100644
--- a/electron.js
+++ b/electron.js
@@ -845,7 +845,7 @@ function createWindow() {
})
myWindow.maximize()
myWindow.show()
- myWindow.loadURL('http://localhost:12388/app/wallet')
+ myWindow.loadURL('http://localhost:12388/app')
myWindow.on('closed', function () {
myWindow = null
})
@@ -886,7 +886,7 @@ function createNewWindow() {
show: false
})
newWindow.show()
- newWindow.loadURL('http://localhost:12388/app/wallet')
+ newWindow.loadURL('http://localhost:12388/app')
newWindow.on('closed', function () {
newWindow = null
})
diff --git a/plugins/plugins/core/components/ChatPage.js b/plugins/plugins/core/components/ChatPage.js
index 0171bcf3..890ade4e 100644
--- a/plugins/plugins/core/components/ChatPage.js
+++ b/plugins/plugins/core/components/ChatPage.js
@@ -1870,7 +1870,7 @@ class ChatPage extends LitElement {
return memberItem
})
const membersWithName = await Promise.all(getMembersWithName)
- this.groupMembers = membersWithName
+ this.groupMembers = [...this.groupMembers, ...membersWithName]
this.pageNumber = this.pageNumber + 1
} catch (error) {
}
diff --git a/plugins/plugins/core/components/ChatRightPanel.js b/plugins/plugins/core/components/ChatRightPanel.js
index fac86ebf..24a90f59 100644
--- a/plugins/plugins/core/components/ChatRightPanel.js
+++ b/plugins/plugins/core/components/ChatRightPanel.js
@@ -225,7 +225,6 @@ class ChatRightPanel extends LitElement {
if(this.groupMembers.length < 20){
return
}
- console.log('this.leaveGroupObjp', this.leaveGroupObj)
this.getMoreMembers(this.leaveGroupObj.groupId)
}
}
@@ -252,7 +251,6 @@ class ChatRightPanel extends LitElement {
activeChatHeadUrl=""
.setActiveChatHeadUrl=${(val) => {
if (val.address === this.myAddress) return;
- console.log({ val });
this.selectedHead = val;
this.setOpenUserInfo(true);
this.setUserName({
@@ -269,7 +267,6 @@ class ChatRightPanel extends LitElement {
activeChatHeadUrl=""
.setActiveChatHeadUrl=${(val) => {
if (val.address === this.myAddress) return;
- console.log({ val });
this.selectedHead = val;
this.setOpenUserInfo(true);
this.setUserName({
@@ -286,7 +283,6 @@ class ChatRightPanel extends LitElement {
activeChatHeadUrl=""
.setActiveChatHeadUrl=${(val) => {
if (val.address === this.myAddress) return;
- console.log({ val });
this.selectedHead = val;
this.setOpenUserInfo(true);
this.setUserName({
diff --git a/plugins/plugins/core/components/ChatScroller.js b/plugins/plugins/core/components/ChatScroller.js
index f5ee24de..e1506232 100644
--- a/plugins/plugins/core/components/ChatScroller.js
+++ b/plugins/plugins/core/components/ChatScroller.js
@@ -101,7 +101,7 @@ function processText(input) {
// Store the URL in a data attribute
link.setAttribute('data-url', part)
link.textContent = part
- link.style.color = 'var(--nav-text-color)'
+ link.style.color = 'var(--code-block-text-color)'
link.style.textDecoration = 'underline'
link.style.cursor = 'pointer'
@@ -125,7 +125,7 @@ function processText(input) {
url: `qdn/browser/index.html${query}`,
id: uid(),
myPlugObj: {
- "url": service === 'WEBSITE' ? "websites" : "qapps",
+ "url": "myapp",
"domain": "core",
"page": `qdn/browser/index.html${query}`,
"title": name,
diff --git a/plugins/plugins/core/components/qdn-action-types.js b/plugins/plugins/core/components/qdn-action-types.js
index fd337ad1..59385690 100644
--- a/plugins/plugins/core/components/qdn-action-types.js
+++ b/plugins/plugins/core/components/qdn-action-types.js
@@ -50,4 +50,13 @@ export const DECRYPT_DATA_GROUP = 'DECRYPT_DATA_GROUP'
export const SAVE_FILE = 'SAVE_FILE'
//SET_TAB_NOTIFICATIONS
-export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS'
\ No newline at end of file
+export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS'
+
+//OPEN_NEW_TAB
+export const OPEN_NEW_TAB = 'OPEN_NEW_TAB'
+
+//NOTIFICATIONS_PERMISSION
+export const NOTIFICATIONS_PERMISSION = 'NOTIFICATIONS_PERMISSION'
+
+//SEND_LOCAL_NOTIFICATION
+export const SEND_LOCAL_NOTIFICATION = 'SEND_LOCAL_NOTIFICATION'
\ No newline at end of file
diff --git a/plugins/plugins/core/qdn/browser/browser.src.js b/plugins/plugins/core/qdn/browser/browser.src.js
index 02b8aa9b..a18f2f37 100644
--- a/plugins/plugins/core/qdn/browser/browser.src.js
+++ b/plugins/plugins/core/qdn/browser/browser.src.js
@@ -3,6 +3,7 @@ import { render } from 'lit/html.js'
import { Epml } from '../../../../epml'
import isElectron from 'is-electron'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
+import ShortUniqueId from 'short-unique-id';
registerTranslateConfig({
loader: (lang) => fetch(`/language/${lang}.json`).then((res) => res.json())
@@ -131,6 +132,7 @@ class WebBrowser extends LitElement {
constructor() {
super();
this.url = 'about:blank';
+ this.uid = new ShortUniqueId()
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress
this._publicKey = { key: '', hasPubKey: false }
const urlParams = new URLSearchParams(window.location.search)
@@ -318,6 +320,44 @@ class WebBrowser extends LitElement {
}
}
+ async linkOpenNewTab(link) {
+
+ const value = link
+ let newQuery = value;
+ if (newQuery.endsWith('/')) {
+ newQuery = newQuery.slice(0, -1);
+ }
+ const res = await this.extractComponents(newQuery)
+ if (!res) return
+ const { service, name, identifier, path } = res
+ let query = `?service=${service}`
+ if (name) {
+ query = query + `&name=${name}`
+ }
+ if (identifier) {
+ query = query + `&identifier=${identifier}`
+ }
+ if (path) {
+ query = query + `&path=${path}`
+ }
+
+ window.parent.reduxStore.dispatch(window.parent.reduxAction.setNewTab({
+ url: `qdn/browser/index.html${query}`,
+ id: this.uid(),
+ myPlugObj: {
+ "url": service === 'WEBSITE' ? "websites" : "qapps",
+ "domain": "core",
+ "page": `qdn/browser/index.html${query}`,
+ "title": name,
+ "icon": service === 'WEBSITE' ? 'vaadin:desktop' : 'vaadin:external-browser',
+ "mwcicon": service === 'WEBSITE' ? 'desktop_mac' : 'open_in_browser',
+ "menus": [],
+ "parent": false
+ }
+ }))
+
+ }
+
render() {
return html`
@@ -1280,8 +1320,95 @@ class WebBrowser extends LitElement {
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
break;
}
+ case actions.OPEN_NEW_TAB: {
+ if(!data.qortalLink){
+ const obj = {};
+ const errorMsg = 'Please enter a qortal link - qortal://...';
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ break
+ }
+ try {
+ await this.linkOpenNewTab(data.qortalLink)
+ response = true
+ break;
+ } catch (error) {
+ console.log('error', error)
+ const obj = {};
+ const errorMsg = "Invalid qortal link";
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ break;
+ }
+
+ }
+ case actions.NOTIFICATIONS_PERMISSION: {
+ try {
+ const res = await showModalAndWait(
+ actions.NOTIFICATIONS_PERMISSION,
+ {
+ name: this.name
+ }
+ );
+ if (res.action === 'accept'){
+ this.addAppToNotificationList(this.name)
+ response = true
+ break;
+ } else {
+ response = false
+ break;
+ }
+
+ } catch (error) {
+ break;
+ }
+
+ }
+ case actions.SEND_LOCAL_NOTIFICATION: {
+ const {title, url, icon, message} = data
+ try {
+ const id = `appNotificationList-${this.selectedAddress.address}`
+ const checkData = localStorage.getItem(id) ? JSON.parse(localStorage.getItem(id)) : null;
+ if(!checkData || !checkData[this.name]) throw new Error('App not on permission list')
+ const appInfo = checkData[this.name]
+ const lastNotification = appInfo.lastNotification
+ const interval = appInfo.interval
+ if (lastNotification && interval) {
+ const timeDifference = Date.now() - lastNotification;
+
+ if (timeDifference > interval) {
+ parentEpml.request('showNotification', {
+ title, type: "qapp-local-notification", sound: '', url, options: { body: message, icon, badge: icon }
+ })
+ response = true
+ this.updateLastNotification(id, this.name)
+ break;
+ } else {
+ throw new Error(`duration until another notification can be sent: ${interval - timeDifference}`)
+ }
+ } else if(!lastNotification){
+ parentEpml.request('showNotification', {
+ title, type: "qapp-local-notification", sound: '', url, options: { body: message, icon, badge: icon }
+ })
+ response = true
+ this.updateLastNotification(id)
+ break;
+ } else {
+ throw new Error(`invalid data`)
+ }
+
+ } catch (error) {
+ const obj = {};
+ const errorMsg = error.message || "error in pushing notification";
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ break;
+
+ }
+
+ }
case actions.SEND_CHAT_MESSAGE: {
const message = data.message;
const recipient = data.destinationAddress;
@@ -2734,6 +2861,46 @@ class WebBrowser extends LitElement {
use(checkLanguage);
}
}
+ addAppToNotificationList(appName) {
+ if(!appName) throw new Error('unknown app name')
+ const id = `appNotificationList-${this.selectedAddress.address}`;
+ const checkData = localStorage.getItem(id) ? JSON.parse(localStorage.getItem(id)) : null;
+
+ if (!checkData) {
+ const newData = {
+ [appName]: {
+ interval: 900000, // 15mins in milliseconds
+ lastNotification: null,
+ },
+ };
+ localStorage.setItem(id, JSON.stringify(newData));
+ } else {
+ const copyData = { ...checkData };
+ copyData[appName] = {
+ interval: 900000, // 15mins in milliseconds
+ lastNotification: null,
+ };
+ localStorage.setItem(id, JSON.stringify(copyData));
+ }
+ }
+
+ updateLastNotification(id, appName) {
+ const checkData = localStorage.getItem(id) ? JSON.parse(localStorage.getItem(id)) : null;
+
+ if (checkData) {
+ const copyData = { ...checkData };
+ if (copyData[appName]) {
+ copyData[appName].lastNotification = Date.now(); // Make sure to use Date.now(), not date.now()
+ } else {
+ copyData[appName] = {
+ interval: 900000, // 15mins in milliseconds
+ lastNotification: Date.now(),
+ };
+ }
+ localStorage.setItem(id, JSON.stringify(copyData));
+ }
+ }
+
renderFollowUnfollowButton() {
// Only show the follow/unfollow button if we have permission to modify the list on this node
@@ -3085,7 +3252,12 @@ async function showModalAndWait(type, data) {
${get("browserpage.bchange46")}: ${data.filename}
` : ''}
-
+ ${type === actions.NOTIFICATIONS_PERMISSION ? `
+