optimistic updates for fav/reblog

This commit is contained in:
Nolan Lawson 2018-03-20 17:41:39 -07:00
parent 1786d737bb
commit 98b704f465
6 changed files with 52 additions and 18 deletions

View File

@ -10,18 +10,16 @@ export async function setFavorited (statusId, favorited) {
} }
let instanceName = store.get('currentInstance') let instanceName = store.get('currentInstance')
let accessToken = store.get('accessToken') let accessToken = store.get('accessToken')
try { let networkPromise = favorited
await (favorited
? favoriteStatus(instanceName, accessToken, statusId) ? favoriteStatus(instanceName, accessToken, statusId)
: unfavoriteStatus(instanceName, accessToken, statusId)) : unfavoriteStatus(instanceName, accessToken, statusId)
store.setStatusFavorited(instanceName, statusId, favorited) // optimistic update
try {
await networkPromise
await database.setStatusFavorited(instanceName, statusId, favorited) await database.setStatusFavorited(instanceName, statusId, favorited)
let statusModifications = store.get('statusModifications')
let currentStatusModifications = statusModifications[instanceName] =
(statusModifications[instanceName] || {favorites: {}, reblogs: {}})
currentStatusModifications.favorites[statusId] = favorited
store.set({statusModifications: statusModifications})
} catch (e) { } catch (e) {
console.error(e) console.error(e)
toast.say(`Failed to ${favorited ? 'favorite' : 'unfavorite'}. ` + (e.message || '')) toast.say(`Failed to ${favorited ? 'favorite' : 'unfavorite'}. ` + (e.message || ''))
store.setStatusFavorited(instanceName, statusId, !favorited) // undo optimistic update
} }
} }

View File

@ -10,18 +10,16 @@ export async function setReblogged (statusId, reblogged) {
} }
let instanceName = store.get('currentInstance') let instanceName = store.get('currentInstance')
let accessToken = store.get('accessToken') let accessToken = store.get('accessToken')
try { let networkPromise = reblogged
await (reblogged
? reblogStatus(instanceName, accessToken, statusId) ? reblogStatus(instanceName, accessToken, statusId)
: unreblogStatus(instanceName, accessToken, statusId)) : unreblogStatus(instanceName, accessToken, statusId)
store.setStatusReblogged(instanceName, statusId, reblogged) // optimistic update
try {
await networkPromise
await database.setStatusReblogged(instanceName, statusId, reblogged) await database.setStatusReblogged(instanceName, statusId, reblogged)
let statusModifications = store.get('statusModifications')
let currentStatusModifications = statusModifications[instanceName] =
(statusModifications[instanceName] || {favorites: {}, reblogs: {}})
currentStatusModifications.reblogs[statusId] = reblogged
store.set({statusModifications: statusModifications})
} catch (e) { } catch (e) {
console.error(e) console.error(e)
toast.say(`Failed to ${reblogged ? 'boost' : 'unboost'}. ` + (e.message || '')) toast.say(`Failed to ${reblogged ? 'boost' : 'unboost'}. ` + (e.message || ''))
store.setStatusReblogged(instanceName, statusId, !reblogged) // undo optimistic update
} }
} }

View File

@ -1,7 +1,9 @@
import { timelineMixins } from './timelineMixins' import { timelineMixins } from './timelineMixins'
import { instanceMixins } from './instanceMixins' import { instanceMixins } from './instanceMixins'
import { statusMixins } from './statusMixins'
export function mixins (Store) { export function mixins (Store) {
instanceMixins(Store) instanceMixins(Store)
timelineMixins(Store) timelineMixins(Store)
statusMixins(Store)
} }

View File

@ -0,0 +1,22 @@
function getStatusModifications (store, instanceName) {
let statusModifications = store.get('statusModifications')
statusModifications[instanceName] = statusModifications[instanceName] || {
favorites: {},
reblogs: {}
}
return statusModifications
}
export function statusMixins (Store) {
Store.prototype.setStatusFavorited = function (instanceName, statusId, favorited) {
let statusModifications = getStatusModifications(this, instanceName)
statusModifications[instanceName].favorites[statusId] = favorited
this.set({statusModifications})
}
Store.prototype.setStatusReblogged = function (instanceName, statusId, reblogged) {
let statusModifications = getStatusModifications(this, instanceName)
statusModifications[instanceName].reblogs[statusId] = reblogged
this.set({statusModifications})
}
}

View File

@ -16,3 +16,18 @@ export async function cacheFirstUpdateAfter (networkFetcher, dbFetcher, dbUpdate
} }
} }
} }
// Make a change that we optimistically show to the user as successful, but which
// actually depends on a network operation. In the unlikely event that the network
// operation fails, revert the changes
export async function optimisticUpdate (doImmediately, networkUpdater, onSuccess, onFailure) {
let networkPromise = networkUpdater()
doImmediately()
try {
let response = await networkPromise
onSuccess(response)
} catch (e) {
console.error(e)
onFailure(e)
}
}

View File

@ -1,8 +1,7 @@
import { foobarRole } from '../roles' import { foobarRole } from '../roles'
import { import {
clickToNotificationsAndBackHome, forceOffline, forceOnline, getNthStatus, getUrl, homeNavButton, clickToNotificationsAndBackHome, forceOffline, forceOnline, getNthStatus, getUrl, homeNavButton,
notificationsNavButton, notificationsNavButton
sleep
} from '../utils' } from '../utils'
import { deleteAs, postAs, postReplyAs } from '../serverActions' import { deleteAs, postAs, postReplyAs } from '../serverActions'