From bd4bb90870fc3c49f19efa3f93a476b974f432d9 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Mon, 24 Aug 2020 19:33:55 +0900 Subject: [PATCH] refs #1714 Create bookmarks timeline --- src/config/locales/en/translation.json | 1 + .../TimelineSpace/Contents/Bookmarks.vue | 213 ++++++++++++++++++ .../components/TimelineSpace/HeaderMenu.vue | 7 +- src/renderer/router/index.ts | 6 + src/renderer/store/TimelineSpace/Contents.ts | 3 + .../store/TimelineSpace/Contents/Bookmarks.ts | 128 +++++++++++ 6 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 src/renderer/components/TimelineSpace/Contents/Bookmarks.vue create mode 100644 src/renderer/store/TimelineSpace/Contents/Bookmarks.ts diff --git a/src/config/locales/en/translation.json b/src/config/locales/en/translation.json index 1da900c7..cd3c0ee8 100644 --- a/src/config/locales/en/translation.json +++ b/src/config/locales/en/translation.json @@ -65,6 +65,7 @@ "notification": "Notification", "mention": "Mention", "favourite": "Favourite", + "bookmark": "Bookmark", "follow_requests": "Follow Requests", "direct_messages": "Direct Messages", "local": "Local timeline", diff --git a/src/renderer/components/TimelineSpace/Contents/Bookmarks.vue b/src/renderer/components/TimelineSpace/Contents/Bookmarks.vue new file mode 100644 index 00000000..399e4945 --- /dev/null +++ b/src/renderer/components/TimelineSpace/Contents/Bookmarks.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/src/renderer/components/TimelineSpace/HeaderMenu.vue b/src/renderer/components/TimelineSpace/HeaderMenu.vue index 71c4e266..9b39f08e 100644 --- a/src/renderer/components/TimelineSpace/HeaderMenu.vue +++ b/src/renderer/components/TimelineSpace/HeaderMenu.vue @@ -74,7 +74,7 @@ export default { this.$store.dispatch('TimelineSpace/HeaderMenu/setupLoading') }, watch: { - $route: function() { + $route: function () { this.channelName() this.loadFilter() } @@ -94,6 +94,9 @@ export default { case 'favourites': this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.favourite')) break + case 'bookmarks': + this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.bookmark')) + break case 'mentions': this.$store.commit('TimelineSpace/HeaderMenu/updateTitle', this.$t('header_menu.mention')) break @@ -142,6 +145,7 @@ export default { case 'notifications': case 'mentions': case 'favourites': + case 'bookmarks': case 'local': case 'public': case 'tag': @@ -159,6 +163,7 @@ export default { case 'notifications': case 'mentions': case 'favourites': + case 'bookmarks': case 'local': case 'public': case 'tag': diff --git a/src/renderer/router/index.ts b/src/renderer/router/index.ts index 0a278c72..0b15b505 100644 --- a/src/renderer/router/index.ts +++ b/src/renderer/router/index.ts @@ -30,6 +30,7 @@ import TimelineSpaceContentsListsIndex from '@/components/TimelineSpace/Contents import TimelineSpaceContentsListsEdit from '@/components/TimelineSpace/Contents/Lists/Edit.vue' import TimelineSpaceContentsListsShow from '@/components/TimelineSpace/Contents/Lists/Show.vue' import TimelineSpaceContentsFollowRequests from '@/components/TimelineSpace/Contents/FollowRequests.vue' +import TimelineSpaceContentsBookmarks from '@/components/TimelineSpace/Contents/Bookmarks.vue' Vue.use(Router) @@ -132,6 +133,11 @@ const router = new Router({ name: 'favourites', component: TimelineSpaceContentsFavourites }, + { + path: 'bookmarks', + name: 'bookmarks', + component: TimelineSpaceContentsBookmarks + }, { path: 'local', name: 'local', diff --git a/src/renderer/store/TimelineSpace/Contents.ts b/src/renderer/store/TimelineSpace/Contents.ts index 3d44456d..e461051e 100644 --- a/src/renderer/store/TimelineSpace/Contents.ts +++ b/src/renderer/store/TimelineSpace/Contents.ts @@ -2,6 +2,7 @@ import SideBar, { SideBarModuleState } from './Contents/SideBar' import Home, { HomeState } from './Contents/Home' import Notifications, { NotificationsState } from './Contents/Notifications' import Favourites, { FavouritesState } from './Contents/Favourites' +import Bookmarks, { BookmarksState } from './Contents/Bookmarks' import Local, { LocalState } from './Contents/Local' import Public, { PublicState } from './Contents/Public' import Search, { SearchModuleState } from './Contents/Search' @@ -24,6 +25,7 @@ type ContentsModule = { Mentions: MentionsState DirectMessages: DirectMessagesState Favourites: FavouritesState + Bookmarks: BookmarksState Local: LocalState Public: PublicState Search: SearchModuleState @@ -61,6 +63,7 @@ const Contents: Module = { Home, Notifications, Favourites, + Bookmarks, Local, DirectMessages, Mentions, diff --git a/src/renderer/store/TimelineSpace/Contents/Bookmarks.ts b/src/renderer/store/TimelineSpace/Contents/Bookmarks.ts new file mode 100644 index 00000000..f16edc4f --- /dev/null +++ b/src/renderer/store/TimelineSpace/Contents/Bookmarks.ts @@ -0,0 +1,128 @@ +import generator, { Entity } from 'megalodon' +import parse from 'parse-link-header' +import { Module, MutationTree, ActionTree } from 'vuex' +import { RootState } from '@/store' +import { LocalAccount } from '~/src/types/localAccount' + +export type BookmarksState = { + bookmarks: Array + lazyLoading: boolean + maxId: string | null +} + +const state = (): BookmarksState => ({ + bookmarks: [], + lazyLoading: false, + maxId: null +}) + +export const MUTATION_TYPES = { + UPDATE_BOOKMARKS: 'updateBookmarks', + INSERT_BOOKMARKS: 'insertBookmarks', + UPDATE_TOOT: 'updateToot', + DELETE_TOOT: 'deleteToot', + CHANGE_LAZY_LOADING: 'changeLazyLoading', + CHANGE_MAX_ID: 'changeMaxId' +} + +const mutations: MutationTree = { + [MUTATION_TYPES.UPDATE_BOOKMARKS]: (state, bookmarks: Array) => { + state.bookmarks = bookmarks + }, + [MUTATION_TYPES.INSERT_BOOKMARKS]: (state, bookmarks: Array) => { + state.bookmarks = state.bookmarks.concat(bookmarks) + }, + [MUTATION_TYPES.UPDATE_TOOT]: (state, message: Entity.Status) => { + state.bookmarks = state.bookmarks.map(toot => { + if (toot.id === message.id) { + return message + } else if (toot.reblog !== null && toot.reblog.id === message.id) { + // When user reblog/favourite a reblogged toot, target message is a original toot. + // So, a message which is received now is original toot. + const reblog = { + reblog: message + } + return Object.assign(toot, reblog) + } else { + return toot + } + }) + }, + [MUTATION_TYPES.DELETE_TOOT]: (state, message: Entity.Status) => { + state.bookmarks = state.bookmarks.filter(toot => { + if (toot.reblog !== null && toot.reblog.id === message.id) { + return false + } else { + return toot.id !== message.id + } + }) + }, + [MUTATION_TYPES.CHANGE_LAZY_LOADING]: (state, value: boolean) => { + state.lazyLoading = value + }, + [MUTATION_TYPES.CHANGE_MAX_ID]: (state, id: string | null) => { + state.maxId = id + } +} + +const actions: ActionTree = { + fetchBookmarks: async ({ commit, rootState }, account: LocalAccount): Promise> => { + const client = generator(rootState.TimelineSpace.sns, account.baseURL, account.accessToken, rootState.App.userAgent) + const res = await client.getBookmarks({ limit: 40 }) + commit(MUTATION_TYPES.UPDATE_BOOKMARKS, res.data) + // Parse link header + try { + const link = parse(res.headers.link) + if (link !== null) { + commit(MUTATION_TYPES.CHANGE_MAX_ID, link.next.max_id) + } else { + commit(MUTATION_TYPES.CHANGE_MAX_ID, null) + } + } catch (err) { + commit(MUTATION_TYPES.CHANGE_MAX_ID, null) + console.error(err) + } + return res.data + }, + laxyFetchBookmarks: async ({ state, commit, rootState }): Promise | null> => { + if (state.lazyLoading) { + return Promise.resolve(null) + } + if (!state.maxId) { + return Promise.resolve(null) + } + commit(MUTATION_TYPES.CHANGE_LAZY_LOADING, true) + const client = generator( + rootState.TimelineSpace.sns, + rootState.TimelineSpace.account.baseURL, + rootState.TimelineSpace.account.accessToken, + rootState.App.userAgent + ) + const res = await client.getFavourites({ max_id: state.maxId, limit: 40 }).finally(() => { + commit(MUTATION_TYPES.CHANGE_LAZY_LOADING, false) + }) + commit(MUTATION_TYPES.INSERT_BOOKMARKS, res.data) + // Parse link header + try { + const link = parse(res.headers.link) + if (link !== null) { + commit(MUTATION_TYPES.CHANGE_MAX_ID, link.next.max_id) + } else { + commit(MUTATION_TYPES.CHANGE_MAX_ID, null) + } + } catch (err) { + commit(MUTATION_TYPES.CHANGE_MAX_ID, null) + console.error(err) + } + return res.data + } +} + +const Bookmark: Module = { + namespaced: true, + state: state, + mutations: mutations, + actions: actions +} + +export default Bookmark