This commit is contained in:
Canorus 2018-09-02 14:00:08 +09:00
commit 383b60cdb4
30 changed files with 582 additions and 83 deletions

View File

@ -2,7 +2,7 @@ version: 2
jobs:
build:
docker:
- image: node:9-slim
- image: node:10-slim
working_directory: /var/opt/app
steps:
- checkout

View File

@ -2,11 +2,68 @@
## [Unreleased]
### Added
- [#586](https://github.com/h3poteto/whalebird-desktop/pull/586) Switch notification in preferences
- [#583](https://github.com/h3poteto/whalebird-desktop/pull/583) Suggest native emoji in New Toot modal
- [#576](https://github.com/h3poteto/whalebird-desktop/pull/576) Add shortcut keys to read image and contents warning
### Changed
- [#585](https://github.com/h3poteto/whalebird-desktop/pull/585) Update packages for node 10.x
- [#584](https://github.com/h3poteto/whalebird-desktop/pull/584) Update electron version to 2.0.8
- [#580](https://github.com/h3poteto/whalebird-desktop/pull/580) Update Korean localization
- [#573](https://github.com/h3poteto/whalebird-desktop/pull/573) Update shortcut description
### Fixed
- [#588](https://github.com/h3poteto/whalebird-desktop/pull/588) Fix closing image modal using esc
- [#587](https://github.com/h3poteto/whalebird-desktop/pull/587) Fix closing sidebar when overlaid
- [#575](https://github.com/h3poteto/whalebird-desktop/pull/575) New Korean localization
## [2.1.2] - 2018-08-27
### Added
- [#562](https://github.com/h3poteto/whalebird-desktop/pull/562) Add shortcut help modal
- [#557](https://github.com/h3poteto/whalebird-desktop/pull/557) Add shortcut keys to control toot
- [#552](https://github.com/h3poteto/whalebird-desktop/pull/552) Set shortcut keys to move toot on timeline
- [#547](https://github.com/h3poteto/whalebird-desktop/pull/547) Add title to display description when hover icon
### Changed
- [#571](https://github.com/h3poteto/whalebird-desktop/pull/571) Add donate link and QR code in README
- [#565](https://github.com/h3poteto/whalebird-desktop/pull/565) Close preference page with esc
- [#559](https://github.com/h3poteto/whalebird-desktop/pull/559) Add description of shortcut in README
### Fixed
- [#570](https://github.com/h3poteto/whalebird-desktop/pull/570) Fix reply visibility level
- [#566](https://github.com/h3poteto/whalebird-desktop/pull/566) Fix shortcut events
- [#560](https://github.com/h3poteto/whalebird-desktop/pull/560) Set active tab to first when close preferences
- [#556](https://github.com/h3poteto/whalebird-desktop/pull/556) Update Korean localization
## [2.1.1] - 2018-08-21
### Added
- [#534](https://github.com/h3poteto/whalebird-desktop/pull/534) Add Korean localization
- [#532](https://github.com/h3poteto/whalebird-desktop/pull/532) Support clipboard picture
- [#528](https://github.com/h3poteto/whalebird-desktop/pull/528) Add Polish translation
### Fixed
- [#546](https://github.com/h3poteto/whalebird-desktop/pull/546) Fix username to include domain when the user is another instance
- [#545](https://github.com/h3poteto/whalebird-desktop/pull/545) Fix boost icon when the toot is direct
- [#544](https://github.com/h3poteto/whalebird-desktop/pull/544) Fix domain validation for short domain
- [#539](https://github.com/h3poteto/whalebird-desktop/pull/539) Focus on new toot modal after change account
- [#538](https://github.com/h3poteto/whalebird-desktop/pull/538) Jump only modal is opened
- [#535](https://github.com/h3poteto/whalebird-desktop/pull/535) Fix typo in README.md
- [#529](https://github.com/h3poteto/whalebird-desktop/pull/529) Fix some minor typos
## [2.1.0] - 2018-08-20
### Added
- [#519](https://github.com/h3poteto/whalebird-desktop/pull/519) Suggest custom emojis in new toot
- [#516](https://github.com/h3poteto/whalebird-desktop/pull/516) Parse emoji and show emoji in toot
- [#514](https://github.com/h3poteto/whalebird-desktop/pull/514) Add description how to add language in README
- [#513](https://github.com/h3poteto/whalebird-desktop/pull/513) Add show profile menu
### Fixed
- [#524](https://github.com/h3poteto/whalebird-desktop/pull/524) Fix space in notifications
- [#523](https://github.com/h3poteto/whalebird-desktop/pull/523) Control CW, NSFW, and emoji in notification
## [2.0.1] - 2018-08-18
### Added

View File

@ -1,5 +1,5 @@
# Whalebird
[![CircleCI](https://img.shields.io/circleci/project/github/h3poteto/whalebird-desktop.svg?style=flat-square)](https://circleci.com/gh/h3poteto/whalebird-desktop)
[![CircleCI](https://circleci.com/gh/h3poteto/whalebird-desktop.svg?style=svg)](https://circleci.com/gh/h3poteto/whalebird-desktop)
[![GitHub release](http://img.shields.io/github/release/h3poteto/whalebird-desktop.svg?style=flat-square)](https://github.com/h3poteto/whalebird-desktop/releases)
[![App Store](https://img.shields.io/itunes/v/1378283354.svg?style=flat-square)](https://itunes.apple.com/us/app/whalebird/id1378283354)
@ -77,7 +77,7 @@ We'd love you to contribute to Whalebird.
### Minimum requirements for development
* Node.js greater than or equal version 8.9.0
* Node.js greater than or equal version 8.9.0 (10.x is recommended)
* npm or yarn
### Getting started

13
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "Whalebird",
"version": "2.1.2",
"version": "2.2.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -4865,9 +4865,9 @@
"dev": true
},
"electron": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/electron/-/electron-2.0.7.tgz",
"integrity": "sha512-MRrDE6mrp+ZrIBpZM27pxbO2yEDKYfkmc6Ll79BtedMNEZsY4+oblupeDJL6RM6meUIp82KMo63W7fP65Tb89Q==",
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/electron/-/electron-2.0.8.tgz",
"integrity": "sha512-pbeGFbwijb5V3Xy/KMcwIp59eA9igg2br+7EHbbwQoa3HRDF5JjTrciX7OiscCA52+ze2n4q38S4lXPqRitgIA==",
"dev": true,
"requires": {
"@types/node": "8.10.21",
@ -5309,6 +5309,11 @@
"minimalistic-crypto-utils": "1.0.1"
}
},
"emojilib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.3.0.tgz",
"integrity": "sha512-gDrDiITC7W5lvXTtUmk0k9soizsjfY9Wqr2GWsEMX7+cKChoxLt3RnT8zW32BvN1SFDQbi7+D5/+HNu/R+qvKA=="
},
"emojis-list": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",

View File

@ -1,6 +1,6 @@
{
"name": "Whalebird",
"version": "2.1.2",
"version": "2.2.0",
"author": "AkiraFukushima <h3.poteto@gmail.com>",
"description": "An Electron based Mastodon client for Windows, Mac and Linux",
"license": "MIT",
@ -15,8 +15,8 @@
"url": "https://github.com/h3poteto/whalebird-desktop.git"
},
"config": {
"buildVersion": "43",
"appVersion": "2.1.2"
"buildVersion": "44",
"appVersion": "2.2.0"
},
"main": "./dist/electron/main.js",
"scripts": {
@ -27,7 +27,7 @@
"build:mac": "node .electron-vue/build.js && electron-builder --mac --x64",
"build:linux": "node .electron-vue/build.js && electron-builder --linux --x64",
"build:windows": "node .electron-vue/build.js && electron-builder --win --x64",
"build:mas": "npm run build:clean && npm run pack && electron-packager ./ 'Whalebird' --platform=mas --arch=x64 --electron-version=2.0.7 --asar.unpackDir='build/sounds' --out=packages --ignore='^/src' --ignore='^/test' --ignore='^/.electron-vue' --ignore='^/.envrc' --ignore='^/packages' --ignore='^/plist' --ignore='^/static' --ignore='^/whalebird.db' --ignore='^/screenshot.png' --prune=true --icon=./build/icons/icon.icns --overwrite --app-bundle-id=org.whalebird.desktop --app-version=$npm_package_config_appVersion --build-version=$npm_package_config_buildVersion --extend-info='./plist/team.plist' --osx-sign --app-category-type=public.app-category.social-networking",
"build:mas": "npm run build:clean && npm run pack && electron-packager ./ 'Whalebird' --platform=mas --arch=x64 --electron-version=2.0.8 --asar.unpackDir='build/sounds' --out=packages --ignore='^/src' --ignore='^/test' --ignore='^/.electron-vue' --ignore='^/.envrc' --ignore='^/packages' --ignore='^/plist' --ignore='^/static' --ignore='^/whalebird.db' --ignore='^/screenshot.png' --prune=true --icon=./build/icons/icon.icns --overwrite --app-bundle-id=org.whalebird.desktop --app-version=$npm_package_config_appVersion --build-version=$npm_package_config_buildVersion --extend-info='./plist/team.plist' --osx-sign --app-category-type=public.app-category.social-networking",
"dev": "node .electron-vue/dev-runner.js",
"e2e": "npm run pack && mocha test/e2e",
"lint": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter src test",
@ -103,6 +103,7 @@
"electron-log": "^2.2.14",
"electron-window-state": "^4.1.1",
"element-ui": "^2.3.4",
"emojilib": "^2.3.0",
"hawk": "^7.0.7",
"hoek": "^5.0.3",
"i18next": "^11.5.0",
@ -147,7 +148,7 @@
"css-loader": "^0.28.4",
"del": "^3.0.0",
"devtron": "^1.4.0",
"electron": "2.0.7",
"electron": "2.0.8",
"electron-builder": "^20.5.1",
"electron-debug": "^1.4.0",
"electron-devtools-installer": "^2.2.4",

View File

@ -99,6 +99,16 @@
"fav_rb_sound": "Favorit und Boost:",
"toot_sound": "Toot:"
},
"notification": {
"title": "Notification",
"notify": {
"title": "Notify",
"reply": "Reply:",
"reblog": "Reblog:",
"favourite": "Favourite:",
"follow": "Follow:"
}
},
"account": {
"title": "Konto",
"connected": "Verbundenes Konto",

View File

@ -87,6 +87,11 @@
"display_name": "Display name",
"username": "Username"
},
"time_format": {
"title": "Time format:",
"absolute": "Absolute",
"relative": "Relative"
},
"toot": "Toot",
"visibility": {
"title": "Default visibility:",
@ -99,6 +104,16 @@
"fav_rb_sound": "Favorite and Boost:",
"toot_sound": "Toot:"
},
"notification": {
"title": "Notification",
"notify": {
"title": "Notify",
"reply": "Reply:",
"reblog": "Reblog:",
"favourite": "Favourite:",
"follow": "Follow:"
}
},
"account": {
"title": "Account",
"connected": "Connected Account",

View File

@ -99,6 +99,16 @@
"fav_rb_sound": "Partages et favoris:",
"toot_sound": "Pouets:"
},
"notification": {
"title": "Notification",
"notify": {
"title": "Notify",
"reply": "Reply:",
"reblog": "Reblog:",
"favourite": "Favourite:",
"follow": "Follow:"
}
},
"account": {
"title": "Compte",
"connected": "Compte connecté",

View File

@ -99,6 +99,16 @@
"fav_rb_sound": "お気に入り,ブースト時:",
"toot_sound": "トゥート時:"
},
"notification": {
"title": "通知",
"notify": {
"title": "通知設定",
"reply": "返信:",
"reblog": "ブースト:",
"favourite": "お気に入り:",
"follow": "フォロー:"
}
},
"account": {
"title": "アカウント",
"connected": "登録済みアカウント",

View File

@ -99,6 +99,16 @@
"fav_rb_sound": "즐겨찾기 및 부스트:",
"toot_sound": "툿:"
},
"notification": {
"title": "Notification",
"notify": {
"title": "Notify",
"reply": "Reply:",
"reblog": "Reblog:",
"favourite": "Favourite:",
"follow": "Follow:"
}
},
"account": {
"title": "계정",
"connected": "연결된 계정",

View File

@ -99,6 +99,16 @@
"fav_rb_sound": "Polubienie i podbicie:",
"toot_sound": "Wpisy:"
},
"notification": {
"title": "Notification",
"notify": {
"title": "Notify",
"reply": "Reply:",
"reblog": "Reblog:",
"favourite": "Favourite:",
"follow": "Follow:"
}
},
"account": {
"title": "Konta",
"connected": "Połączone konta",

View File

@ -0,0 +1,10 @@
export default {
Absolute: {
name: 'preferences.general.time_format.absolute',
value: 0
},
Relative: {
name: 'preferences.general.time_format.relative',
value: 1
}
}

View File

@ -578,14 +578,14 @@ ipcMain.on('get-preferences', (event, _) => {
})
})
ipcMain.on('save-preferences', (event, data) => {
ipcMain.on('update-preferences', (event, data) => {
const preferences = new Preferences(preferencesDBPath)
preferences.save(data)
preferences.update(data)
.then((conf) => {
event.sender.send('response-save-preferences', conf)
event.sender.send('response-update-preferences', conf)
})
.catch((err) => {
event.sender.send('error-save-preferences', err)
event.sender.send('error-update-preferences', err)
})
})

View File

@ -4,6 +4,7 @@ import Visibility from '../constants/visibility'
import DisplayStyle from '../constants/displayStyle'
import Theme from '../constants/theme'
import Language from '../constants/language'
import TimeFormat from '../constants/timeFormat'
const Base = {
general: {
@ -14,13 +15,22 @@ const Base = {
theme: Theme.Light.key,
fontSize: 14,
displayNameStyle: DisplayStyle.DisplayNameAndUsername.value,
tootVisibility: Visibility.Public.value
tootVisibility: Visibility.Public.value,
timeFormat: TimeFormat.Absolute.value
},
state: {
collapse: false
},
language: {
language: Language.en.key
},
notification: {
notify: {
reply: true,
reblog: true,
favourite: true,
follow: true
}
}
}

View File

@ -23,11 +23,15 @@
<icon name="cog" class="icon" scale="1.3"></icon>
<span>{{ $t('preferences.general.title') }}</span>
</el-menu-item>
<el-menu-item index="2" :route="{path: '/preferences/account'}" @click="account">
<el-menu-item index="2" :route="{path: '/preferences/notification'}" @click="notification">
<icon name="bell" class="icon" scale="1.3"></icon>
<span>{{ $t('preferences.notification.title') }}</span>
</el-menu-item>
<el-menu-item index="3" :route="{path: '/preferences/account'}" @click="account">
<icon name="user" class="icon" scale="1.3"></icon>
<span>{{ $t('preferences.account.title') }}</span>
</el-menu-item>
<el-menu-item index="3" :route="{path: '/preferences/language'}" @click="language">
<el-menu-item index="4" :route="{path: '/preferences/language'}" @click="language">
<icon name="language" class="icon" scale="1.3"></icon>
<span>{{ $t('preferences.language.title') }}</span>
</el-menu-item>
@ -60,6 +64,9 @@ export default {
general () {
this.$router.push('/preferences/general')
},
notification () {
this.$router.push('/preferences/notification')
},
account () {
this.$router.push('/preferences/account')
},

View File

@ -30,6 +30,19 @@
</el-select>
</td>
</tr>
<tr>
<td class="title">{{ $t('preferences.general.time_format.title') }}</td>
<td class="status">
<el-select v-model="timeFormat" placeholder="format">
<el-option
v-for="format in timeFormats"
:key="format.value"
:label="$t(format.name)"
:value="format.value">
</el-option>
</el-select>
</td>
</tr>
</tbody>
</table>
</div>
@ -86,6 +99,7 @@ import { mapState } from 'vuex'
import Visibility from '~/src/constants/visibility'
import DisplayStyle from '~/src/constants/displayStyle'
import Theme from '~/src/constants/theme'
import TimeFormat from '~/src/constants/timeFormat'
export default {
name: 'general',
@ -104,6 +118,10 @@ export default {
themes: [
Theme.Light,
Theme.Dark
],
timeFormats: [
TimeFormat.Absolute,
TimeFormat.Relative
]
}
},
@ -128,6 +146,14 @@ export default {
this.$store.dispatch('Preferences/General/updateDisplayNameStyle', value)
}
},
timeFormat: {
get () {
return this.$store.state.Preferences.General.general.timeFormat
},
set (value) {
this.$store.dispatch('Preferences/General/updateTimeFormat', value)
}
},
tootVisibility: {
get () {
return this.$store.state.Preferences.General.general.tootVisibility

View File

@ -0,0 +1,129 @@
<template>
<div id="notification">
<h2>{{ $t('preferences.notification.title') }}</h2>
<div class="notify">
<h3>{{ $t('preferences.notification.notify.title') }}</h3>
<table class="notification">
<tbody>
<tr>
<td class="title">{{ $t('preferences.notification.notify.reply') }}</td>
<td class="status">
<el-switch
v-model="notifyReply"
active-color="#13ce66">
</el-switch>
</td>
</tr>
<tr>
<td class="title">{{ $t('preferences.notification.notify.reblog') }}</td>
<td class="status">
<el-switch
v-model="notifyReblog"
active-color="#13ce66">
</el-switch>
</td>
</tr>
<tr>
<td class="title">{{ $t('preferences.notification.notify.favourite') }}</td>
<td class="status">
<el-switch
v-model="notifyFavourite"
active-color="#13ce66">
</el-switch>
</td>
</tr>
<tr>
<td class="title">{{ $t('preferences.notification.notify.follow') }}</td>
<td class="status">
<el-switch
v-model="notifyFollow"
active-color="#13ce66">
</el-switch>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
export default {
name: 'notification',
computed: {
notifyReply: {
get () {
return this.$store.state.Preferences.Notification.notification.notify.reply
},
set (value) {
this.$store.dispatch('Preferences/Notification/updateNotify', {
reply: value
})
}
},
notifyReblog: {
get () {
return this.$store.state.Preferences.Notification.notification.notify.reblog
},
set (value) {
this.$store.dispatch('Preferences/Notification/updateNotify', {
reblog: value
})
}
},
notifyFavourite: {
get () {
return this.$store.state.Preferences.Notification.notification.notify.favourite
},
set (value) {
this.$store.dispatch('Preferences/Notification/updateNotify', {
favourite: value
})
}
},
notifyFollow: {
get () {
return this.$store.state.Preferences.Notification.notification.notify.follow
},
set (value) {
this.$store.dispatch('Preferences/Notification/updateNotify', {
follow: value
})
}
}
},
created () {
this.$store.dispatch('Preferences/Notification/loadNotification')
.catch(() => {
this.$message({
message: this.$t('message.preferences_load_error'),
type: 'error'
})
})
}
}
</script>
<style lang="scss" scoped>
#notification {
.notify {
table {
width: 100%;
}
td {
padding: 16px 0;
}
.title {
text-align: right;
width: 50%;
}
.status {
width: 50%;
text-align: center;
}
}
}
</style>

View File

@ -3,12 +3,14 @@
<div id="scrollable" :class="openSideBar ? 'timeline-wrapper-with-side-bar' : 'timeline-wrapper'">
<router-view></router-view>
</div>
<side-bar></side-bar>
<side-bar
:overlaid="modalOpened"
></side-bar>
</div>
</template>
<script>
import { mapState } from 'vuex'
import { mapState, mapGetters } from 'vuex'
import SideBar from './Contents/SideBar'
export default {
@ -19,7 +21,10 @@ export default {
computed: {
...mapState({
openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar
})
}),
...mapGetters('TimelineSpace/Modals', [
'modalOpened'
])
}
}
</script>

View File

@ -72,10 +72,12 @@
</template>
<script>
import { mapState } from 'vuex'
import moment from 'moment'
import { shell } from 'electron'
import { findAccount, findLink, isTag } from '../../../../utils/link'
import emojify from '~/src/renderer/utils/emojify'
import TimeFormat from '~/src/constants/timeFormat'
export default {
name: 'favourite',
@ -104,6 +106,11 @@ export default {
}
},
computed: {
...mapState({
displayNameStyle: state => state.App.displayNameStyle,
timeFormat: state => state.App.timeFormat,
language: state => state.App.language
}),
shortcutEnabled: function () {
return this.focused && !this.overlaid
}
@ -135,7 +142,13 @@ export default {
}
},
parseDatetime (datetime) {
return moment(datetime).format('YYYY-MM-DD HH:mm:ss')
switch (this.timeFormat) {
case TimeFormat.Absolute.value:
return moment(datetime).format('YYYY-MM-DD HH:mm:ss')
case TimeFormat.Relative.value:
moment.locale(this.language)
return moment(datetime).fromNow()
}
},
tootClick (e) {
if (isTag(e.target)) {

View File

@ -72,10 +72,12 @@
</template>
<script>
import { mapState } from 'vuex'
import moment from 'moment'
import { shell } from 'electron'
import { findAccount, findLink, isTag } from '../../../../utils/link'
import emojify from '~/src/renderer/utils/emojify'
import TimeFormat from '~/src/constants/timeFormat'
export default {
name: 'reblog',
@ -104,6 +106,10 @@ export default {
}
},
computed: {
...mapState({
timeFormat: state => state.App.timeFormat,
language: state => state.App.language
}),
shortcutEnabled: function () {
return this.focused && !this.overlaid
}
@ -135,7 +141,13 @@ export default {
}
},
parseDatetime (datetime) {
return moment(datetime).format('YYYY-MM-DD HH:mm:ss')
switch (this.timeFormat) {
case TimeFormat.Absolute.value:
return moment(datetime).format('YYYY-MM-DD HH:mm:ss')
case TimeFormat.Relative.value:
moment.locale(this.language)
return moment(datetime).fromNow()
}
},
tootClick (e) {
if (isTag(e.target)) {

View File

@ -120,6 +120,7 @@ import { shell, clipboard } from 'electron'
import { mapState } from 'vuex'
import { findAccount, findLink, isTag } from '../../../utils/link'
import DisplayStyle from '~/src/constants/displayStyle'
import TimeFormat from '~/src/constants/timeFormat'
import emojify from '~/src/renderer/utils/emojify'
export default {
@ -150,7 +151,9 @@ export default {
},
computed: {
...mapState({
displayNameStyle: state => state.App.displayNameStyle
displayNameStyle: state => state.App.displayNameStyle,
timeFormat: state => state.App.timeFormat,
language: state => state.App.language
}),
shortcutEnabled: function () {
return this.focused && !this.overlaid
@ -210,7 +213,13 @@ export default {
}
},
parseDatetime (datetime) {
return moment(datetime).format('YYYY-MM-DD HH:mm:ss')
switch (this.timeFormat) {
case TimeFormat.Absolute.value:
return moment(datetime).format('YYYY-MM-DD HH:mm:ss')
case TimeFormat.Relative.value:
moment.locale(this.language)
return moment(datetime).fromNow()
}
},
tootClick (e) {
if (isTag(e.target)) {

View File

@ -1,6 +1,6 @@
<template>
<transition name="slide-detail">
<div id="side_bar" v-if="openSideBar" v-shortkey="['esc']" @shortkey="close">
<div id="side_bar" v-if="openSideBar" v-shortkey="shortcutEnabled ? {close: ['esc']} : {}" @shortkey="handleKey">
<div class="header">
<i class="el-icon-loading" v-show="loading"></i>
<i class="el-icon-close" @click="close"></i>
@ -32,6 +32,12 @@ export default {
TootDetail,
AccountProfile
},
props: {
overlaid: {
type: Boolean,
default: false
}
},
data () {
return {
loading: false
@ -42,7 +48,10 @@ export default {
openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
component: state => state.TimelineSpace.Contents.SideBar.component,
backgroundColor: state => state.App.theme.background_color
})
}),
shortcutEnabled: function () {
return !this.overlaid
}
},
beforeDestroy () {
this.close()
@ -53,6 +62,13 @@ export default {
},
changeLoading (value) {
this.loading = value
},
handleKey (event) {
switch (event.srcKey) {
case 'close':
this.close()
break
}
}
}
}

View File

@ -1,7 +1,7 @@
<template>
<transition name="image-viewer">
<div id="image" v-show="modalOpen" @click="close">
<div class="image-wrapper" @keyup.esc.exact="close" tabindex="-1" ref="wrapper">
<div class="image-wrapper" v-shortkey="modalOpen ? {close: ['esc']} : {}" @shortkey="closeHandle">
<div class="image-header">
<el-button type="text" icon="el-icon-close" @click="close" class="close-button"></el-button>
</div>
@ -38,11 +38,6 @@ export default {
return this.$store.getters['TimelineSpace/Modals/ImageViewer/showRight']
}
},
updated () {
if (this.modalOpen) {
this.$refs.wrapper.focus()
}
},
methods: {
close () {
this.$store.dispatch('TimelineSpace/Modals/ImageViewer/closeModal')
@ -52,6 +47,13 @@ export default {
},
incrementIndex () {
if (this.showRight) this.$store.dispatch('TimelineSpace/Modals/ImageViewer/incrementIndex')
},
closeHandle (event) {
switch (event.srcKey) {
case 'close':
this.close()
break
}
}
}
}

View File

@ -26,6 +26,9 @@
<span v-if="item.image">
<img :src="item.image" class="icon" />
</span>
<span v-if="item.code">
{{ item.code }}
</span>
{{ item.name }}
</li>
</ul>
@ -35,6 +38,7 @@
<script>
import { mapState } from 'vuex'
import emojilib from 'emojilib'
import suggestText from '../../../../utils/suggestText'
export default {
@ -60,7 +64,7 @@ export default {
computed: {
...mapState({
filteredAccounts: state => state.TimelineSpace.Modals.NewToot.Status.filteredAccounts,
emojis: state => state.TimelineSpace.emojis
customEmojis: state => state.TimelineSpace.emojis
}),
status: {
get: function () {
@ -131,7 +135,18 @@ export default {
this.closeSuggest()
return false
}
const filtered = this.emojis.filter(emoji => emoji.name.includes(word))
// Find native emojis
const filteredEmojiName = emojilib.ordered.filter(emoji => `:${emoji}`.includes(word))
const filteredNativeEmoji = filteredEmojiName.map((name) => {
return {
name: `:${name}:`,
code: emojilib.lib[name].char
}
})
// Find custom emojis
const filteredCustomEmoji = this.customEmojis.filter(emoji => emoji.name.includes(word))
const filtered = filteredNativeEmoji.concat(filteredCustomEmoji)
console.log(filtered)
if (filtered.length > 0) {
this.openSuggest = true
this.startIndex = start
@ -160,8 +175,13 @@ export default {
}
},
insertItem (item) {
const str = `${this.status.slice(0, this.startIndex - 1)}${item.name} ${this.status.slice(this.startIndex + this.matchWord.length)}`
this.status = str
if (item.code) {
const str = `${this.status.slice(0, this.startIndex - 1)}${item.code} ${this.status.slice(this.startIndex + this.matchWord.length)}`
this.status = str
} else {
const str = `${this.status.slice(0, this.startIndex - 1)}${item.name} ${this.status.slice(this.startIndex + this.matchWord.length)}`
this.status = str
}
this.closeSuggest()
},
selectCurrentItem () {

View File

@ -26,6 +26,11 @@ export default new Router({
name: 'general',
component: require('@/components/Preferences/General').default
},
{
path: 'notification',
name: 'notification',
component: require('@/components/Preferences/Notification').default
},
{
path: 'account',
name: 'account',

View File

@ -4,6 +4,8 @@ import { LightTheme, DarkTheme } from '../utils/theme'
import Visibility from '~/src/constants/visibility'
import DisplayStyle from '~/src/constants/displayStyle'
import Theme from '~/src/constants/theme'
import TimeFormat from '~/src/constants/timeFormat'
import Language from '~/src/constants/language'
const App = {
namespaced: true,
@ -11,7 +13,15 @@ const App = {
theme: LightTheme,
fontSize: 14,
displayNameStyle: DisplayStyle.DisplayNameAndUsername.value,
tootVisibility: Visibility.Public.value
tootVisibility: Visibility.Public.value,
notify: {
reply: true,
reblog: true,
favourite: true,
follow: true
},
timeFormat: TimeFormat.Absolute.value,
language: Language.en.key
},
mutations: {
updateTheme (state, themeKey) {
@ -35,6 +45,15 @@ const App = {
},
updateTootVisibility (state, value) {
state.tootVisibility = value
},
updateNotify (state, notify) {
state.notify = notify
},
updateTimeFormat (state, format) {
state.timeFormat = format
},
updateLanguage (state, key) {
state.language = key
}
},
actions: {
@ -59,6 +78,9 @@ const App = {
commit('updateDisplayNameStyle', conf.general.displayNameStyle)
commit('updateFontSize', conf.general.fontSize)
commit('updateTootVisibility', conf.general.tootVisibility)
commit('updateNotify', conf.notification.notify)
commit('updateTimeFormat', conf.general.timeFormat)
commit('updateLanguage', conf.language.language)
resolve(conf)
})
})

View File

@ -1,13 +1,15 @@
import General from './Preferences/General'
import Account from './Preferences/Account'
import Language from './Preferences/Language'
import Notification from './Preferences/Notification'
const Preferences = {
namespaced: true,
modules: {
General,
Account,
Language
Language,
Notification
},
state: {
defaultActive: '1'

View File

@ -2,6 +2,7 @@ import { ipcRenderer } from 'electron'
import Visibility from '~/src/constants/visibility'
import DisplayStyle from '~/src/constants/displayStyle'
import Theme from '~/src/constants/theme'
import TimeFormat from '~/src/constants/timeFormat'
const General = {
namespaced: true,
@ -14,7 +15,8 @@ const General = {
theme: Theme.Light.key,
fontSize: 14,
displayNameStyle: DisplayStyle.DisplayNameAndUsername.value,
tootVisibility: Visibility.Public.value
tootVisibility: Visibility.Public.value,
timeFormat: TimeFormat.Absolute.value
},
loading: false
},
@ -52,13 +54,13 @@ const General = {
const config = {
general: newGeneral
}
ipcRenderer.send('save-preferences', config)
ipcRenderer.once('error-save-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-save-preferences')
ipcRenderer.send('update-preferences', config)
ipcRenderer.once('error-update-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-update-preferences')
commit('changeLoading', false)
})
ipcRenderer.once('response-save-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-save-preferences')
ipcRenderer.once('response-update-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-update-preferences')
commit('updateGeneral', conf.general)
dispatch('App/loadPreferences', null, { root: true })
commit('changeLoading', false)
@ -71,12 +73,12 @@ const General = {
const config = {
general: newGeneral
}
ipcRenderer.send('save-preferences', config)
ipcRenderer.once('error-save-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-save-preferences')
ipcRenderer.send('update-preferences', config)
ipcRenderer.once('error-update-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-update-preferences')
})
ipcRenderer.once('response-save-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-save-preferences')
ipcRenderer.once('response-update-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-update-preferences')
commit('updateGeneral', conf.general)
dispatch('App/loadPreferences', null, { root: true })
})
@ -88,12 +90,29 @@ const General = {
const config = {
general: newGeneral
}
ipcRenderer.send('save-preferences', config)
ipcRenderer.once('error-save-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-save-preferences')
ipcRenderer.send('update-preferences', config)
ipcRenderer.once('error-update-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-update-preferences')
})
ipcRenderer.once('response-save-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-save-preferences')
ipcRenderer.once('response-update-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-update-preferences')
dispatch('App/loadPreferences', null, { root: true })
commit('updateGeneral', conf.general)
})
},
updateTimeFormat ({ dispatch, commit, state }, value) {
const newGeneral = Object.assign({}, state.general, {
timeFormat: value
})
const config = {
general: newGeneral
}
ipcRenderer.send('update-preferences', config)
ipcRenderer.once('error-update-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-update-preferences')
})
ipcRenderer.once('response-update-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-update-preferences')
dispatch('App/loadPreferences', null, { root: true })
commit('updateGeneral', conf.general)
})
@ -105,12 +124,12 @@ const General = {
const config = {
general: newGeneral
}
ipcRenderer.send('save-preferences', config)
ipcRenderer.once('error-save-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-save-preferences')
ipcRenderer.send('update-preferences', config)
ipcRenderer.once('error-update-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-update-preferences')
})
ipcRenderer.once('response-save-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-save-preferences')
ipcRenderer.once('response-update-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-update-preferences')
dispatch('App/loadPreferences', null, { root: true })
commit('updateGeneral', conf.general)
})
@ -124,13 +143,13 @@ const General = {
const config = {
general: newGeneral
}
ipcRenderer.send('save-preferences', config)
ipcRenderer.once('error-save-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-save-preferences')
ipcRenderer.send('update-preferences', config)
ipcRenderer.once('error-update-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-update-preferences')
commit('changeLoading', false)
})
ipcRenderer.once('response-save-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-save-preferences')
ipcRenderer.once('response-update-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-update-preferences')
commit('updateGeneral', conf.general)
commit('changeLoading', false)
})

View File

@ -0,0 +1,50 @@
import { ipcRenderer } from 'electron'
export default {
namespaced: true,
state: {
notification: {
notify: {
reply: true,
reblog: true,
favourite: true,
follow: true
}
}
},
mutations: {
updateNotification (state, notification) {
state.notification = notification
}
},
actions: {
loadNotification ({ commit }) {
return new Promise((resolve, reject) => {
ipcRenderer.send('get-preferences')
ipcRenderer.once('error-get-preferences', (event, err) => {
ipcRenderer.removeAllListeners('response-get-preferences')
reject(err)
})
ipcRenderer.once('response-get-preferences', (event, conf) => {
ipcRenderer.removeAllListeners('error-get-preferences')
commit('updateNotification', conf.notification)
resolve(conf)
})
})
},
updateNotify ({ commit, state, dispatch }, notify) {
const newNotify = Object.assign({}, state.notification.notify, notify)
const newNotification = Object.assign({}, state.notification, {
notify: newNotify
})
const config = {
notification: newNotification
}
ipcRenderer.send('update-preferences', config)
ipcRenderer.once('response-update-preferences', (event, conf) => {
commit('updateNotification', conf.notification)
dispatch('App/loadPreferences', null, { root: true })
})
}
}
}

View File

@ -89,9 +89,11 @@ const TimelineSpace = {
commit('TimelineSpace/SideMenu/changeUnreadHomeTimeline', true, { root: true })
})
ipcRenderer.on('notification-start-user-streaming', (event, notification) => {
let notify = buildNotification(notification)
notify.onclick = () => {
router.push(`/${account._id}/notifications`)
let notify = createNotification(notification, rootState.App.notify)
if (notify) {
notify.onclick = () => {
router.push(`/${account._id}/notifications`)
}
}
commit('TimelineSpace/Contents/Notifications/appendNotifications', notification, { root: true })
if (rootState.TimelineSpace.Contents.Notifications.heading && Math.random() > 0.8) {
@ -172,25 +174,37 @@ const TimelineSpace = {
export default TimelineSpace
function buildNotification (notification) {
function createNotification (notification, notifyConfig) {
switch (notification.type) {
case 'favourite':
return new Notification('Favourite', {
body: `${username(notification.account)} favourited your status`
})
if (notifyConfig.favourite) {
return new Notification('Favourite', {
body: `${username(notification.account)} favourited your status`
})
}
break
case 'follow':
return new Notification('Follow', {
body: `${username(notification.account)} is now following you`
})
if (notifyConfig.follow) {
return new Notification('Follow', {
body: `${username(notification.account)} is now following you`
})
}
break
case 'mention':
// Clean html tags
return new Notification(`${notification.status.account.display_name}`, {
body: `${notification.status.content.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, '')}`
})
if (notifyConfig.reply) {
// Clean html tags
return new Notification(`${notification.status.account.display_name}`, {
body: `${notification.status.content.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, '')}`
})
}
break
case 'reblog':
return new Notification('Reblog', {
body: `${username(notification.account)} boosted your status`
})
if (notifyConfig.reblog) {
return new Notification('Reblog', {
body: `${username(notification.account)} boosted your status`
})
}
break
}
}