From c3003cb363315d3a16c09649354ab57e34003551 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 28 Jul 2019 05:25:12 +0900 Subject: [PATCH] Improve mobile notifications view --- locales/ja-JP.yml | 4 ++ src/client/app/common/scripts/paging.ts | 1 + .../views/components/settings/settings.vue | 6 ++ src/client/app/mobile/script.ts | 2 + .../mobile/views/components/notification.vue | 21 ++++++ .../mobile/views/components/notifications.vue | 32 ++++++++- .../app/mobile/views/components/ui.nav.vue | 7 +- .../app/mobile/views/pages/notifications.vue | 68 +++++++++++++++++++ src/client/app/store.ts | 1 + 9 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 src/client/app/mobile/views/pages/notifications.vue diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 437a0b115a..526f9b0f35 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -225,6 +225,7 @@ common: use-avatar-reversi-stones: "リバーシの石にアバターを使う" disable-animated-mfm: "投稿内の動きのあるテキストを無効にする" disable-showing-animated-images: "アニメーション画像を再生しない" + enable-quick-notification-view: "通知のクイックビューを有効にする" suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" always-show-nsfw: "常に閲覧注意のメディアを表示する" always-mark-nsfw: "常にメディアを閲覧注意として投稿" @@ -1894,6 +1895,9 @@ mobile/views/pages/search.vue: mobile/views/pages/selectdrive.vue: select-file: "ファイルを選択" +mobile/views/pages/notifications.vue: + notifications: "通知" + mobile/views/pages/settings.vue: signed-in-as: "{}としてサインイン中" diff --git a/src/client/app/common/scripts/paging.ts b/src/client/app/common/scripts/paging.ts index cf36a692d2..289a72a6ab 100644 --- a/src/client/app/common/scripts/paging.ts +++ b/src/client/app/common/scripts/paging.ts @@ -67,6 +67,7 @@ export default (opts) => ({ async init() { this.fetching = true; + if (opts.beforeInit) opts.beforeInit(this); let params = typeof this.pagination.params === 'function' ? this.pagination.params(true) : this.pagination.params; if (params && params.then) params = await params; await this.$root.api(this.pagination.endpoint, { diff --git a/src/client/app/common/views/components/settings/settings.vue b/src/client/app/common/views/components/settings/settings.vue index 401d9423ae..c609a96722 100644 --- a/src/client/app/common/views/components/settings/settings.vue +++ b/src/client/app/common/views/components/settings/settings.vue @@ -47,6 +47,7 @@ <ui-switch v-model="disableAnimatedMfm">{{ $t('@._settings.disable-animated-mfm') }}</ui-switch> <ui-switch v-model="disableShowingAnimatedImages">{{ $t('@._settings.disable-showing-animated-images') }}</ui-switch> <ui-switch v-model="remainDeletedNote">{{ $t('@._settings.remain-deleted-note') }}</ui-switch> + <ui-switch v-model="enableMobileQuickNotificationView">{{ $t('@._settings.enable-quick-notification-view') }}</ui-switch> </section> <section> <header>{{ $t('@._settings.line-width') }}</header> @@ -532,6 +533,11 @@ export default Vue.extend({ set(value) { this.$store.commit('device/set', { key: 'mobileNotificationPosition', value }); } }, + enableMobileQuickNotificationView: { + get() { return this.$store.state.device.enableMobileQuickNotificationView; }, + set(value) { this.$store.commit('device/set', { key: 'enableMobileQuickNotificationView', value }); } + }, + homeProfile: { get() { return this.$store.state.device.homeProfile; }, set(value) { this.$store.commit('device/set', { key: 'homeProfile', value }); } diff --git a/src/client/app/mobile/script.ts b/src/client/app/mobile/script.ts index 6222409931..082b3e895f 100644 --- a/src/client/app/mobile/script.ts +++ b/src/client/app/mobile/script.ts @@ -14,6 +14,7 @@ import MkIndex from './views/pages/index.vue'; import MkSignup from './views/pages/signup.vue'; import MkSelectDrive from './views/pages/selectdrive.vue'; import MkDrive from './views/pages/drive.vue'; +import MkNotifications from './views/pages/notifications.vue'; import MkMessaging from './views/pages/messaging.vue'; import MkMessagingRoom from './views/pages/messaging-room.vue'; import MkNote from './views/pages/note.vue'; @@ -144,6 +145,7 @@ init((launch, os) => { { path: '/i/groups/:group', component: UI, props: route => ({ component: () => import('../common/views/pages/user-group-editor.vue').then(m => m.default), groupId: route.params.group }) }, { path: '/i/follow-requests', name: 'follow-requests', component: UI, props: route => ({ component: () => import('../common/views/pages/follow-requests.vue').then(m => m.default) }) }, { path: '/i/widgets', name: 'widgets', component: () => import('./views/pages/widgets.vue').then(m => m.default) }, + { path: '/i/notifications', name: 'notifications', component: MkNotifications }, { path: '/i/messaging', name: 'messaging', component: MkMessaging }, { path: '/i/messaging/group/:group', component: MkMessagingRoom }, { path: '/i/messaging/:user', component: MkMessagingRoom }, diff --git a/src/client/app/mobile/views/components/notification.vue b/src/client/app/mobile/views/components/notification.vue index 448d22cbe6..300a46e52a 100644 --- a/src/client/app/mobile/views/components/notification.vue +++ b/src/client/app/mobile/views/components/notification.vue @@ -100,6 +100,27 @@ export default Vue.extend({ <style lang="stylus" scoped> .mk-notification + + &.wide + > .notification + @media (min-width 350px) + font-size 14px + + @media (min-width 500px) + font-size 16px + + @media (min-width 600px) + padding 24px 32px + + > .avatar + @media (min-width 500px) + width 42px + height 42px + + > div + @media (min-width 500px) + width calc(100% - 42px) + > .notification padding 16px font-size 12px diff --git a/src/client/app/mobile/views/components/notifications.vue b/src/client/app/mobile/views/components/notifications.vue index f793f5d685..ca6a8beca3 100644 --- a/src/client/app/mobile/views/components/notifications.vue +++ b/src/client/app/mobile/views/components/notifications.vue @@ -9,7 +9,7 @@ <!-- トランジションを有効にするとなぜかメモリリークする --> <component :is="!$store.state.device.reduceMotion ? 'transition-group' : 'div'" name="mk-notifications" class="transition notifications" tag="div"> <template v-for="(notification, i) in _notifications"> - <mk-notification :notification="notification" :key="notification.id"/> + <mk-notification :notification="notification" :key="notification.id" :class="{ wide: wide }"/> <p class="date" :key="notification.id + '_date'" v-if="i != items.length - 1 && notification._date != _notifications[i + 1]._date"> <span><fa icon="angle-up"/>{{ notification._datetext }}</span> <span><fa icon="angle-down"/>{{ _notifications[i + 1]._datetext }}</span> @@ -37,15 +37,37 @@ export default Vue.extend({ i18n: i18n('mobile/views/components/notifications.vue'), mixins: [ - paging({}), + paging({ + beforeInit: (self) => { + self.$emit('beforeInit'); + }, + onInited: (self) => { + self.$emit('inited'); + } + }), ], + props: { + type: { + type: String, + required: false + }, + wide: { + type: Boolean, + required: false, + default: false + } + }, + data() { return { connection: null, pagination: { endpoint: 'i/notifications', limit: 15, + params: () => ({ + includeTypes: this.type ? [this.type] : undefined + }) } }; }, @@ -62,6 +84,12 @@ export default Vue.extend({ } }, + watch: { + type() { + this.reload(); + } + }, + mounted() { this.connection = this.$root.stream.useSharedConnection('main'); this.connection.on('notification', this.onNotification); diff --git a/src/client/app/mobile/views/components/ui.nav.vue b/src/client/app/mobile/views/components/ui.nav.vue index 26a388914a..db250ec6f8 100644 --- a/src/client/app/mobile/views/components/ui.nav.vue +++ b/src/client/app/mobile/views/components/ui.nav.vue @@ -17,7 +17,8 @@ <div class="links"> <ul> <li><router-link to="/" :data-active="$route.name == 'index'"><i><fa icon="home" fixed-width/></i>{{ $t('timeline') }}<i><fa icon="angle-right"/></i></router-link></li> - <li><p @click="showNotifications = true"><i><fa :icon="['far', 'bell']" fixed-width/></i>{{ $t('notifications') }}<i v-if="hasUnreadNotification" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></p></li> + <li v-if="$store.state.device.enableMobileQuickNotificationView"><p @click="showNotifications = true"><i><fa :icon="faBell" fixed-width/></i>{{ $t('notifications') }}<i v-if="hasUnreadNotification" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></p></li> + <li v-else><router-link to="/i/notifications" :data-active="$route.name == 'notifications'"><i><fa :icon="faBell" fixed-width/></i>{{ $t('notifications') }}<i v-if="hasUnreadNotification" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li> <li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'"><i><fa :icon="['far', 'comments']" fixed-width/></i>{{ $t('@.messaging') }}<i v-if="hasUnreadMessagingMessage" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li> <li v-if="$store.getters.isSignedIn && ($store.state.i.isLocked || $store.state.i.carefulBot)"><router-link to="/i/follow-requests" :data-active="$route.name == 'follow-requests'"><i><fa :icon="['far', 'envelope']" fixed-width/></i>{{ $t('follow-requests') }}<i v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li> <li><router-link to="/featured" :data-active="$route.name == 'featured'"><i><fa :icon="faNewspaper" fixed-width/></i>{{ $t('@.featured-notes') }}<i><fa icon="angle-right"/></i></router-link></li> @@ -68,7 +69,7 @@ import Vue from 'vue'; import i18n from '../../../i18n'; import { lang } from '../../../config'; import { faNewspaper, faHashtag, faHome, faColumns, faUsers } from '@fortawesome/free-solid-svg-icons'; -import { faMoon, faSun, faStickyNote } from '@fortawesome/free-regular-svg-icons'; +import { faMoon, faSun, faStickyNote, faBell } from '@fortawesome/free-regular-svg-icons'; import { search } from '../../../common/scripts/search'; export default Vue.extend({ @@ -88,7 +89,7 @@ export default Vue.extend({ announcements: [], searching: false, showNotifications: false, - faNewspaper, faHashtag, faMoon, faSun, faHome, faColumns, faStickyNote, faUsers + faNewspaper, faHashtag, faMoon, faSun, faHome, faColumns, faStickyNote, faUsers, faBell, }; }, diff --git a/src/client/app/mobile/views/pages/notifications.vue b/src/client/app/mobile/views/pages/notifications.vue new file mode 100644 index 0000000000..e71a855d56 --- /dev/null +++ b/src/client/app/mobile/views/pages/notifications.vue @@ -0,0 +1,68 @@ +<template> +<mk-ui> + <template #header><fa :icon="faBell"/> {{ $t('notifications') }}</template> + <template #func> + <button @click="filter()"><fa icon="cog"/></button> + </template> + + <main> + <mk-notifications @before-init="beforeInit()" @inited="inited()" :type="type === 'all' ? null : type" :wide="true" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }"/> + </main> +</mk-ui> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import { faBell } from '@fortawesome/free-regular-svg-icons'; +import i18n from '../../../i18n'; +import Progress from '../../../common/scripts/loading'; + +export default Vue.extend({ + i18n: i18n('mobile/views/pages/notifications.vue'), + data() { + return { + type: 'all', + faBell, + }; + }, + methods: { + beforeInit() { + Progress.start(); + }, + inited() { + Progress.done(); + }, + filter() { + this.$root.dialog({ + title: this.$t('@.notification-type'), + type: null, + select: { + items: ['all', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'receiveFollowRequest'].map(x => ({ + value: x, text: this.$t('@.notification-types.' + x) + })) + default: this.type, + }, + showCancelButton: true + }).then(({ canceled, result: type }) => { + if (canceled) return; + this.type = type; + }); + } + } +}); +</script> + +<style lang="stylus" scoped> +main > * + overflow hidden + background var(--face) + + &.round + border-radius 8px + + &.shadow + box-shadow 0 4px 16px rgba(#000, 0.1) + + @media (min-width 500px) + box-shadow 0 8px 32px rgba(#000, 0.1) +</style> diff --git a/src/client/app/store.ts b/src/client/app/store.ts index 18137c1ca9..d9f1631a82 100644 --- a/src/client/app/store.ts +++ b/src/client/app/store.ts @@ -75,6 +75,7 @@ const defaultDeviceSettings = { disableShowingAnimatedImages: false, expandUsersPhotos: true, expandUsersActivity: true, + enableMobileQuickNotificationView: false, }; export default (os: MiOS) => new Vuex.Store({