mirror of
https://github.com/h3poteto/whalebird-desktop
synced 2025-01-30 17:15:16 +01:00
Merge pull request #883 from h3poteto/iss-850
refs #850 Replace main with typescript
This commit is contained in:
commit
9ab7ca26fd
@ -79,7 +79,7 @@ function startRenderer () {
|
||||
|
||||
function startMain () {
|
||||
return new Promise((resolve, reject) => {
|
||||
mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main)
|
||||
mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.ts')].concat(mainConfig.entry.main)
|
||||
mainConfig.mode = 'development'
|
||||
const compiler = webpack(mainConfig)
|
||||
|
||||
|
@ -11,7 +11,7 @@ const MinifyPlugin = require('babel-minify-webpack-plugin')
|
||||
|
||||
let mainConfig = {
|
||||
entry: {
|
||||
main: path.join(__dirname, '../src/main/index.js')
|
||||
main: path.join(__dirname, '../src/main/index.ts')
|
||||
},
|
||||
externals: [
|
||||
...Object.keys(dependencies || {})
|
||||
@ -19,7 +19,7 @@ let mainConfig = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js)$/,
|
||||
test: /\.(js|ts)$/,
|
||||
enforce: 'pre',
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
@ -65,6 +65,11 @@ let mainConfig = {
|
||||
])
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
// Same as tsconfig.json
|
||||
'@': path.join(__dirname, '../src/renderer'),
|
||||
'~': path.join(__dirname, '../')
|
||||
},
|
||||
extensions: ['.js', '.json', '.node', '.ts']
|
||||
},
|
||||
target: 'electron-main'
|
||||
|
134
package-lock.json
generated
134
package-lock.json
generated
@ -1963,6 +1963,92 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
|
||||
"integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w=="
|
||||
},
|
||||
"@types/electron-json-storage": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/electron-json-storage/-/electron-json-storage-4.0.0.tgz",
|
||||
"integrity": "sha512-b1+VXOjCPENmXhV0q41NCsJIFwpIjPfuJk++h53O4dQhb2RBZYEMTuAnu/UC+0+PhvmysT1f5WNt8RHM3vGevA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"electron": "1.8.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "8.10.45",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.45.tgz",
|
||||
"integrity": "sha512-tGVTbA+i3qfXsLbq9rEq/hezaHY55QxQLeXQL2ejNgFAxxrgu8eMmYIOsRcl7hN1uTLVsKOOYacV/rcJM3sfgQ==",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"electron": {
|
||||
"version": "1.8.8",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-1.8.8.tgz",
|
||||
"integrity": "sha512-1f9zJehcTTGjrkb06o6ds+gsRq6SYhZJyxOk6zIWjRH8hVy03y/RzUDELzNas71f5vcvXmfGVvyjeEsadDI8tg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "8.10.45",
|
||||
"electron-download": "3.3.0",
|
||||
"extract-zip": "1.6.7"
|
||||
}
|
||||
},
|
||||
"electron-download": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-download/-/electron-download-3.3.0.tgz",
|
||||
"integrity": "sha1-LP1U1pZsAZxNSa1l++Zcyc3vaMg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "2.6.9",
|
||||
"fs-extra": "0.30.0",
|
||||
"home-path": "1.0.6",
|
||||
"minimist": "1.2.0",
|
||||
"nugget": "2.0.1",
|
||||
"path-exists": "2.1.0",
|
||||
"rc": "1.2.8",
|
||||
"semver": "5.5.0",
|
||||
"sumchecker": "1.3.1"
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "0.30.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
|
||||
"integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11",
|
||||
"jsonfile": "2.4.0",
|
||||
"klaw": "1.3.1",
|
||||
"path-is-absolute": "1.0.1",
|
||||
"rimraf": "2.6.2"
|
||||
}
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
|
||||
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pinkie-promise": "2.0.1"
|
||||
}
|
||||
},
|
||||
"sumchecker": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-1.3.1.tgz",
|
||||
"integrity": "sha1-ebs7RFbdBPGOvbwNcDodHa7FEF0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "2.6.9",
|
||||
"es6-promise": "4.2.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/events": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
|
||||
@ -2009,6 +2095,15 @@
|
||||
"integrity": "sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/nedb": {
|
||||
"version": "1.8.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/nedb/-/nedb-1.8.7.tgz",
|
||||
"integrity": "sha512-9YAo9VTD+AFj2/yar+T9+/u/t+pn9CtuXnIYcGADwbknWyymuIO4WXOY8boYYNO7bk4DIbDBpIMfHED3pUpkJA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "11.11.4"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "11.11.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.4.tgz",
|
||||
@ -6939,12 +7034,12 @@
|
||||
}
|
||||
},
|
||||
"electron-context-menu": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-context-menu/-/electron-context-menu-0.10.1.tgz",
|
||||
"integrity": "sha512-KFkKwFbT6iJUgarEknYuXQlJAT+naJZtSWFBtHf9RiSb70wscWdDNpYoUERzF7FgqYE1Mil4npfRWsjqGLwtog==",
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-context-menu/-/electron-context-menu-0.12.0.tgz",
|
||||
"integrity": "sha512-kZEPG3a864UQOZDJnfsVUiWjhonIpfPPtH8Z7luvPUf7sra/Sz1x2n3aRnyzGN8jQhgRvQomJg/QKXHNbZZ/+g==",
|
||||
"requires": {
|
||||
"electron-dl": "1.12.0",
|
||||
"electron-is-dev": "1.0.1"
|
||||
"electron-dl": "1.14.0",
|
||||
"electron-is-dev": "1.1.0"
|
||||
}
|
||||
},
|
||||
"electron-debug": {
|
||||
@ -6978,9 +7073,9 @@
|
||||
}
|
||||
},
|
||||
"electron-dl": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-1.12.0.tgz",
|
||||
"integrity": "sha512-UMc2CL45Ybpvu66LDPYzwmDRmYK4Ivz+wdnTM0eXcNMztvQwhixAk2UPme1c7McqG8bAlKEkQpZn3epmQy4EWg==",
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-1.14.0.tgz",
|
||||
"integrity": "sha512-4okyei42a1mLsvLK7hLrIfd20EQzB18nIlLTwBV992aMSmTGLUEFRTmO1MfSslGNrzD8nuPuy1l/VxO8so4lig==",
|
||||
"requires": {
|
||||
"ext-name": "5.0.0",
|
||||
"pupa": "1.0.0",
|
||||
@ -7017,9 +7112,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"electron-is-dev": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.0.1.tgz",
|
||||
"integrity": "sha512-iwM3EotA9HTXqMGpQRkR/kT8OZqBbdfHTnlwcxsjSLYqY8svvsq0MuujsWCn3/vtgRmDv/PC/gKUUpoZvi5C1w=="
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.1.0.tgz",
|
||||
"integrity": "sha512-Z1qA/1oHNowGtSBIcWk0pcLEqYT/j+13xUw/MYOrBUOL4X7VN0i0KCTf5SqyvMPmW5pSPKbo28wkxMxzZ20YnQ=="
|
||||
},
|
||||
"electron-json-storage": {
|
||||
"version": "4.1.5",
|
||||
@ -7420,6 +7515,12 @@
|
||||
"is-symbol": "1.0.1"
|
||||
}
|
||||
},
|
||||
"es6-promise": {
|
||||
"version": "4.2.6",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz",
|
||||
"integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==",
|
||||
"dev": true
|
||||
},
|
||||
"es6-templates": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz",
|
||||
@ -10126,6 +10227,12 @@
|
||||
"os-tmpdir": "1.0.2"
|
||||
}
|
||||
},
|
||||
"home-path": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/home-path/-/home-path-1.0.6.tgz",
|
||||
"integrity": "sha512-wo+yjrdAtoXt43Vy92a+0IPCYViiyLAHyp0QVS4xL/tfvVz5sXIW1ubLZk3nhVkD92fQpUMKX+fzMjr5F489vw==",
|
||||
"dev": true
|
||||
},
|
||||
"homedir-polyfill": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz",
|
||||
@ -10914,11 +11021,6 @@
|
||||
"resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
|
||||
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
|
||||
},
|
||||
"is-empty": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/is-empty/-/is-empty-1.2.0.tgz",
|
||||
"integrity": "sha1-3pu1snhzigWgsJpX4ftNSjQan2s="
|
||||
},
|
||||
"is-extendable": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
|
||||
|
@ -132,7 +132,7 @@
|
||||
"axios": "^0.18.0",
|
||||
"boom": "^7.3.0",
|
||||
"deep-extend": "^0.6.0",
|
||||
"electron-context-menu": "^0.10.1",
|
||||
"electron-context-menu": "^0.12.0",
|
||||
"electron-json-storage": "^4.1.5",
|
||||
"electron-log": "^2.2.17",
|
||||
"electron-window-state": "^5.0.3",
|
||||
@ -143,7 +143,6 @@
|
||||
"hoek": "^6.1.2",
|
||||
"i18next": "^12.1.0",
|
||||
"i18next-sync-fs-backend": "^1.1.0",
|
||||
"is-empty": "^1.2.0",
|
||||
"lodash": "^4.17.11",
|
||||
"megalodon": "0.6.3",
|
||||
"moment": "^2.21.0",
|
||||
@ -171,9 +170,11 @@
|
||||
"@babel/preset-env": "^7.4.2",
|
||||
"@babel/preset-typescript": "^7.3.3",
|
||||
"@mapbox/stylelint-processor-arbitrary-tags": "^0.2.0",
|
||||
"@types/electron-json-storage": "^4.0.0",
|
||||
"@types/i18next": "^12.1.0",
|
||||
"@types/jest": "^24.0.11",
|
||||
"@types/lodash": "^4.14.123",
|
||||
"@types/nedb": "^1.8.7",
|
||||
"@types/node": "^11.11.4",
|
||||
"@types/parse-link-header": "^1.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^1.5.0",
|
||||
|
@ -3,7 +3,7 @@ import Vuex from 'vuex'
|
||||
import { ipcMain } from '~/spec/mock/electron'
|
||||
import App from '@/store/App'
|
||||
import DisplayStyle from '~/src/constants/displayStyle'
|
||||
import { LightTheme, DarkTheme } from '@/utils/theme'
|
||||
import { LightTheme, DarkTheme } from '~/src/constants/themeColor'
|
||||
import Theme from '~/src/constants/theme'
|
||||
import TimeFormat from '~/src/constants/timeFormat'
|
||||
import Language from '~/src/constants/language'
|
||||
|
@ -3,7 +3,7 @@ import Vuex from 'vuex'
|
||||
import Theme from '~/src/constants/theme'
|
||||
import DisplayStyle from '~/src/constants/displayStyle'
|
||||
import TimeFormat from '~/src/constants/timeFormat'
|
||||
import { LightTheme, DarkTheme } from '~/src/renderer/utils/theme'
|
||||
import { LightTheme, DarkTheme } from '~/src/constants/themeColor'
|
||||
import DefaultFonts from '@/utils/fonts'
|
||||
import Appearance, { AppearanceState } from '@/store/Preferences/Appearance'
|
||||
import { ipcMain } from '~/spec/mock/electron'
|
||||
|
@ -4,7 +4,7 @@ import { createLocalVue } from '@vue/test-utils'
|
||||
import Vuex from 'vuex'
|
||||
import { ipcMain } from '~/spec/mock/electron'
|
||||
import SideMenu, { SideMenuState } from '~/src/renderer/store/TimelineSpace/SideMenu'
|
||||
import Hashtag from '~/src/types/hashtag'
|
||||
import LocalTag from '~/src/types/localTag'
|
||||
|
||||
jest.mock('megalodon')
|
||||
|
||||
@ -116,10 +116,10 @@ describe('SideMenu', () => {
|
||||
|
||||
describe('listTags', () => {
|
||||
it('should be listed', async () => {
|
||||
const tag1: Hashtag = {
|
||||
const tag1: LocalTag = {
|
||||
tagName: 'tag1'
|
||||
}
|
||||
const tag2: Hashtag = {
|
||||
const tag2: LocalTag = {
|
||||
tagName: 'tag2'
|
||||
}
|
||||
ipcMain.once('list-hashtags', (event: any, _) => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Theme from '~/src/constants/theme'
|
||||
import DisplayStyle from '~/src/constants/displayStyle'
|
||||
import TimeFormat from '~/src/constants/timeFormat'
|
||||
import { LightTheme } from '~/src/renderer/utils/theme'
|
||||
import { LightTheme } from '~/src/constants/themeColor'
|
||||
import DefaultFonts from '@/utils/fonts'
|
||||
import Appearance, { AppearanceState, MUTATION_TYPES } from '@/store/Preferences/Appearance'
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import i18n from '~/src/config/i18n'
|
||||
import Jump, { JumpState, MUTATION_TYPES, Channel } from '@/store/TimelineSpace/Modals/Jump'
|
||||
import Hashtag from '~/src/types/hashtag'
|
||||
import LocalTag from '~/src/types/localTag'
|
||||
import { List } from 'megalodon'
|
||||
|
||||
describe('TimelineSpace/Modals/Jump', () => {
|
||||
@ -87,10 +87,10 @@ describe('TimelineSpace/Modals/Jump', () => {
|
||||
|
||||
describe('updateTagChannel', () => {
|
||||
it('should be updated', () => {
|
||||
const whalebird: Hashtag = {
|
||||
const whalebird: LocalTag = {
|
||||
tagName: 'whalebird'
|
||||
}
|
||||
const tqrk: Hashtag = {
|
||||
const tqrk: LocalTag = {
|
||||
tagName: 'tqrk'
|
||||
}
|
||||
const channelList = [whalebird, tqrk]
|
||||
|
@ -1,4 +1,4 @@
|
||||
export type ThemeType = {
|
||||
export type ThemeColorType = {
|
||||
background_color: string,
|
||||
selected_background_color: string,
|
||||
global_header_color: string,
|
||||
@ -11,10 +11,10 @@ export type ThemeType = {
|
||||
wrapper_mask_color: string
|
||||
}
|
||||
|
||||
declare var LightTheme: ThemeType
|
||||
declare var DarkTheme: ThemeType
|
||||
declare var SolarizedLightTheme: ThemeType
|
||||
declare var SolarizedDarkTheme: ThemeType
|
||||
declare var KimbieDarkTheme: ThemeType
|
||||
declare var LightTheme: ThemeColorType
|
||||
declare var DarkTheme: ThemeColorType
|
||||
declare var SolarizedLightTheme: ThemeColorType
|
||||
declare var SolarizedDarkTheme: ThemeColorType
|
||||
declare var KimbieDarkTheme: ThemeColorType
|
||||
|
||||
export { LightTheme, DarkTheme, SolarizedLightTheme, SolarizedDarkTheme, KimbieDarkTheme }
|
@ -1,8 +1,12 @@
|
||||
import empty from 'is-empty'
|
||||
import Mastodon from 'megalodon'
|
||||
import { isEmpty } from 'lodash'
|
||||
import Mastodon, { Account as RemoteAccount } from 'megalodon'
|
||||
import Datastore from 'nedb'
|
||||
import LocalAccount from '~/src/types/localAccount'
|
||||
|
||||
export default class Account {
|
||||
constructor (db) {
|
||||
private db: Datastore
|
||||
|
||||
constructor (db: Datastore) {
|
||||
this.db = db
|
||||
}
|
||||
|
||||
@ -12,7 +16,7 @@ export default class Account {
|
||||
await this.updateUnique()
|
||||
}
|
||||
|
||||
updateUnique () {
|
||||
updateUnique (): Promise<{}> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// At first, remove old index.
|
||||
this.db.removeIndex('order', (err) => {
|
||||
@ -20,7 +24,7 @@ export default class Account {
|
||||
// Add unique index.
|
||||
this.db.ensureIndex({ fieldName: 'order', unique: true, sparse: true }, (err) => {
|
||||
if (err) reject(err)
|
||||
resolve(null)
|
||||
resolve({})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -32,7 +36,7 @@ export default class Account {
|
||||
async reorder () {
|
||||
const accounts = await this.listAllAccounts()
|
||||
await Promise.all(accounts.map(async (account, index) => {
|
||||
const update = await this.updateAccount(account._id, Object.assign(account, { order: index + 1 }))
|
||||
const update = await this.updateAccount(account._id!, Object.assign(account, { order: index + 1 }))
|
||||
return update
|
||||
}))
|
||||
const ordered = await this.listAllAccounts()
|
||||
@ -49,18 +53,18 @@ export default class Account {
|
||||
}
|
||||
if (accounts[0].order < 1 || accounts[accounts.length - 1].order > accounts.length) {
|
||||
await Promise.all(accounts.map(async (element, index) => {
|
||||
const update = await this.updateAccount(element._id, Object.assign(element, { order: index + 1 }))
|
||||
const update = await this.updateAccount(element._id!, Object.assign(element, { order: index + 1 }))
|
||||
return update
|
||||
}))
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
insertAccount (obj) {
|
||||
insertAccount (localAccount: LocalAccount): Promise<LocalAccount> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.insert(obj, (err, doc) => {
|
||||
this.db.insert<LocalAccount>(localAccount, (err, doc) => {
|
||||
if (err) return reject(err)
|
||||
if (empty(doc)) return reject(new EmptyRecordError('empty'))
|
||||
if (isEmpty(doc)) return reject(new EmptyRecordError('empty'))
|
||||
resolve(doc)
|
||||
})
|
||||
})
|
||||
@ -69,11 +73,11 @@ export default class Account {
|
||||
/**
|
||||
* List up all accounts either authenticated or not authenticated.
|
||||
*/
|
||||
listAllAccounts (order = 1) {
|
||||
listAllAccounts (order = 1): Promise<Array<LocalAccount>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.find().sort({ order: order }).exec((err, docs) => {
|
||||
this.db.find<LocalAccount>({}).sort({ order: order }).exec((err, docs) => {
|
||||
if (err) return reject(err)
|
||||
if (empty(docs)) return reject(new EmptyRecordError('empty'))
|
||||
if (isEmpty(docs)) return reject(new EmptyRecordError('empty'))
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
@ -82,59 +86,59 @@ export default class Account {
|
||||
/**
|
||||
* List up authenticated accounts.
|
||||
*/
|
||||
listAccounts () {
|
||||
listAccounts (): Promise<Array<LocalAccount>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.find({ accessToken: { $ne: '' } }).sort({ order: 1 }).exec((err, docs) => {
|
||||
this.db.find<LocalAccount>({ accessToken: { $ne: '' } }).sort({ order: 1 }).exec((err, docs) => {
|
||||
if (err) return reject(err)
|
||||
if (empty(docs)) return reject(new EmptyRecordError('empty'))
|
||||
if (isEmpty(docs)) return reject(new EmptyRecordError('empty'))
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Get the last account.
|
||||
async lastAccount () {
|
||||
async lastAccount (): Promise<LocalAccount> {
|
||||
const accounts = await this.listAllAccounts(-1)
|
||||
return accounts[0]
|
||||
}
|
||||
|
||||
getAccount (id) {
|
||||
getAccount (id: string): Promise<LocalAccount> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.findOne(
|
||||
this.db.findOne<LocalAccount>(
|
||||
{
|
||||
_id: id
|
||||
},
|
||||
(err, doc) => {
|
||||
if (err) return reject(err)
|
||||
if (empty(doc)) return reject(new EmptyRecordError('empty'))
|
||||
if (isEmpty(doc)) return reject(new EmptyRecordError('empty'))
|
||||
resolve(doc)
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
searchAccount (obj) {
|
||||
searchAccount (obj: any): Promise<LocalAccount> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.findOne(
|
||||
this.db.findOne<LocalAccount>(
|
||||
obj,
|
||||
(err, doc) => {
|
||||
if (err) return reject(err)
|
||||
if (empty(doc)) return reject(new EmptyRecordError('empty'))
|
||||
if (isEmpty(doc)) return reject(new EmptyRecordError('empty'))
|
||||
resolve(doc)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
searchAccounts (obj, order = 1) {
|
||||
searchAccounts (obj: any, order = 1): Promise<Array<LocalAccount>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.find(obj).sort({ order: order }).exec((err, docs) => {
|
||||
this.db.find<LocalAccount>(obj).sort({ order: order }).exec((err, docs) => {
|
||||
if (err) return reject(err)
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
updateAccount (id, obj) {
|
||||
updateAccount (id: string, obj: any): Promise<LocalAccount> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.update(
|
||||
{
|
||||
@ -144,13 +148,13 @@ export default class Account {
|
||||
{ multi: true },
|
||||
(err, _numReplaced) => {
|
||||
if (err) return reject(err)
|
||||
this.db.findOne(
|
||||
this.db.findOne<LocalAccount>(
|
||||
{
|
||||
_id: id
|
||||
},
|
||||
(err, doc) => {
|
||||
if (err) return reject(err)
|
||||
if (empty(doc)) return reject(new EmptyRecordError('empty'))
|
||||
if (isEmpty(doc)) return reject(new EmptyRecordError('empty'))
|
||||
resolve(doc)
|
||||
})
|
||||
}
|
||||
@ -158,7 +162,7 @@ export default class Account {
|
||||
})
|
||||
}
|
||||
|
||||
removeAccount (id) {
|
||||
removeAccount (id: string): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.remove(
|
||||
{
|
||||
@ -173,7 +177,7 @@ export default class Account {
|
||||
})
|
||||
}
|
||||
|
||||
removeAll () {
|
||||
removeAll (): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.remove(
|
||||
{},
|
||||
@ -186,7 +190,7 @@ export default class Account {
|
||||
})
|
||||
}
|
||||
|
||||
async forwardAccount (ac) {
|
||||
async forwardAccount (ac: LocalAccount): Promise<LocalAccount | {}> {
|
||||
// Find account which is the previous of the target account.
|
||||
const accounts = await this.searchAccounts({ order: { $lt: ac.order } }, -1)
|
||||
.catch((err) => {
|
||||
@ -194,7 +198,7 @@ export default class Account {
|
||||
return []
|
||||
})
|
||||
if (accounts.length < 1) {
|
||||
return null
|
||||
return Promise.resolve({})
|
||||
}
|
||||
const previousAccount = accounts[0]
|
||||
const targetOrder = ac.order
|
||||
@ -202,21 +206,21 @@ export default class Account {
|
||||
|
||||
// At first, we need to update the previous account with dummy order.
|
||||
// Because this column is uniqued, so can not update with same order.
|
||||
await this.updateAccount(previousAccount._id, Object.assign(
|
||||
await this.updateAccount(previousAccount._id!, Object.assign(
|
||||
previousAccount,
|
||||
{
|
||||
order: -1
|
||||
}
|
||||
))
|
||||
// Change order of the target account.
|
||||
const updated = await this.updateAccount(ac._id, Object.assign(
|
||||
const updated = await this.updateAccount(ac._id!, Object.assign(
|
||||
ac,
|
||||
{
|
||||
order: previousOrder
|
||||
}
|
||||
))
|
||||
// Update the previous account with right order.
|
||||
await this.updateAccount(previousAccount._id, Object.assign(
|
||||
await this.updateAccount(previousAccount._id!, Object.assign(
|
||||
previousAccount,
|
||||
{
|
||||
order: targetOrder
|
||||
@ -225,7 +229,7 @@ export default class Account {
|
||||
return updated
|
||||
}
|
||||
|
||||
async backwardAccount (ac) {
|
||||
async backwardAccount (ac: LocalAccount): Promise<LocalAccount | {}> {
|
||||
// Find account which is the next of the target account.
|
||||
const accounts = await this.searchAccounts({ order: { $gt: ac.order } }, 1)
|
||||
.catch((err) => {
|
||||
@ -233,7 +237,7 @@ export default class Account {
|
||||
return []
|
||||
})
|
||||
if (accounts.length < 1) {
|
||||
return null
|
||||
return Promise.resolve({})
|
||||
}
|
||||
const nextAccount = accounts[0]
|
||||
const targetOrder = ac.order
|
||||
@ -241,21 +245,21 @@ export default class Account {
|
||||
|
||||
// At first, we need to update the next account with dummy order.
|
||||
// Because this colum is uniqued, so can not update with same order.
|
||||
await this.updateAccount(nextAccount._id, Object.assign(
|
||||
await this.updateAccount(nextAccount._id!, Object.assign(
|
||||
nextAccount,
|
||||
{
|
||||
order: -1
|
||||
}
|
||||
))
|
||||
// Change order of the target account/
|
||||
const updated = await this.updateAccount(ac._id, Object.assign(
|
||||
const updated = await this.updateAccount(ac._id!, Object.assign(
|
||||
ac,
|
||||
{
|
||||
order: nextOrder
|
||||
}
|
||||
))
|
||||
// Update the next account with right order.
|
||||
await this.updateAccount(nextAccount._id, Object.assign(
|
||||
await this.updateAccount(nextAccount._id!, Object.assign(
|
||||
nextAccount,
|
||||
{
|
||||
order: targetOrder
|
||||
@ -264,10 +268,10 @@ export default class Account {
|
||||
return updated
|
||||
}
|
||||
|
||||
async refreshAccounts () {
|
||||
async refreshAccounts (): Promise<Array<LocalAccount>> {
|
||||
const accounts = await this.listAccounts()
|
||||
if (accounts.length < 1) {
|
||||
return accounts.length
|
||||
return accounts
|
||||
}
|
||||
const results = await Promise.all(accounts.map(async (account) => {
|
||||
const refresh = await this.refresh(account)
|
||||
@ -276,51 +280,41 @@ export default class Account {
|
||||
return results
|
||||
}
|
||||
|
||||
refresh (account) {
|
||||
async refresh (account: LocalAccount): Promise<LocalAccount> {
|
||||
const client = new Mastodon(
|
||||
account.accessToken,
|
||||
account.accessToken!,
|
||||
account.baseURL + '/api/v1'
|
||||
)
|
||||
return client.get('/accounts/verify_credentials')
|
||||
return client.get<RemoteAccount>('/accounts/verify_credentials')
|
||||
.then(res => {
|
||||
const json = {
|
||||
username: res.data.username,
|
||||
accountId: res.data.id,
|
||||
avatar: res.data.avatar
|
||||
}
|
||||
return this.updateAccount(account._id, json)
|
||||
return this.updateAccount(account._id!, json)
|
||||
})
|
||||
}
|
||||
|
||||
// Confirm the access token, and check duplicate
|
||||
async fetchAccount (account, accessToken) {
|
||||
async fetchAccount (account: LocalAccount, accessToken: string): Promise<RemoteAccount> {
|
||||
const client = new Mastodon(
|
||||
accessToken,
|
||||
account.baseURL + '/api/v1'
|
||||
)
|
||||
const data = await client.get('/accounts/verify_credentials')
|
||||
const res = await client.get<RemoteAccount>('/accounts/verify_credentials')
|
||||
const query = {
|
||||
baseURL: account.baseURL,
|
||||
username: data.username
|
||||
username: res.data.username
|
||||
}
|
||||
const duplicates = await this.searchAccounts(query)
|
||||
if (duplicates.length > 0) {
|
||||
throw new DuplicateRecordError(`${data.username}@${account.baseURL} is duplicated`)
|
||||
throw new DuplicateRecordError(`${res.data.username}@${account.baseURL} is duplicated`)
|
||||
}
|
||||
return data
|
||||
return res.data
|
||||
}
|
||||
}
|
||||
|
||||
class EmptyRecordError extends Error {
|
||||
constructor (msg) {
|
||||
super(msg)
|
||||
this.name = 'EmptyRecordError'
|
||||
}
|
||||
}
|
||||
class EmptyRecordError extends Error {}
|
||||
|
||||
class DuplicateRecordError extends Error {
|
||||
constructor (msg) {
|
||||
super(msg)
|
||||
this.name = 'DuplicateRecordError'
|
||||
}
|
||||
}
|
||||
class DuplicateRecordError extends Error {}
|
@ -1,11 +1,20 @@
|
||||
import Mastodon from 'megalodon'
|
||||
import Account from './account'
|
||||
import LocalAccount from '~src/types/localAccount'
|
||||
|
||||
const appName = 'Whalebird'
|
||||
const appURL = 'https://whalebird.org'
|
||||
const scope = 'read write follow'
|
||||
|
||||
export default class Authentication {
|
||||
constructor (accountDB) {
|
||||
private db: Account
|
||||
private baseURL: string
|
||||
private domain: string
|
||||
private clientId: string
|
||||
private clientSecret: string
|
||||
private protocol: 'http' | 'https'
|
||||
|
||||
constructor (accountDB: Account) {
|
||||
this.db = accountDB
|
||||
this.baseURL = ''
|
||||
this.domain = ''
|
||||
@ -14,14 +23,14 @@ export default class Authentication {
|
||||
this.protocol = 'https'
|
||||
}
|
||||
|
||||
setOtherInstance (domain) {
|
||||
setOtherInstance (domain: string) {
|
||||
this.baseURL = `${this.protocol}://${domain}`
|
||||
this.domain = domain
|
||||
this.clientId = ''
|
||||
this.clientSecret = ''
|
||||
}
|
||||
|
||||
async getAuthorizationUrl (domain = 'mastodon.social') {
|
||||
async getAuthorizationUrl (domain = 'mastodon.social'): Promise<string> {
|
||||
this.setOtherInstance(domain)
|
||||
const res = await Mastodon.registerApp(
|
||||
appName, {
|
||||
@ -39,7 +48,7 @@ export default class Authentication {
|
||||
console.log(err)
|
||||
return 1
|
||||
})
|
||||
const json = {
|
||||
const local: LocalAccount = {
|
||||
baseURL: this.baseURL,
|
||||
domain: this.domain,
|
||||
clientId: this.clientId,
|
||||
@ -47,15 +56,18 @@ export default class Authentication {
|
||||
accessToken: '',
|
||||
refreshToken: '',
|
||||
username: '',
|
||||
accountId: '',
|
||||
accountId: null,
|
||||
avatar: '',
|
||||
order: order
|
||||
}
|
||||
await this.db.insertAccount(json)
|
||||
await this.db.insertAccount(local)
|
||||
if (res.url === null) {
|
||||
throw new AuthenticationURLError('Can not get url')
|
||||
}
|
||||
return res.url
|
||||
}
|
||||
|
||||
async getAccessToken (code) {
|
||||
async getAccessToken (code: string): Promise<string> {
|
||||
const tokenData = await Mastodon.fetchAccessToken(this.clientId, this.clientSecret, code, this.baseURL)
|
||||
const search = {
|
||||
baseURL: this.baseURL,
|
||||
@ -67,7 +79,7 @@ export default class Authentication {
|
||||
const accessToken = tokenData.accessToken
|
||||
const refreshToken = tokenData.refreshToken
|
||||
const data = await this.db.fetchAccount(rec, accessToken)
|
||||
await this.db.updateAccount(rec._id, {
|
||||
await this.db.updateAccount(rec._id!, {
|
||||
username: data.username,
|
||||
accountId: data.id,
|
||||
avatar: data.avatar,
|
||||
@ -78,3 +90,5 @@ export default class Authentication {
|
||||
}
|
||||
// TODO: Refresh access token when expired
|
||||
}
|
||||
|
||||
class AuthenticationURLError extends Error {}
|
@ -1,9 +1,9 @@
|
||||
import SystemFonts from 'system-font-families'
|
||||
|
||||
const fonts = () => {
|
||||
const fonts = async (): Promise<Array<string>> => {
|
||||
const systemFonts = new SystemFonts()
|
||||
return systemFonts.getFonts()
|
||||
.then(res => {
|
||||
.then((res: string) => {
|
||||
return Array.from(new Set(res)).sort()
|
||||
})
|
||||
}
|
@ -1,19 +1,24 @@
|
||||
import Datastore from 'nedb'
|
||||
import LocalTag from '~/src/types/localTag'
|
||||
|
||||
export default class Hashtags {
|
||||
constructor (db) {
|
||||
private db: Datastore
|
||||
|
||||
constructor (db: Datastore) {
|
||||
this.db = db
|
||||
this.db.ensureIndex({ fieldName: 'tagName', unique: true }, (_) => {})
|
||||
}
|
||||
|
||||
listTags () {
|
||||
listTags (): Promise<Array<LocalTag>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.find({}, (err, docs) => {
|
||||
this.db.find<LocalTag>({}, (err, docs) => {
|
||||
if (err) return reject(err)
|
||||
resolve(docs)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
insertTag (tag) {
|
||||
insertTag (tag: string): Promise<LocalTag> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.insert({ tagName: tag }, (err, doc) => {
|
||||
if (err) return reject(err)
|
||||
@ -22,11 +27,11 @@ export default class Hashtags {
|
||||
})
|
||||
}
|
||||
|
||||
removeTag (tag) {
|
||||
removeTag (localTag: LocalTag): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.remove(
|
||||
{
|
||||
tagName: tag.tagName
|
||||
tagName: localTag.tagName
|
||||
},
|
||||
{ multi: true },
|
||||
(err, numRemoved) => {
|
@ -1,25 +1,29 @@
|
||||
'use strict'
|
||||
|
||||
import { app, ipcMain, shell, Menu, Tray } from 'electron'
|
||||
import { app, ipcMain, shell, Menu, Tray, BrowserWindow, BrowserWindowConstructorOptions, MenuItemConstructorOptions, Event } from 'electron'
|
||||
import Datastore from 'nedb'
|
||||
import empty from 'is-empty'
|
||||
import { isEmpty } from 'lodash'
|
||||
import log from 'electron-log'
|
||||
import windowStateKeeper from 'electron-window-state'
|
||||
import simplayer from 'simplayer'
|
||||
import path from 'path'
|
||||
import ContextMenu from 'electron-context-menu'
|
||||
import * as Splashscreen from '@trodi/electron-splashscreen'
|
||||
import { initSplashScreen, Config } from '@trodi/electron-splashscreen'
|
||||
import openAboutWindow from 'about-window'
|
||||
import { Status, Notification } from 'megalodon'
|
||||
|
||||
import Authentication from './auth'
|
||||
import Account from './account'
|
||||
import StreamingManager from './streaming_manager'
|
||||
import StreamingManager from './streamingManager'
|
||||
import Preferences from './preferences'
|
||||
import Fonts from './fonts'
|
||||
import Hashtags from './hashtags'
|
||||
import UnreadNotification from './unread_notification'
|
||||
import UnreadNotification from './unreadNotification'
|
||||
import i18n from '../config/i18n'
|
||||
import Language from '../constants/language'
|
||||
import LocalAccount from '~src/types/localAccount'
|
||||
import LocalTag from '~src/types/localTag'
|
||||
import { UnreadNotification as UnreadNotificationConfig } from '~/src/types/unreadNotification'
|
||||
|
||||
/**
|
||||
* Context menu
|
||||
@ -32,6 +36,10 @@ ContextMenu()
|
||||
log.transports.console.level = 'debug'
|
||||
log.transports.file.level = 'info'
|
||||
|
||||
declare namespace global {
|
||||
let __static: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Set `__static` path to static files in production
|
||||
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
|
||||
@ -40,8 +48,8 @@ if (process.env.NODE_ENV !== 'development') {
|
||||
global.__static = path.join(__dirname, '/static').replace(/\\/g, '\\\\')
|
||||
}
|
||||
|
||||
let mainWindow
|
||||
let tray = null
|
||||
let mainWindow: BrowserWindow | null
|
||||
let tray: Tray
|
||||
const winURL = process.env.NODE_ENV === 'development'
|
||||
? `http://localhost:9080`
|
||||
: `file://${__dirname}/index.html`
|
||||
@ -61,7 +69,7 @@ let accountDB = new Datastore({
|
||||
})
|
||||
const accountManager = new Account(accountDB)
|
||||
accountManager.initialize()
|
||||
.catch(err => log.error(err))
|
||||
.catch((err: Error) => log.error(err))
|
||||
|
||||
const hashtagsDBPath = process.env.NODE_ENV === 'production'
|
||||
? userData + '/db/hashtags.db'
|
||||
@ -76,7 +84,7 @@ const unreadNotificationDBPath = process.env.NODE_ENV === 'production'
|
||||
: 'unread_notification.db'
|
||||
const unreadNotification = new UnreadNotification(unreadNotificationDBPath)
|
||||
unreadNotification.initialize()
|
||||
.catch(err => log.error(err))
|
||||
.catch((err: Error) => log.error(err))
|
||||
|
||||
const preferencesDBPath = process.env.NODE_ENV === 'production'
|
||||
? userData + './db/preferences.json'
|
||||
@ -84,9 +92,9 @@ const preferencesDBPath = process.env.NODE_ENV === 'production'
|
||||
|
||||
const soundBasePath = process.env.NODE_ENV === 'development'
|
||||
? path.join(__dirname, '../../build/sounds/')
|
||||
: path.join(process.resourcesPath, 'build/sounds/')
|
||||
: path.join(process.resourcesPath!, 'build/sounds/')
|
||||
|
||||
async function listAccounts () {
|
||||
async function listAccounts (): Promise<Array<LocalAccount>> {
|
||||
try {
|
||||
const accounts = await accountManager.listAccounts()
|
||||
return accounts
|
||||
@ -95,14 +103,14 @@ async function listAccounts () {
|
||||
}
|
||||
}
|
||||
|
||||
async function changeAccount (account, index) {
|
||||
async function changeAccount (account: LocalAccount, index: number) {
|
||||
// In MacOS, user can hide the window.
|
||||
// In this time, mainWindow in not exist, so we have to create window.
|
||||
if (mainWindow === null) {
|
||||
await createWindow()
|
||||
// We have to wait the web contents is loaded.
|
||||
mainWindow.webContents.on('did-finish-load', () => {
|
||||
mainWindow.webContents.send('change-account', Object.assign(account, { index: index }))
|
||||
mainWindow!.webContents.on('did-finish-load', () => {
|
||||
mainWindow!.webContents.send('change-account', Object.assign(account, { index: index }))
|
||||
})
|
||||
} else {
|
||||
mainWindow.webContents.send('change-account', Object.assign(account, { index: index }))
|
||||
@ -123,24 +131,24 @@ async function getLanguage () {
|
||||
* Minimize to tray when click close button
|
||||
*/
|
||||
async function setMinimizeToTray () {
|
||||
mainWindow.on('close', (event) => {
|
||||
mainWindow.hide()
|
||||
mainWindow.setSkipTaskbar(true)
|
||||
mainWindow!.on('close', (event) => {
|
||||
mainWindow!.hide()
|
||||
mainWindow!.setSkipTaskbar(true)
|
||||
event.preventDefault()
|
||||
})
|
||||
tray = new Tray(path.join(__dirname, '../../build/icons/256x256.png'))
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{ label: i18n.t('main_menu.application.quit'), click: () => { mainWindow.destroy() } }
|
||||
{ label: i18n.t('main_menu.application.quit'), click: () => { mainWindow!.destroy() } }
|
||||
])
|
||||
tray.setToolTip(i18n.t('main_menu.application.name'))
|
||||
tray.setContextMenu(contextMenu)
|
||||
tray.on('click', () => {
|
||||
if (mainWindow.isVisible()) {
|
||||
mainWindow.hide()
|
||||
mainWindow.setSkipTaskbar(true)
|
||||
if (mainWindow!.isVisible()) {
|
||||
mainWindow!.hide()
|
||||
mainWindow!.setSkipTaskbar(true)
|
||||
} else {
|
||||
mainWindow.show()
|
||||
mainWindow.setSkipTaskbar(false)
|
||||
mainWindow!.show()
|
||||
mainWindow!.setSkipTaskbar(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -150,7 +158,7 @@ async function createWindow () {
|
||||
* List accounts
|
||||
*/
|
||||
const accounts = await listAccounts()
|
||||
const accountsChange = accounts.map((a, index) => {
|
||||
const accountsChange: Array<MenuItemConstructorOptions> = accounts.map((a, index) => {
|
||||
return {
|
||||
label: a.domain,
|
||||
accelerator: `CmdOrCtrl+${index + 1}`,
|
||||
@ -187,10 +195,10 @@ async function createWindow () {
|
||||
*/
|
||||
let mainWindowState = windowStateKeeper({
|
||||
defaultWidth: 1000,
|
||||
height: 563
|
||||
defaultHeight: 563
|
||||
})
|
||||
// mainWindow = new BrowserWindow({
|
||||
const mainOpts = {
|
||||
const mainOpts: BrowserWindowConstructorOptions = {
|
||||
titleBarStyle: 'hidden',
|
||||
x: mainWindowState.x,
|
||||
y: mainWindowState.y,
|
||||
@ -199,7 +207,7 @@ async function createWindow () {
|
||||
useContentSize: true,
|
||||
icon: path.resolve(__dirname, '../../build/icons/256x256.png')
|
||||
}
|
||||
const config = {
|
||||
const config: Config = {
|
||||
windowOpts: mainOpts,
|
||||
templateUrl: splashURL,
|
||||
splashScreenOpts: {
|
||||
@ -207,7 +215,7 @@ async function createWindow () {
|
||||
height: 325
|
||||
}
|
||||
}
|
||||
mainWindow = Splashscreen.initSplashScreen(config)
|
||||
mainWindow = initSplashScreen(config)
|
||||
|
||||
mainWindowState.manage(mainWindow)
|
||||
|
||||
@ -238,14 +246,16 @@ app.on('window-all-closed', () => {
|
||||
} else {
|
||||
// In MacOS, we should change disable some menu items.
|
||||
const menu = Menu.getApplicationMenu()
|
||||
// Preferences
|
||||
menu.items[0].submenu.items[2].enabled = false
|
||||
// New Toot
|
||||
menu.items[1].submenu.items[0].enabled = false
|
||||
// Open Window
|
||||
menu.items[4].submenu.items[1].enabled = true
|
||||
// Jump to
|
||||
menu.items[4].submenu.items[4].enabled = false
|
||||
if (menu !== null) {
|
||||
// Preferences
|
||||
((menu.items[0] as MenuItemConstructorOptions).submenu as Menu).items[2].enabled = false as boolean
|
||||
// New Toot
|
||||
((menu.items[1] as MenuItemConstructorOptions).submenu as Menu).items[0].enabled = false as boolean
|
||||
// Open Window
|
||||
((menu.items[4] as MenuItemConstructorOptions).submenu as Menu).items[1].enabled = true as boolean
|
||||
// Jump to
|
||||
((menu.items[4] as MenuItemConstructorOptions).submenu as Menu).items[4].enabled = false as boolean
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -257,7 +267,7 @@ app.on('activate', () => {
|
||||
|
||||
let auth = new Authentication(accountManager)
|
||||
|
||||
ipcMain.on('get-auth-url', (event, domain) => {
|
||||
ipcMain.on('get-auth-url', (event: Event, domain: string) => {
|
||||
auth.getAuthorizationUrl(domain)
|
||||
.then((url) => {
|
||||
log.debug(url)
|
||||
@ -271,14 +281,14 @@ ipcMain.on('get-auth-url', (event, domain) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('get-access-token', (event, code) => {
|
||||
ipcMain.on('get-access-token', (event: Event, code: string) => {
|
||||
auth.getAccessToken(code)
|
||||
.then((token) => {
|
||||
accountDB.findOne({
|
||||
accessToken: token
|
||||
}, (err, doc) => {
|
||||
}, (err, doc: any) => {
|
||||
if (err) return event.sender.send('error-get-access-token', err)
|
||||
if (empty(doc)) return event.sender.send('error-get-access-token', 'error document is empty')
|
||||
if (isEmpty(doc)) return event.sender.send('error-get-access-token', 'error document is empty')
|
||||
event.sender.send('response-get-access-token', doc._id)
|
||||
})
|
||||
})
|
||||
@ -289,16 +299,16 @@ ipcMain.on('get-access-token', (event, code) => {
|
||||
})
|
||||
|
||||
// environments
|
||||
ipcMain.on('get-social-token', (event, _) => {
|
||||
ipcMain.on('get-social-token', (event: Event) => {
|
||||
const token = process.env.SOCIAL_TOKEN
|
||||
if (empty(token)) {
|
||||
if (isEmpty(token)) {
|
||||
return event.sender.send('error-get-social-token', new EmptyTokenError())
|
||||
}
|
||||
event.sender.send('response-get-social-token', token)
|
||||
})
|
||||
|
||||
// nedb
|
||||
ipcMain.on('list-accounts', (event, _) => {
|
||||
ipcMain.on('list-accounts', (event: Event) => {
|
||||
accountManager.listAccounts()
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
@ -309,7 +319,7 @@ ipcMain.on('list-accounts', (event, _) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('get-local-account', (event, id) => {
|
||||
ipcMain.on('get-local-account', (event: Event, id: string) => {
|
||||
accountManager.getAccount(id)
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
@ -320,7 +330,7 @@ ipcMain.on('get-local-account', (event, id) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('update-account', (event, acct) => {
|
||||
ipcMain.on('update-account', (event: Event, acct: LocalAccount) => {
|
||||
accountManager.refresh(acct)
|
||||
.then((ac) => {
|
||||
event.sender.send('response-update-account', ac)
|
||||
@ -330,7 +340,7 @@ ipcMain.on('update-account', (event, acct) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('remove-account', (event, id) => {
|
||||
ipcMain.on('remove-account', (event: Event, id: string) => {
|
||||
accountManager.removeAccount(id)
|
||||
.then(() => {
|
||||
event.sender.send('response-remove-account')
|
||||
@ -340,7 +350,7 @@ ipcMain.on('remove-account', (event, id) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('forward-account', (event, acct) => {
|
||||
ipcMain.on('forward-account', (event: Event, acct: LocalAccount) => {
|
||||
accountManager.forwardAccount(acct)
|
||||
.then(() => {
|
||||
event.sender.send('response-forward-account')
|
||||
@ -351,7 +361,7 @@ ipcMain.on('forward-account', (event, acct) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('backward-account', (event, acct) => {
|
||||
ipcMain.on('backward-account', (event: Event, acct: LocalAccount) => {
|
||||
accountManager.backwardAccount(acct)
|
||||
.then(() => {
|
||||
event.sender.send('response-backward-account')
|
||||
@ -361,7 +371,7 @@ ipcMain.on('backward-account', (event, acct) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('refresh-accounts', (event, _) => {
|
||||
ipcMain.on('refresh-accounts', (event: Event) => {
|
||||
accountManager.refreshAccounts()
|
||||
.then((accounts) => {
|
||||
event.sender.send('response-refresh-accounts', accounts)
|
||||
@ -371,7 +381,7 @@ ipcMain.on('refresh-accounts', (event, _) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('remove-all-accounts', (event, _) => {
|
||||
ipcMain.on('remove-all-accounts', (event: Event) => {
|
||||
accountManager.removeAll()
|
||||
.then(() => {
|
||||
event.sender.send('response-remove-all-accounts')
|
||||
@ -390,15 +400,16 @@ ipcMain.on('reset-badge', () => {
|
||||
})
|
||||
|
||||
// streaming
|
||||
let userStreaming = null
|
||||
let userStreaming: StreamingManager | null = null
|
||||
|
||||
ipcMain.on('start-user-streaming', (event, obj) => {
|
||||
type StreamingSetting = {
|
||||
account: LocalAccount,
|
||||
useWebsocket: boolean
|
||||
}
|
||||
|
||||
ipcMain.on('start-user-streaming', (event: Event, obj: StreamingSetting) => {
|
||||
const { account, useWebsocket } = obj
|
||||
accountManager.getAccount(account._id)
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-user-streaming', err)
|
||||
})
|
||||
accountManager.getAccount(account._id!)
|
||||
.then((acct) => {
|
||||
// Stop old user streaming
|
||||
if (userStreaming !== null) {
|
||||
@ -408,10 +419,10 @@ ipcMain.on('start-user-streaming', (event, obj) => {
|
||||
|
||||
userStreaming = new StreamingManager(acct, useWebsocket)
|
||||
userStreaming.startUser(
|
||||
(update) => {
|
||||
(update: Status) => {
|
||||
event.sender.send('update-start-user-streaming', update)
|
||||
},
|
||||
(notification) => {
|
||||
(notification: Notification) => {
|
||||
event.sender.send('notification-start-user-streaming', notification)
|
||||
// Does not exist a endpoint for only mention. And mention is a part of notification.
|
||||
// So we have to get mention from notification.
|
||||
@ -422,7 +433,7 @@ ipcMain.on('start-user-streaming', (event, obj) => {
|
||||
app.dock.setBadge('•')
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
(err: Error) => {
|
||||
log.error(err)
|
||||
// In macOS, sometimes window is closed (not quit).
|
||||
// When window is closed, we can not send event to webContents; because it is destroyed.
|
||||
@ -433,24 +444,24 @@ ipcMain.on('start-user-streaming', (event, obj) => {
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-user-streaming', err)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('stop-user-streaming', (_event, _) => {
|
||||
ipcMain.on('stop-user-streaming', () => {
|
||||
if (userStreaming !== null) {
|
||||
userStreaming.stop()
|
||||
userStreaming = null
|
||||
}
|
||||
})
|
||||
|
||||
let directMessagesStreaming = null
|
||||
let directMessagesStreaming: StreamingManager | null = null
|
||||
|
||||
ipcMain.on('start-directmessages-streaming', (event, obj) => {
|
||||
ipcMain.on('start-directmessages-streaming', (event: Event, obj: StreamingSetting) => {
|
||||
const { account, useWebsocket } = obj
|
||||
accountManager.getAccount(account._id)
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-directmessages-streaming', err)
|
||||
})
|
||||
accountManager.getAccount(account._id!)
|
||||
.then((acct) => {
|
||||
// Stop old directmessages streaming
|
||||
if (directMessagesStreaming !== null) {
|
||||
@ -462,10 +473,10 @@ ipcMain.on('start-directmessages-streaming', (event, obj) => {
|
||||
directMessagesStreaming.start(
|
||||
'direct',
|
||||
'',
|
||||
(update) => {
|
||||
(update: Status) => {
|
||||
event.sender.send('update-start-directmessages-streaming', update)
|
||||
},
|
||||
(err) => {
|
||||
(err: Error) => {
|
||||
log.error(err)
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send('error-start-directmessages-streaming', err)
|
||||
@ -473,24 +484,24 @@ ipcMain.on('start-directmessages-streaming', (event, obj) => {
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-directmessages-streaming', err)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('stop-directmessages-streaming', (_event, _) => {
|
||||
ipcMain.on('stop-directmessages-streaming', () => {
|
||||
if (directMessagesStreaming !== null) {
|
||||
directMessagesStreaming.stop()
|
||||
directMessagesStreaming = null
|
||||
}
|
||||
})
|
||||
|
||||
let localStreaming = null
|
||||
let localStreaming: StreamingManager | null = null
|
||||
|
||||
ipcMain.on('start-local-streaming', (event, obj) => {
|
||||
ipcMain.on('start-local-streaming', (event: Event, obj: StreamingSetting) => {
|
||||
const { account, useWebsocket } = obj
|
||||
accountManager.getAccount(account._id)
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-local-streaming', err)
|
||||
})
|
||||
accountManager.getAccount(account._id!)
|
||||
.then((acct) => {
|
||||
// Stop old local streaming
|
||||
if (localStreaming !== null) {
|
||||
@ -502,10 +513,10 @@ ipcMain.on('start-local-streaming', (event, obj) => {
|
||||
localStreaming.start(
|
||||
'public/local',
|
||||
'',
|
||||
(update) => {
|
||||
(update: Status) => {
|
||||
event.sender.send('update-start-local-streaming', update)
|
||||
},
|
||||
(err) => {
|
||||
(err: Error) => {
|
||||
log.error(err)
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send('error-start-local-streaming', err)
|
||||
@ -513,24 +524,24 @@ ipcMain.on('start-local-streaming', (event, obj) => {
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-local-streaming', err)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('stop-local-streaming', (_event, _) => {
|
||||
ipcMain.on('stop-local-streaming', () => {
|
||||
if (localStreaming !== null) {
|
||||
localStreaming.stop()
|
||||
localStreaming = null
|
||||
}
|
||||
})
|
||||
|
||||
let publicStreaming = null
|
||||
let publicStreaming: StreamingManager | null = null
|
||||
|
||||
ipcMain.on('start-public-streaming', (event, obj) => {
|
||||
ipcMain.on('start-public-streaming', (event: Event, obj: StreamingSetting) => {
|
||||
const { account, useWebsocket } = obj
|
||||
accountManager.getAccount(account._id)
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-public-streaming', err)
|
||||
})
|
||||
accountManager.getAccount(account._id!)
|
||||
.then((acct) => {
|
||||
// Stop old public streaming
|
||||
if (publicStreaming !== null) {
|
||||
@ -542,10 +553,10 @@ ipcMain.on('start-public-streaming', (event, obj) => {
|
||||
publicStreaming.start(
|
||||
'public',
|
||||
'',
|
||||
(update) => {
|
||||
(update: Status) => {
|
||||
event.sender.send('update-start-public-streaming', update)
|
||||
},
|
||||
(err) => {
|
||||
(err: Error) => {
|
||||
log.error(err)
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send('error-start-public-streaming', err)
|
||||
@ -553,24 +564,28 @@ ipcMain.on('start-public-streaming', (event, obj) => {
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-public-streaming', err)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('stop-public-streaming', (_event, _) => {
|
||||
ipcMain.on('stop-public-streaming', () => {
|
||||
if (publicStreaming !== null) {
|
||||
publicStreaming.stop()
|
||||
publicStreaming = null
|
||||
}
|
||||
})
|
||||
|
||||
let listStreaming = null
|
||||
let listStreaming: StreamingManager | null = null
|
||||
|
||||
ipcMain.on('start-list-streaming', (event, obj) => {
|
||||
type ListID = {
|
||||
listID: number
|
||||
}
|
||||
|
||||
ipcMain.on('start-list-streaming', (event: Event, obj: ListID & StreamingSetting) => {
|
||||
const { listID, account, useWebsocket } = obj
|
||||
accountManager.getAccount(account._id)
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-list-streaming', err)
|
||||
})
|
||||
accountManager.getAccount(account._id!)
|
||||
.then((acct) => {
|
||||
// Stop old list streaming
|
||||
if (listStreaming !== null) {
|
||||
@ -582,10 +597,10 @@ ipcMain.on('start-list-streaming', (event, obj) => {
|
||||
listStreaming.start(
|
||||
'list',
|
||||
`list=${listID}`,
|
||||
(update) => {
|
||||
(update: Status) => {
|
||||
event.sender.send('update-start-list-streaming', update)
|
||||
},
|
||||
(err) => {
|
||||
(err: Error) => {
|
||||
log.error(err)
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send('error-start-list-streaming', err)
|
||||
@ -593,24 +608,28 @@ ipcMain.on('start-list-streaming', (event, obj) => {
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-list-streaming', err)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('stop-list-streaming', (_event, _) => {
|
||||
ipcMain.on('stop-list-streaming', () => {
|
||||
if (listStreaming !== null) {
|
||||
listStreaming.stop()
|
||||
listStreaming = null
|
||||
}
|
||||
})
|
||||
|
||||
let tagStreaming = null
|
||||
let tagStreaming: StreamingManager | null = null
|
||||
|
||||
ipcMain.on('start-tag-streaming', (event, obj) => {
|
||||
type Tag = {
|
||||
tag: string
|
||||
}
|
||||
|
||||
ipcMain.on('start-tag-streaming', (event: Event, obj: Tag & StreamingSetting) => {
|
||||
const { tag, account, useWebsocket } = obj
|
||||
accountManager.getAccount(account._id)
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-tag-streaming', err)
|
||||
})
|
||||
accountManager.getAccount(account._id!)
|
||||
.then((acct) => {
|
||||
// Stop old tag streaming
|
||||
if (tagStreaming !== null) {
|
||||
@ -622,10 +641,10 @@ ipcMain.on('start-tag-streaming', (event, obj) => {
|
||||
tagStreaming.start(
|
||||
'hashtag',
|
||||
`tag=${tag}`,
|
||||
(update) => {
|
||||
(update: Status) => {
|
||||
event.sender.send('update-start-tag-streaming', update)
|
||||
},
|
||||
(err) => {
|
||||
(err: Error) => {
|
||||
log.error(err)
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send('error-start-tag-streaming', err)
|
||||
@ -633,9 +652,13 @@ ipcMain.on('start-tag-streaming', (event, obj) => {
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch((err) => {
|
||||
log.error(err)
|
||||
event.sender.send('error-start-tag-streaming', err)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('stop-tag-streaming', (_event, _) => {
|
||||
ipcMain.on('stop-tag-streaming', () => {
|
||||
if (tagStreaming !== null) {
|
||||
tagStreaming.stop()
|
||||
tagStreaming = null
|
||||
@ -643,13 +666,13 @@ ipcMain.on('stop-tag-streaming', (_event, _) => {
|
||||
})
|
||||
|
||||
// sounds
|
||||
ipcMain.on('fav-rt-action-sound', (_event, _) => {
|
||||
ipcMain.on('fav-rt-action-sound', () => {
|
||||
const preferences = new Preferences(preferencesDBPath)
|
||||
preferences.load()
|
||||
.then((conf) => {
|
||||
if (conf.general.sound.fav_rb) {
|
||||
const sound = path.join(soundBasePath, 'operation_sound01.wav')
|
||||
simplayer(sound, (err) => {
|
||||
simplayer(sound, (err: Error) => {
|
||||
if (err) log.error(err)
|
||||
})
|
||||
}
|
||||
@ -657,13 +680,13 @@ ipcMain.on('fav-rt-action-sound', (_event, _) => {
|
||||
.catch(err => log.error(err))
|
||||
})
|
||||
|
||||
ipcMain.on('toot-action-sound', (_event, _) => {
|
||||
ipcMain.on('toot-action-sound', () => {
|
||||
const preferences = new Preferences(preferencesDBPath)
|
||||
preferences.load()
|
||||
.then((conf) => {
|
||||
if (conf.general.sound.toot) {
|
||||
const sound = path.join(soundBasePath, 'operation_sound02.wav')
|
||||
simplayer(sound, (err) => {
|
||||
simplayer(sound, (err: Error) => {
|
||||
if (err) log.error(err)
|
||||
})
|
||||
}
|
||||
@ -672,7 +695,7 @@ ipcMain.on('toot-action-sound', (_event, _) => {
|
||||
})
|
||||
|
||||
// preferences
|
||||
ipcMain.on('get-preferences', (event, _) => {
|
||||
ipcMain.on('get-preferences', (event: Event) => {
|
||||
const preferences = new Preferences(preferencesDBPath)
|
||||
preferences.load()
|
||||
.then((conf) => {
|
||||
@ -683,7 +706,7 @@ ipcMain.on('get-preferences', (event, _) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('update-preferences', (event, data) => {
|
||||
ipcMain.on('update-preferences', (event: Event, data: any) => {
|
||||
const preferences = new Preferences(preferencesDBPath)
|
||||
preferences.update(data)
|
||||
.then((conf) => {
|
||||
@ -694,7 +717,7 @@ ipcMain.on('update-preferences', (event, data) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('change-collapse', (event, value) => {
|
||||
ipcMain.on('change-collapse', (_event: Event, value: boolean) => {
|
||||
const preferences = new Preferences(preferencesDBPath)
|
||||
preferences.update(
|
||||
{
|
||||
@ -707,7 +730,7 @@ ipcMain.on('change-collapse', (event, value) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('get-collapse', (event, _) => {
|
||||
ipcMain.on('get-collapse', (event: Event) => {
|
||||
const preferences = new Preferences(preferencesDBPath)
|
||||
preferences.load()
|
||||
.then((conf) => {
|
||||
@ -715,7 +738,7 @@ ipcMain.on('get-collapse', (event, _) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('change-global-header', (event, value) => {
|
||||
ipcMain.on('change-global-header', (event: Event, value: boolean) => {
|
||||
const preferences = new Preferences(preferencesDBPath)
|
||||
preferences.update(
|
||||
{
|
||||
@ -731,7 +754,7 @@ ipcMain.on('change-global-header', (event, value) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('get-global-header', (event, _) => {
|
||||
ipcMain.on('get-global-header', (event: Event) => {
|
||||
const preferences = new Preferences(preferencesDBPath)
|
||||
preferences.load()
|
||||
.then((conf) => {
|
||||
@ -739,7 +762,7 @@ ipcMain.on('get-global-header', (event, _) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('change-language', (event, value) => {
|
||||
ipcMain.on('change-language', (event: Event, value: string) => {
|
||||
const preferences = new Preferences(preferencesDBPath)
|
||||
preferences.update(
|
||||
{
|
||||
@ -754,7 +777,7 @@ ipcMain.on('change-language', (event, value) => {
|
||||
})
|
||||
|
||||
// hashtag
|
||||
ipcMain.on('save-hashtag', (event, tag) => {
|
||||
ipcMain.on('save-hashtag', (event: Event, tag: string) => {
|
||||
const hashtags = new Hashtags(hashtagsDB)
|
||||
hashtags.insertTag(tag)
|
||||
.then(() => {
|
||||
@ -765,7 +788,7 @@ ipcMain.on('save-hashtag', (event, tag) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('list-hashtags', (event, _) => {
|
||||
ipcMain.on('list-hashtags', (event: Event) => {
|
||||
const hashtags = new Hashtags(hashtagsDB)
|
||||
hashtags.listTags()
|
||||
.then((tags) => {
|
||||
@ -776,7 +799,7 @@ ipcMain.on('list-hashtags', (event, _) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('remove-hashtag', (event, tag) => {
|
||||
ipcMain.on('remove-hashtag', (event: Event, tag: LocalTag) => {
|
||||
const hashtags = new Hashtags(hashtagsDB)
|
||||
hashtags.removeTag(tag)
|
||||
.then(() => {
|
||||
@ -788,7 +811,7 @@ ipcMain.on('remove-hashtag', (event, tag) => {
|
||||
})
|
||||
|
||||
// Fonts
|
||||
ipcMain.on('list-fonts', (event, _) => {
|
||||
ipcMain.on('list-fonts', (event: Event) => {
|
||||
Fonts()
|
||||
.then(list => {
|
||||
event.sender.send('response-list-fonts', list)
|
||||
@ -799,7 +822,7 @@ ipcMain.on('list-fonts', (event, _) => {
|
||||
})
|
||||
|
||||
// Unread notifications
|
||||
ipcMain.on('get-unread-notification', (event, accountID) => {
|
||||
ipcMain.on('get-unread-notification', (event: Event, accountID: string) => {
|
||||
unreadNotification.findOne({
|
||||
accountID: accountID
|
||||
})
|
||||
@ -812,9 +835,9 @@ ipcMain.on('get-unread-notification', (event, accountID) => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('update-unread-notification', (event, obj) => {
|
||||
const { accountID } = obj
|
||||
unreadNotification.insertOrUpdate(accountID, obj)
|
||||
ipcMain.on('update-unread-notification', (event: Event, config: UnreadNotificationConfig) => {
|
||||
const { accountID } = config
|
||||
unreadNotification.insertOrUpdate(accountID!, config)
|
||||
.then(_ => {
|
||||
event.sender.send('response-update-unread-notification', true)
|
||||
})
|
||||
@ -825,7 +848,7 @@ ipcMain.on('update-unread-notification', (event, obj) => {
|
||||
})
|
||||
|
||||
// Application control
|
||||
ipcMain.on('relaunch', (_event, _) => {
|
||||
ipcMain.on('relaunch', () => {
|
||||
app.relaunch()
|
||||
app.exit()
|
||||
})
|
||||
@ -855,11 +878,11 @@ class EmptyTokenError {}
|
||||
/**
|
||||
* Set application menu
|
||||
*/
|
||||
const ApplicationMenu = (accountsChange, i18n) => {
|
||||
const ApplicationMenu = (accountsChange: Array<MenuItemConstructorOptions>, i18n: i18n.i18n) => {
|
||||
/**
|
||||
* For mac menu
|
||||
*/
|
||||
const macGeneralMenu = process.platform !== 'darwin' ? [] : [
|
||||
const macGeneralMenu: Array<MenuItemConstructorOptions> = process.platform !== 'darwin' ? [] : [
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
@ -885,7 +908,7 @@ const ApplicationMenu = (accountsChange, i18n) => {
|
||||
}
|
||||
]
|
||||
|
||||
const template = [
|
||||
const template: Array<MenuItemConstructorOptions> = [
|
||||
{
|
||||
label: i18n.t('main_menu.application.name'),
|
||||
submenu: [
|
||||
@ -908,7 +931,7 @@ const ApplicationMenu = (accountsChange, i18n) => {
|
||||
label: i18n.t('main_menu.application.preferences'),
|
||||
accelerator: 'CmdOrCtrl+,',
|
||||
click: () => {
|
||||
mainWindow.webContents.send('open-preferences')
|
||||
mainWindow!.webContents.send('open-preferences')
|
||||
}
|
||||
},
|
||||
...macGeneralMenu,
|
||||
@ -929,7 +952,7 @@ const ApplicationMenu = (accountsChange, i18n) => {
|
||||
label: i18n.t('main_menu.toot.new'),
|
||||
accelerator: 'CmdOrCtrl+N',
|
||||
click: () => {
|
||||
mainWindow.webContents.send('CmdOrCtrl+N')
|
||||
mainWindow!.webContents.send('CmdOrCtrl+N')
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -1007,7 +1030,7 @@ const ApplicationMenu = (accountsChange, i18n) => {
|
||||
accelerator: 'CmdOrCtrl+K',
|
||||
enabled: true,
|
||||
click: () => {
|
||||
mainWindow.webContents.send('CmdOrCtrl+K')
|
||||
mainWindow!.webContents.send('CmdOrCtrl+K')
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -1018,7 +1041,7 @@ const ApplicationMenu = (accountsChange, i18n) => {
|
||||
}
|
||||
]
|
||||
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
const menu: Menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(menu)
|
||||
}
|
||||
|
@ -1,88 +0,0 @@
|
||||
import storage from 'electron-json-storage'
|
||||
import objectAssignDeep from 'object-assign-deep'
|
||||
import DisplayStyle from '../constants/displayStyle'
|
||||
import Theme from '../constants/theme'
|
||||
import Language from '../constants/language'
|
||||
import TimeFormat from '../constants/timeFormat'
|
||||
import { LightTheme } from '../renderer/utils/theme'
|
||||
import DefaultFonts from '../renderer/utils/fonts'
|
||||
|
||||
const Base = {
|
||||
general: {
|
||||
sound: {
|
||||
fav_rb: true,
|
||||
toot: true
|
||||
},
|
||||
timeline: {
|
||||
cw: false,
|
||||
nfsw: false,
|
||||
hideAllAttachments: false
|
||||
}
|
||||
},
|
||||
state: {
|
||||
collapse: false,
|
||||
hideGlobalHeader: false
|
||||
},
|
||||
language: {
|
||||
language: Language.en.key
|
||||
},
|
||||
notification: {
|
||||
notify: {
|
||||
reply: true,
|
||||
reblog: true,
|
||||
favourite: true,
|
||||
follow: true
|
||||
}
|
||||
},
|
||||
appearance: {
|
||||
theme: Theme.Light.key,
|
||||
fontSize: 14,
|
||||
displayNameStyle: DisplayStyle.DisplayNameAndUsername.value,
|
||||
timeFormat: TimeFormat.Absolute.value,
|
||||
customThemeColor: LightTheme,
|
||||
font: DefaultFonts[0]
|
||||
}
|
||||
}
|
||||
|
||||
export default class Preferences {
|
||||
constructor (path) {
|
||||
this.path = path
|
||||
this.data = Base
|
||||
}
|
||||
|
||||
async load () {
|
||||
try {
|
||||
const preferences = await this.get()
|
||||
return objectAssignDeep({}, Base, preferences)
|
||||
} catch (err) {
|
||||
return Base
|
||||
}
|
||||
}
|
||||
|
||||
get () {
|
||||
return new Promise((resolve, reject) => {
|
||||
storage.get(this.path, (err, data) => {
|
||||
if (err) return reject(err)
|
||||
this.data = data
|
||||
return resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
save (data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
storage.set(this.path, data, (err) => {
|
||||
if (err) return reject(err)
|
||||
this.data = data
|
||||
return resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async update (obj) {
|
||||
const current = await this.load()
|
||||
const data = objectAssignDeep({}, current, obj)
|
||||
const result = await this.save(data)
|
||||
return result
|
||||
}
|
||||
}
|
130
src/main/preferences.ts
Normal file
130
src/main/preferences.ts
Normal file
@ -0,0 +1,130 @@
|
||||
import storage from 'electron-json-storage'
|
||||
import objectAssignDeep from 'object-assign-deep'
|
||||
import DisplayStyle from '../constants/displayStyle'
|
||||
import Theme from '../constants/theme'
|
||||
import Language from '../constants/language'
|
||||
import TimeFormat from '../constants/timeFormat'
|
||||
import { LightTheme } from '~/src/constants/themeColor'
|
||||
import DefaultFonts from '../renderer/utils/fonts'
|
||||
import { Sound } from '~/src/types/sound'
|
||||
import { Timeline } from '~/src/types/timeline'
|
||||
import { Notify } from '~/src/types/notify'
|
||||
import { Appearance } from '~/src/types/appearance'
|
||||
import { Language as LanguageSet } from '~/src/types/language'
|
||||
|
||||
type General = {
|
||||
sound: Sound,
|
||||
timeline: Timeline
|
||||
}
|
||||
|
||||
type State = {
|
||||
collapse: boolean,
|
||||
hideGlobalHeader: boolean
|
||||
}
|
||||
|
||||
type Notification = {
|
||||
notify: Notify
|
||||
}
|
||||
|
||||
type BaseConfig = {
|
||||
general: General,
|
||||
state: State,
|
||||
language: LanguageSet,
|
||||
notification: Notification,
|
||||
appearance: Appearance
|
||||
}
|
||||
|
||||
const sound: Sound = {
|
||||
fav_rb: true,
|
||||
toot: true
|
||||
}
|
||||
|
||||
const timeline: Timeline = {
|
||||
cw: false,
|
||||
nfsw: false,
|
||||
hideAllAttachments: false
|
||||
}
|
||||
|
||||
const general: General = {
|
||||
sound: sound,
|
||||
timeline: timeline
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
collapse: false,
|
||||
hideGlobalHeader: false
|
||||
}
|
||||
|
||||
const notify: Notify = {
|
||||
reply: true,
|
||||
reblog: true,
|
||||
favourite: true,
|
||||
follow: true
|
||||
}
|
||||
|
||||
const language: LanguageSet = {
|
||||
language: Language.en.key
|
||||
}
|
||||
|
||||
const notification: Notification = {
|
||||
notify: notify
|
||||
}
|
||||
|
||||
const appearance: Appearance = {
|
||||
theme: Theme.Light.key,
|
||||
fontSize: 14,
|
||||
displayNameStyle: DisplayStyle.DisplayNameAndUsername.value,
|
||||
timeFormat: TimeFormat.Absolute.value,
|
||||
customThemeColor: LightTheme,
|
||||
font: DefaultFonts[0]
|
||||
}
|
||||
|
||||
const Base: BaseConfig = {
|
||||
general: general,
|
||||
state: state,
|
||||
language: language,
|
||||
notification: notification,
|
||||
appearance: appearance
|
||||
}
|
||||
|
||||
export default class Preferences {
|
||||
private path: string
|
||||
|
||||
constructor (path: string) {
|
||||
this.path = path
|
||||
}
|
||||
|
||||
async load (): Promise<BaseConfig> {
|
||||
try {
|
||||
const preferences = await this.get()
|
||||
return objectAssignDeep({}, Base, preferences)
|
||||
} catch (err) {
|
||||
return Base
|
||||
}
|
||||
}
|
||||
|
||||
get (): Promise<BaseConfig> {
|
||||
return new Promise((resolve, reject) => {
|
||||
storage.get(this.path, (err, data) => {
|
||||
if (err) return reject(err)
|
||||
return resolve(data as BaseConfig)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
save (data: BaseConfig): Promise<BaseConfig> {
|
||||
return new Promise((resolve, reject) => {
|
||||
storage.set(this.path, data, (err) => {
|
||||
if (err) return reject(err)
|
||||
return resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async update (obj: any): Promise<BaseConfig> {
|
||||
const current = await this.load()
|
||||
const data = objectAssignDeep({}, current, obj)
|
||||
const result = await this.save(data)
|
||||
return result
|
||||
}
|
||||
}
|
@ -1,51 +1,54 @@
|
||||
import Mastodon from 'megalodon'
|
||||
import Mastodon, { StreamListener, Status, Notification } from 'megalodon'
|
||||
import log from 'electron-log'
|
||||
import LocalAccount from '~/src/types/localAccount'
|
||||
|
||||
export default class Streaming {
|
||||
constructor (account) {
|
||||
this.account = account
|
||||
private client: Mastodon
|
||||
private listener: StreamListener | null
|
||||
|
||||
constructor (account: LocalAccount) {
|
||||
this.client = new Mastodon(
|
||||
account.accessToken,
|
||||
account.accessToken!,
|
||||
account.baseURL + '/api/v1'
|
||||
)
|
||||
this.listener = null
|
||||
}
|
||||
|
||||
startUserStreaming (updateCallback, notificationCallback, errCallback) {
|
||||
startUserStreaming (updateCallback: Function, notificationCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.stream('/streaming/user')
|
||||
|
||||
this.listener.on('connect', _ => {
|
||||
log.info('/streaming/user started')
|
||||
})
|
||||
|
||||
this.listener.on('update', (status) => {
|
||||
this.listener.on('update', (status: Status) => {
|
||||
updateCallback(status)
|
||||
})
|
||||
|
||||
this.listener.on('notification', (notification) => {
|
||||
this.listener.on('notification', (notification: Notification) => {
|
||||
notificationCallback(notification)
|
||||
})
|
||||
|
||||
this.listener.on('error', (err) => {
|
||||
this.listener.on('error', (err: Error) => {
|
||||
errCallback(err)
|
||||
})
|
||||
|
||||
this.listener.on('connection-limit-exceeded', err => {
|
||||
this.listener.on('connection-limit-exceeded', (err: Error) => {
|
||||
errCallback(err)
|
||||
})
|
||||
}
|
||||
|
||||
start (path, updateCallback, errCallback) {
|
||||
start (path: string, updateCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.stream(path)
|
||||
this.listener.on('connect', _ => {
|
||||
log.info(`${path} started`)
|
||||
})
|
||||
|
||||
this.listener.on('update', (status) => {
|
||||
this.listener.on('update', (status: Status) => {
|
||||
updateCallback(status)
|
||||
})
|
||||
|
||||
this.listener.on('error', (err) => {
|
||||
this.listener.on('error', (err: Error) => {
|
||||
errCallback(err)
|
||||
})
|
||||
|
||||
@ -61,10 +64,10 @@ export default class Streaming {
|
||||
this.listener.removeAllListeners('notification')
|
||||
this.listener.removeAllListeners('error')
|
||||
this.listener.removeAllListeners('parser-error')
|
||||
this.listener.on('error', (e) => {
|
||||
this.listener.on('error', (e: Error) => {
|
||||
log.error(e)
|
||||
})
|
||||
this.listener.on('parser-error', (e) => {
|
||||
this.listener.on('parser-error', (e: Error) => {
|
||||
log.error(e)
|
||||
})
|
||||
this.listener.stop()
|
@ -1,15 +1,19 @@
|
||||
import Streaming from './streaming'
|
||||
import WebSocket from './websocket'
|
||||
import LocalAccount from '~src/types/localAccount'
|
||||
|
||||
export default class StreamingManager {
|
||||
constructor (account, useWebsocket = false) {
|
||||
this.account = account
|
||||
private streaming: Streaming
|
||||
private websocket: WebSocket
|
||||
private useWebsocket: boolean
|
||||
|
||||
constructor (account: LocalAccount, useWebsocket = false) {
|
||||
this.streaming = new Streaming(account)
|
||||
this.websocket = new WebSocket(account)
|
||||
this.useWebsocket = useWebsocket
|
||||
}
|
||||
|
||||
startUser (updateCallback, notificationCallback, errCallback) {
|
||||
startUser (updateCallback: Function, notificationCallback: Function, errCallback: Function) {
|
||||
if (this.useWebsocket) {
|
||||
this._startUserSocket(updateCallback, notificationCallback, errCallback)
|
||||
} else {
|
||||
@ -17,7 +21,7 @@ export default class StreamingManager {
|
||||
}
|
||||
}
|
||||
|
||||
start (path, params, updateCallback, errCallback) {
|
||||
start (path: string, params: string, updateCallback: Function, errCallback: Function) {
|
||||
if (this.useWebsocket) {
|
||||
this._startSocket(path, params, updateCallback, errCallback)
|
||||
} else {
|
||||
@ -33,11 +37,11 @@ export default class StreamingManager {
|
||||
/**
|
||||
* Using streaming for Mastodon
|
||||
*/
|
||||
_startUserStreaming (updateCallback, notificationCallback, errCallback) {
|
||||
_startUserStreaming (updateCallback: Function, notificationCallback: Function, errCallback: Function) {
|
||||
this.streaming.startUserStreaming(updateCallback, notificationCallback, errCallback)
|
||||
}
|
||||
|
||||
_startStreaming (path, params, updateCallback, errCallback) {
|
||||
_startStreaming (path: string, params: string, updateCallback: Function, errCallback: Function) {
|
||||
const target = `/streaming/${path}?${params}`
|
||||
this.streaming.start(
|
||||
target,
|
||||
@ -53,11 +57,11 @@ export default class StreamingManager {
|
||||
/**
|
||||
* Using websocket for Pleroma
|
||||
*/
|
||||
_startUserSocket (updateCallback, notificationCallback, errCallback) {
|
||||
_startUserSocket (updateCallback: Function, notificationCallback: Function, errCallback: Function) {
|
||||
this.websocket.startUserStreaming(updateCallback, notificationCallback, errCallback)
|
||||
}
|
||||
|
||||
_startSocket (path, params, updateCallback, errCallback) {
|
||||
_startSocket (path: string, params: string, updateCallback: Function, errCallback: Function) {
|
||||
let stream = path
|
||||
if (stream === 'public/local') {
|
||||
stream = 'public:local'
|
@ -1,8 +1,11 @@
|
||||
import empty from 'is-empty'
|
||||
import { isEmpty } from 'lodash'
|
||||
import Datastore from 'nedb'
|
||||
import { UnreadNotification as Config } from '~/src/types/unreadNotification'
|
||||
|
||||
export default class UnreadNotification {
|
||||
constructor (path) {
|
||||
private db: Datastore
|
||||
|
||||
constructor (path: string) {
|
||||
this.db = new Datastore({
|
||||
filename: path,
|
||||
autoload: true
|
||||
@ -21,19 +24,19 @@ export default class UnreadNotification {
|
||||
// Add unique index.
|
||||
this.db.ensureIndex({ fieldName: 'accountID', unique: true, sparse: true }, (err) => {
|
||||
if (err) reject(err)
|
||||
resolve(null)
|
||||
resolve({})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
insertOrUpdate (accountID, obj) {
|
||||
insertOrUpdate (accountID: string, config: Config): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.update(
|
||||
{
|
||||
accountID: accountID
|
||||
},
|
||||
obj,
|
||||
config,
|
||||
{
|
||||
upsert: true
|
||||
},
|
||||
@ -44,20 +47,15 @@ export default class UnreadNotification {
|
||||
})
|
||||
}
|
||||
|
||||
findOne (obj) {
|
||||
findOne (obj: any): Promise<Config> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.findOne(obj, (err, doc) => {
|
||||
this.db.findOne<Config>(obj, (err, doc) => {
|
||||
if (err) return reject(err)
|
||||
if (empty(doc)) return reject(new EmptyRecordError('empty'))
|
||||
if (isEmpty(doc)) return reject(new EmptyRecordError('empty'))
|
||||
resolve(doc)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class EmptyRecordError extends Error {
|
||||
constructor (msg) {
|
||||
super(msg)
|
||||
this.name = 'EmptyRecordError'
|
||||
}
|
||||
}
|
||||
class EmptyRecordError extends Error {}
|
@ -1,37 +1,40 @@
|
||||
import Mastodon from 'megalodon'
|
||||
import Mastodon, { WebSocket as SocketListener, Status, Notification } from 'megalodon'
|
||||
import log from 'electron-log'
|
||||
import LocalAccount from '~src/types/localAccount'
|
||||
|
||||
export default class WebSocket {
|
||||
constructor (account) {
|
||||
this.account = account
|
||||
private client: Mastodon
|
||||
private listener: SocketListener | null
|
||||
|
||||
constructor (account: LocalAccount) {
|
||||
const url = account.baseURL.replace(/^https:\/\//, 'wss://')
|
||||
this.client = new Mastodon(
|
||||
account.accessToken,
|
||||
account.accessToken!,
|
||||
url + '/api/v1'
|
||||
)
|
||||
this.listener = null
|
||||
}
|
||||
|
||||
startUserStreaming (updateCallback, notificationCallback, errCallback) {
|
||||
startUserStreaming (updateCallback: Function, notificationCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.socket('/streaming', 'user')
|
||||
|
||||
this.listener.on('connect', _ => {
|
||||
log.info('/streaming/?stream=user started')
|
||||
})
|
||||
|
||||
this.listener.on('update', (status) => {
|
||||
this.listener.on('update', (status: Status) => {
|
||||
updateCallback(status)
|
||||
})
|
||||
|
||||
this.listener.on('notification', (notification) => {
|
||||
this.listener.on('notification', (notification: Notification) => {
|
||||
notificationCallback(notification)
|
||||
})
|
||||
|
||||
this.listener.on('error', (err) => {
|
||||
this.listener.on('error', (err: Error) => {
|
||||
errCallback(err)
|
||||
})
|
||||
|
||||
this.listener.on('parser-error', (err) => {
|
||||
this.listener.on('parser-error', (err: Error) => {
|
||||
errCallback(err)
|
||||
})
|
||||
}
|
||||
@ -46,21 +49,21 @@ export default class WebSocket {
|
||||
* When hashtag timeline, the path is `hashtag&tag=tag_name`.
|
||||
* When list timeline, the path is `list&list=list_id`.
|
||||
*/
|
||||
start (stream, updateCallback, errCallback) {
|
||||
start (stream: string, updateCallback: Function, errCallback: Function) {
|
||||
this.listener = this.client.socket('/streaming', stream)
|
||||
this.listener.on('connect', _ => {
|
||||
log.info(`/streaming/?stream=${stream} started`)
|
||||
})
|
||||
|
||||
this.listener.on('update', status => {
|
||||
this.listener.on('update', (status: Status) => {
|
||||
updateCallback(status)
|
||||
})
|
||||
|
||||
this.listener.on('error', (err) => {
|
||||
this.listener.on('error', (err: Error) => {
|
||||
errCallback(err)
|
||||
})
|
||||
|
||||
this.listener.on('parser-error', (err) => {
|
||||
this.listener.on('parser-error', (err: Error) => {
|
||||
errCallback(err)
|
||||
})
|
||||
}
|
||||
@ -72,10 +75,10 @@ export default class WebSocket {
|
||||
this.listener.removeAllListeners('notification')
|
||||
this.listener.removeAllListeners('error')
|
||||
this.listener.removeAllListeners('parser-error')
|
||||
this.listener.on('error', (e) => {
|
||||
this.listener.on('error', (e: Error) => {
|
||||
log.error(e)
|
||||
})
|
||||
this.listener.on('parser-error', (e) => {
|
||||
this.listener.on('parser-error', (e: Error) => {
|
||||
log.error(e)
|
||||
})
|
||||
this.listener.stop()
|
@ -1,7 +1,7 @@
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { MutationTree, ActionTree, Module } from 'vuex'
|
||||
import router from '@/router'
|
||||
import { LightTheme, DarkTheme, SolarizedLightTheme, SolarizedDarkTheme, KimbieDarkTheme, ThemeType } from '@/utils/theme'
|
||||
import { LightTheme, DarkTheme, SolarizedLightTheme, SolarizedDarkTheme, KimbieDarkTheme, ThemeColorType } from '~/src/constants/themeColor'
|
||||
import DisplayStyle from '~/src/constants/displayStyle'
|
||||
import Theme from '~/src/constants/theme'
|
||||
import TimeFormat from '~/src/constants/timeFormat'
|
||||
@ -11,7 +11,7 @@ import { RootState } from '@/store'
|
||||
import { Notify } from '~/src/types/notify'
|
||||
|
||||
export interface AppState {
|
||||
theme: ThemeType,
|
||||
theme: ThemeColorType,
|
||||
fontSize: number,
|
||||
displayNameStyle: number,
|
||||
notify: Notify,
|
||||
|
@ -2,22 +2,14 @@ import { ipcRenderer } from 'electron'
|
||||
import DisplayStyle from '~/src/constants/displayStyle'
|
||||
import Theme from '~/src/constants/theme'
|
||||
import TimeFormat from '~/src/constants/timeFormat'
|
||||
import { LightTheme, ThemeType } from '@/utils/theme'
|
||||
import { LightTheme, ThemeColorType } from '~/src/constants/themeColor'
|
||||
import DefaultFonts from '@/utils/fonts'
|
||||
import { Module, MutationTree, ActionTree } from 'vuex'
|
||||
import { RootState } from '@/store'
|
||||
|
||||
interface AppearanceSet {
|
||||
theme: string,
|
||||
fontSize: number,
|
||||
displayNameStyle: number,
|
||||
timeFormat: number,
|
||||
customThemeColor: ThemeType,
|
||||
font: string
|
||||
}
|
||||
import { Appearance } from '~/src/types/appearance'
|
||||
|
||||
export interface AppearanceState {
|
||||
appearance: AppearanceSet,
|
||||
appearance: Appearance,
|
||||
fonts: Array<string>
|
||||
}
|
||||
|
||||
@ -39,7 +31,7 @@ export const MUTATION_TYPES = {
|
||||
}
|
||||
|
||||
const mutations: MutationTree<AppearanceState> = {
|
||||
[MUTATION_TYPES.UPDATE_APPEARANCE]: (state, conf: AppearanceSet) => {
|
||||
[MUTATION_TYPES.UPDATE_APPEARANCE]: (state, conf: Appearance) => {
|
||||
state.appearance = conf
|
||||
},
|
||||
[MUTATION_TYPES.UPDATE_FONTS]: (state, fonts: Array<string>) => {
|
||||
@ -57,7 +49,7 @@ const actions: ActionTree<AppearanceState, RootState> = {
|
||||
})
|
||||
ipcRenderer.once('response-get-preferences', (_, conf: any) => {
|
||||
ipcRenderer.removeAllListeners('error-get-preferences')
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as AppearanceSet)
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as Appearance)
|
||||
resolve(conf)
|
||||
})
|
||||
})
|
||||
@ -77,7 +69,7 @@ const actions: ActionTree<AppearanceState, RootState> = {
|
||||
})
|
||||
},
|
||||
updateTheme: ({ dispatch, commit, state }, themeKey: string) => {
|
||||
const newAppearance: AppearanceSet = Object.assign({}, state.appearance, {
|
||||
const newAppearance: Appearance = Object.assign({}, state.appearance, {
|
||||
theme: themeKey
|
||||
})
|
||||
const config = {
|
||||
@ -91,14 +83,14 @@ const actions: ActionTree<AppearanceState, RootState> = {
|
||||
})
|
||||
ipcRenderer.once('response-update-preferences', (_, conf: any) => {
|
||||
ipcRenderer.removeAllListeners('error-update-preferences')
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as AppearanceSet)
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as Appearance)
|
||||
dispatch('App/loadPreferences', null, { root: true })
|
||||
resolve(conf.appearance)
|
||||
})
|
||||
})
|
||||
},
|
||||
updateFontSize: ({ dispatch, commit, state }, fontSize: number) => {
|
||||
const newAppearance: AppearanceSet = Object.assign({}, state.appearance, {
|
||||
const newAppearance: Appearance = Object.assign({}, state.appearance, {
|
||||
fontSize: fontSize
|
||||
})
|
||||
const config = {
|
||||
@ -112,14 +104,14 @@ const actions: ActionTree<AppearanceState, RootState> = {
|
||||
})
|
||||
ipcRenderer.once('response-update-preferences', (_, conf: any) => {
|
||||
ipcRenderer.removeAllListeners('error-update-preferences')
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as AppearanceSet)
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as Appearance)
|
||||
dispatch('App/loadPreferences', null, { root: true })
|
||||
resolve(conf.appearance)
|
||||
})
|
||||
})
|
||||
},
|
||||
updateDisplayNameStyle: ({ dispatch, commit, state }, value: number) => {
|
||||
const newAppearance: AppearanceSet = Object.assign({}, state.appearance, {
|
||||
const newAppearance: Appearance = Object.assign({}, state.appearance, {
|
||||
displayNameStyle: value
|
||||
})
|
||||
const config = {
|
||||
@ -134,13 +126,13 @@ const actions: ActionTree<AppearanceState, RootState> = {
|
||||
ipcRenderer.once('response-update-preferences', (_, conf: any) => {
|
||||
ipcRenderer.removeAllListeners('error-update-preferences')
|
||||
dispatch('App/loadPreferences', null, { root: true })
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as AppearanceSet)
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as Appearance)
|
||||
resolve(conf.appearance)
|
||||
})
|
||||
})
|
||||
},
|
||||
updateTimeFormat: ({ dispatch, commit, state }, value: number) => {
|
||||
const newAppearance: AppearanceSet = Object.assign({}, state.appearance, {
|
||||
const newAppearance: Appearance = Object.assign({}, state.appearance, {
|
||||
timeFormat: value
|
||||
})
|
||||
const config = {
|
||||
@ -155,14 +147,14 @@ const actions: ActionTree<AppearanceState, RootState> = {
|
||||
ipcRenderer.once('response-update-preferences', (_, conf: any) => {
|
||||
ipcRenderer.removeAllListeners('error-update-preferences')
|
||||
dispatch('App/loadPreferences', null, { root: true })
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as AppearanceSet)
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as Appearance)
|
||||
resolve(conf.appearance)
|
||||
})
|
||||
})
|
||||
},
|
||||
updateCustomThemeColor: ({ dispatch, state, commit }, value: object) => {
|
||||
const newCustom: ThemeType = Object.assign({}, state.appearance.customThemeColor, value)
|
||||
const newAppearance: AppearanceSet = Object.assign({}, state.appearance, {
|
||||
const newCustom: ThemeColorType = Object.assign({}, state.appearance.customThemeColor, value)
|
||||
const newAppearance: Appearance = Object.assign({}, state.appearance, {
|
||||
customThemeColor: newCustom
|
||||
})
|
||||
const config = {
|
||||
@ -176,14 +168,14 @@ const actions: ActionTree<AppearanceState, RootState> = {
|
||||
})
|
||||
ipcRenderer.once('response-update-preferences', (_, conf: any) => {
|
||||
ipcRenderer.removeAllListeners('error-update-preferences')
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as AppearanceSet)
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as Appearance)
|
||||
dispatch('App/loadPreferences', null, { root: true })
|
||||
resolve(conf.appearance)
|
||||
})
|
||||
})
|
||||
},
|
||||
updateFont: ({ dispatch, state, commit }, value: string) => {
|
||||
const newAppearance: AppearanceSet = Object.assign({}, state.appearance, {
|
||||
const newAppearance: Appearance = Object.assign({}, state.appearance, {
|
||||
font: value
|
||||
})
|
||||
const config = {
|
||||
@ -197,7 +189,7 @@ const actions: ActionTree<AppearanceState, RootState> = {
|
||||
})
|
||||
ipcRenderer.once('response-update-preferences', (_, conf: any) => {
|
||||
ipcRenderer.removeAllListeners('error-update-preferences')
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as AppearanceSet)
|
||||
commit(MUTATION_TYPES.UPDATE_APPEARANCE, conf.appearance as Appearance)
|
||||
dispatch('App/loadPreferences', null, { root: true })
|
||||
resolve(conf.appearance)
|
||||
})
|
||||
@ -205,11 +197,9 @@ const actions: ActionTree<AppearanceState, RootState> = {
|
||||
}
|
||||
}
|
||||
|
||||
const Appearance: Module<AppearanceState, RootState> = {
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: state,
|
||||
mutations: mutations,
|
||||
actions: actions
|
||||
}
|
||||
|
||||
export default Appearance
|
||||
} as Module<AppearanceState, RootState>
|
||||
|
@ -2,10 +2,7 @@ import { ipcRenderer } from 'electron'
|
||||
import Language from '~/src/constants/language'
|
||||
import { Module, MutationTree, ActionTree } from 'vuex'
|
||||
import { RootState } from '@/store'
|
||||
|
||||
interface LanguageSet {
|
||||
language: string
|
||||
}
|
||||
import { Language as LanguageSet } from '~/src/types/language'
|
||||
|
||||
export interface LanguageState {
|
||||
language: LanguageSet
|
||||
|
@ -47,8 +47,8 @@ const actions: ActionTree<TimelineState, RootState> = {
|
||||
ipcRenderer.send('get-unread-notification', rootState.Settings.accountID)
|
||||
})
|
||||
},
|
||||
changeUnreadNotification: ({ dispatch, state, rootState }, timeline: object): Promise<boolean> => {
|
||||
const settings = Object.assign({}, state.unreadNotification, timeline, {
|
||||
changeUnreadNotification: ({ dispatch, state, rootState }, timeline: any): Promise<boolean> => {
|
||||
const settings: UnreadNotification = Object.assign({}, state.unreadNotification, timeline, {
|
||||
accountID: rootState.Settings.accountID
|
||||
})
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { ipcRenderer } from 'electron'
|
||||
import Hashtag from '~/src/types/hashtag'
|
||||
import LocalTag from '~/src/types/localTag'
|
||||
import { Module, MutationTree, ActionTree } from 'vuex'
|
||||
import { RootState } from '@/store'
|
||||
|
||||
export interface ListState {
|
||||
tags: Array<Hashtag>
|
||||
tags: Array<LocalTag>
|
||||
}
|
||||
|
||||
const state = (): ListState => ({
|
||||
@ -16,7 +16,7 @@ export const MUTATION_TYPES = {
|
||||
}
|
||||
|
||||
const mutations: MutationTree<ListState> = {
|
||||
[MUTATION_TYPES.UPDATE_TAGS]: (state, tags: Array<Hashtag>) => {
|
||||
[MUTATION_TYPES.UPDATE_TAGS]: (state, tags: Array<LocalTag>) => {
|
||||
state.tags = tags
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,7 @@ const mutations: MutationTree<ListState> = {
|
||||
const actions: ActionTree<ListState, RootState> = {
|
||||
listTags: ({ commit }) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
ipcRenderer.once('response-list-hashtags', (_, tags: Array<Hashtag>) => {
|
||||
ipcRenderer.once('response-list-hashtags', (_, tags: Array<LocalTag>) => {
|
||||
ipcRenderer.removeAllListeners('error-list-hashtags')
|
||||
commit(MUTATION_TYPES.UPDATE_TAGS, tags)
|
||||
resolve(tags)
|
||||
@ -36,7 +36,7 @@ const actions: ActionTree<ListState, RootState> = {
|
||||
ipcRenderer.send('list-hashtags')
|
||||
})
|
||||
},
|
||||
removeTag: ({ dispatch }, tag: Hashtag) => {
|
||||
removeTag: ({ dispatch }, tag: LocalTag) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
ipcRenderer.once('response-remove-hashtag', () => {
|
||||
ipcRenderer.removeAllListeners('error-remove-hashtag')
|
||||
|
@ -2,7 +2,7 @@ import router from '@/router'
|
||||
import i18n from '~/src/config/i18n'
|
||||
import { Module, MutationTree, ActionTree } from 'vuex'
|
||||
import { List } from 'megalodon'
|
||||
import Hashtag from '~/src/types/hashtag'
|
||||
import LocalTag from '~/src/types/localTag'
|
||||
import { RootState } from '@/store'
|
||||
|
||||
export interface Channel {
|
||||
@ -95,7 +95,7 @@ const mutations: MutationTree<JumpState> = {
|
||||
return channel
|
||||
})
|
||||
},
|
||||
[MUTATION_TYPES.UPDATE_TAG_CHANNEL]: (state, tags: Array<Hashtag>) => {
|
||||
[MUTATION_TYPES.UPDATE_TAG_CHANNEL]: (state, tags: Array<LocalTag>) => {
|
||||
state.tagChannelList = tags.map(t => {
|
||||
const channel: Channel = {
|
||||
name: `#${t.tagName}`,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Mastodon, { List, Response } from 'megalodon'
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { Module, MutationTree, ActionTree } from 'vuex'
|
||||
import Hashtag from '~/src/types/hashtag'
|
||||
import LocalTag from '~/src/types/localTag'
|
||||
import LocalAccount from '~/src/types/localAccount'
|
||||
import { RootState } from '@/store'
|
||||
|
||||
@ -13,7 +13,7 @@ export interface SideMenuState {
|
||||
unreadDirectMessagesTimeline: boolean,
|
||||
unreadPublicTimeline: boolean,
|
||||
lists: Array<List>,
|
||||
tags: Array<Hashtag>,
|
||||
tags: Array<LocalTag>,
|
||||
collapse: boolean
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ const mutations: MutationTree<SideMenuState> = {
|
||||
[MUTATION_TYPES.CHANGE_COLLAPSE]: (state, collapse: boolean) => {
|
||||
state.collapse = collapse
|
||||
},
|
||||
[MUTATION_TYPES.UPDATE_TAGS]: (state, tags: Array<Hashtag>) => {
|
||||
[MUTATION_TYPES.UPDATE_TAGS]: (state, tags: Array<LocalTag>) => {
|
||||
state.tags = tags
|
||||
}
|
||||
}
|
||||
@ -105,7 +105,7 @@ const actions: ActionTree<SideMenuState, RootState> = {
|
||||
},
|
||||
listTags: ({ commit }) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
ipcRenderer.once('response-list-hashtags', (_, tags: Array<Hashtag>) => {
|
||||
ipcRenderer.once('response-list-hashtags', (_, tags: Array<LocalTag>) => {
|
||||
ipcRenderer.removeAllListeners('error-list-hashtags')
|
||||
commit(MUTATION_TYPES.UPDATE_TAGS, tags)
|
||||
resolve(tags)
|
||||
|
10
src/types/appearance.ts
Normal file
10
src/types/appearance.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { ThemeColorType } from '~/src/constants/themeColor'
|
||||
|
||||
export type Appearance = {
|
||||
theme: string,
|
||||
fontSize: number,
|
||||
displayNameStyle: number,
|
||||
timeFormat: number,
|
||||
customThemeColor: ThemeColorType,
|
||||
font: string
|
||||
}
|
3
src/types/language.ts
Normal file
3
src/types/language.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export type Language = {
|
||||
language: string
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
export default interface Hasthag {
|
||||
export default interface LocalTag {
|
||||
tagName: string,
|
||||
_id?: string
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
export type UnreadNotification = {
|
||||
accountID?: string,
|
||||
direct: boolean,
|
||||
local: boolean,
|
||||
public: boolean
|
||||
|
1
types/element-ui.d.ts
vendored
1
types/element-ui.d.ts
vendored
@ -1,2 +1 @@
|
||||
declare module 'element-ui'
|
||||
declare module 'element-ui/lib/locale/lang/en'
|
||||
|
Loading…
x
Reference in New Issue
Block a user