mirror of
https://github.com/maunium/stickerpicker
synced 2024-09-18 00:20:52 +00:00
Frequently used in sync with packs & way to clear Frequently used
This commit is contained in:
parent
5c8c72e341
commit
70b90b5738
|
@ -13,22 +13,80 @@
|
|||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
const FREQUENTLY_USED = JSON.parse(window.localStorage.mauFrequentlyUsedStickerIDs || "{}")
|
||||
|
||||
const FREQUENTLY_USED_STORAGE_KEY = 'mauFrequentlyUsedStickerIDs'
|
||||
const FREQUENTLY_USED_STORAGE_CACHE_KEY = 'mauFrequentlyUsedStickerCache'
|
||||
|
||||
let FREQUENTLY_USED = JSON.parse(window.localStorage[FREQUENTLY_USED_STORAGE_KEY] ?? '{}')
|
||||
let FREQUENTLY_USED_SORTED = null
|
||||
|
||||
export const add = id => {
|
||||
const [count] = FREQUENTLY_USED[id] || [0]
|
||||
FREQUENTLY_USED[id] = [count + 1, Date.now()]
|
||||
window.localStorage.mauFrequentlyUsedStickerIDs = JSON.stringify(FREQUENTLY_USED)
|
||||
const sortFrequentlyUsedEntries = (entry1, entry2) => {
|
||||
const [, [count1, date1]] = entry1
|
||||
const [, [count2, date2]] = entry2
|
||||
return count2 === count1 ? date2 - date1 : count2 - count1
|
||||
}
|
||||
|
||||
export const setFrequentlyUsedStorage = (frequentlyUsed) => {
|
||||
FREQUENTLY_USED = frequentlyUsed ?? {}
|
||||
window.localStorage[FREQUENTLY_USED_STORAGE_KEY] = JSON.stringify(FREQUENTLY_USED)
|
||||
FREQUENTLY_USED_SORTED = null
|
||||
}
|
||||
|
||||
export const setFrequentlyUsedCacheStorage = (stickers) => {
|
||||
const toPutInCache = stickers.map(sticker => [sticker.id, sticker])
|
||||
window.localStorage[FREQUENTLY_USED_STORAGE_CACHE_KEY] = JSON.stringify(toPutInCache)
|
||||
}
|
||||
|
||||
export const add = (id) => {
|
||||
let FREQUENTLY_USED_COPY = { ...FREQUENTLY_USED }
|
||||
const [count] = FREQUENTLY_USED_COPY[id] || [0]
|
||||
FREQUENTLY_USED_COPY[id] = [count + 1, Date.now()]
|
||||
setFrequentlyUsedStorage(FREQUENTLY_USED_COPY)
|
||||
}
|
||||
|
||||
export const get = (limit = 16) => {
|
||||
if (FREQUENTLY_USED_SORTED === null) {
|
||||
FREQUENTLY_USED_SORTED = Object.entries(FREQUENTLY_USED)
|
||||
.sort(([, [count1, date1]], [, [count2, date2]]) =>
|
||||
count2 === count1 ? date2 - date1 : count2 - count1)
|
||||
FREQUENTLY_USED_SORTED = Object.entries(FREQUENTLY_USED || {})
|
||||
.sort(sortFrequentlyUsedEntries)
|
||||
.map(([emoji]) => emoji)
|
||||
}
|
||||
return FREQUENTLY_USED_SORTED.slice(0, limit)
|
||||
}
|
||||
|
||||
export const getFromCache = () => {
|
||||
return Object.values(JSON.parse(localStorage[FREQUENTLY_USED_STORAGE_CACHE_KEY] ?? '[]'))
|
||||
}
|
||||
|
||||
export const remove = (id) => {
|
||||
let FREQUENTLY_USED_COPY = { ...FREQUENTLY_USED }
|
||||
if (FREQUENTLY_USED_COPY[id]) {
|
||||
delete FREQUENTLY_USED_COPY[id]
|
||||
setFrequentlyUsedStorage(FREQUENTLY_USED_COPY)
|
||||
}
|
||||
}
|
||||
|
||||
export const removeMultiple = (ids) => {
|
||||
let FREQUENTLY_USED_COPY = { ...FREQUENTLY_USED }
|
||||
ids.forEach((id) => {
|
||||
delete FREQUENTLY_USED_COPY[id]
|
||||
})
|
||||
setFrequentlyUsedStorage(FREQUENTLY_USED_COPY)
|
||||
}
|
||||
|
||||
export const removeAll = setFrequentlyUsedStorage
|
||||
|
||||
const compareStorageWith = (packs) => {
|
||||
const stickersIDsFromPacks = packs.map((pack) => pack.stickers).flat().map((sticker) => sticker.id)
|
||||
const stickersIDsFromFrequentlyUsedStorage = get()
|
||||
|
||||
const notFound = stickersIDsFromFrequentlyUsedStorage.filter((id) => !stickersIDsFromPacks.includes(id))
|
||||
const found = stickersIDsFromFrequentlyUsedStorage.filter((id) => !notFound.includes(id))
|
||||
|
||||
return { found, notFound }
|
||||
}
|
||||
|
||||
export const removeNotFoundFromStorage = (packs) => {
|
||||
const { found, notFound } = compareStorageWith(packs)
|
||||
removeMultiple(notFound)
|
||||
return found
|
||||
}
|
||||
|
|
|
@ -47,6 +47,13 @@ const defaultState = {
|
|||
},
|
||||
}
|
||||
|
||||
const makeFrequentlyUsedState = ({ stickerIDs, stickers } = {}) => ({
|
||||
id: "frequently-used",
|
||||
title: "Frequently used",
|
||||
stickerIDs: stickerIDs ?? [],
|
||||
stickers: stickers ?? [],
|
||||
})
|
||||
|
||||
class App extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
@ -57,29 +64,26 @@ class App extends Component {
|
|||
error: null,
|
||||
stickersPerRow: parseInt(localStorage.mauStickersPerRow || "4"),
|
||||
theme: localStorage.mauStickerThemeOverride || this.defaultTheme,
|
||||
frequentlyUsed: {
|
||||
id: "frequently-used",
|
||||
title: "Frequently used",
|
||||
stickerIDs: frequent.get(),
|
||||
stickers: [],
|
||||
},
|
||||
frequentlyUsed: makeFrequentlyUsedState(),
|
||||
filtering: defaultState.filtering,
|
||||
}
|
||||
|
||||
if (!supportedThemes.includes(this.state.theme)) {
|
||||
this.state.theme = "light"
|
||||
}
|
||||
if (!supportedThemes.includes(this.defaultTheme)) {
|
||||
this.defaultTheme = "light"
|
||||
}
|
||||
this.stickersByID = new Map(JSON.parse(localStorage.mauFrequentlyUsedStickerCache || "[]"))
|
||||
this.state.frequentlyUsed.stickers = this._getStickersByID(this.state.frequentlyUsed.stickerIDs)
|
||||
|
||||
this.imageObserver = null
|
||||
this.packListRef = null
|
||||
this.navRef = null
|
||||
|
||||
this.searchStickers = this.searchStickers.bind(this)
|
||||
this.sendSticker = this.sendSticker.bind(this)
|
||||
this.navScroll = this.navScroll.bind(this)
|
||||
this.reloadPacks = this.reloadPacks.bind(this)
|
||||
this.clearFrequentlyUsed = this.clearFrequentlyUsed.bind(this)
|
||||
this.observeSectionIntersections = this.observeSectionIntersections.bind(this)
|
||||
this.observeImageIntersections = this.observeImageIntersections.bind(this)
|
||||
}
|
||||
|
@ -88,17 +92,26 @@ class App extends Component {
|
|||
return ids.map(id => this.stickersByID.get(id)).filter(sticker => !!sticker)
|
||||
}
|
||||
|
||||
_setFrequentlyUsed(stickerIDs = []) {
|
||||
const stickers = this._getStickersByID(stickerIDs)
|
||||
const frequentlyUsed = makeFrequentlyUsedState({ stickerIDs, stickers })
|
||||
this.setState({ frequentlyUsed })
|
||||
frequent.setFrequentlyUsedCacheStorage(stickers)
|
||||
}
|
||||
|
||||
updateFrequentlyUsed() {
|
||||
const stickerIDs = frequent.get()
|
||||
const stickers = this._getStickersByID(stickerIDs)
|
||||
this.setState({
|
||||
frequentlyUsed: {
|
||||
...this.state.frequentlyUsed,
|
||||
stickerIDs,
|
||||
stickers,
|
||||
},
|
||||
})
|
||||
localStorage.mauFrequentlyUsedStickerCache = JSON.stringify(stickers.map(sticker => [sticker.id, sticker]))
|
||||
this._setFrequentlyUsed(stickerIDs)
|
||||
}
|
||||
|
||||
refreshFrequentlyUsed(packs) {
|
||||
const stickerIDs = frequent.removeNotFoundFromStorage(packs)
|
||||
this._setFrequentlyUsed(stickerIDs)
|
||||
}
|
||||
|
||||
clearFrequentlyUsed() {
|
||||
frequent.removeAll()
|
||||
this._setFrequentlyUsed()
|
||||
}
|
||||
|
||||
searchStickers(e) {
|
||||
|
@ -152,6 +165,10 @@ class App extends Component {
|
|||
this._loadPacks(true)
|
||||
}
|
||||
|
||||
_initializeStickersByID(ids) {
|
||||
this.stickersByID = new Map(ids ?? [])
|
||||
}
|
||||
|
||||
async populateStickersByID(allPacks) {
|
||||
const allStickers = allPacks.map(({ stickers }) => stickers).flat()
|
||||
allStickers.forEach((sticker) => {
|
||||
|
@ -187,17 +204,18 @@ class App extends Component {
|
|||
loading: false,
|
||||
})
|
||||
this.populateStickersByID(fetchedPacks)
|
||||
this.updateFrequentlyUsed()
|
||||
this.refreshFrequentlyUsed(fetchedPacks)
|
||||
return fetchedPacks
|
||||
}, error => this.setState({ loading: false, error }))
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.documentElement.style.setProperty("--stickers-per-row", this.state.stickersPerRow.toString())
|
||||
|
||||
this._loadPacks()
|
||||
this.imageObserver = new IntersectionObserver(this.observeImageIntersections, {
|
||||
rootMargin: "100px",
|
||||
})
|
||||
this._initializeStickersByID(frequent.getFromCache())
|
||||
|
||||
this.imageObserver = new IntersectionObserver(this.observeImageIntersections, { rootMargin: "100px" })
|
||||
this.sectionObserver = new IntersectionObserver(this.observeSectionIntersections)
|
||||
}
|
||||
|
||||
|
@ -309,6 +327,7 @@ const Settings = ({ app }) => html`
|
|||
<h1>Settings</h1>
|
||||
<div class="settings-list">
|
||||
<button onClick=${app.reloadPacks}>Reload</button>
|
||||
<button onClick=${app.clearFrequentlyUsed}>Clear frequently used</button>
|
||||
<div>
|
||||
<label for="stickers-per-row">Stickers per row: ${app.state.stickersPerRow}</label>
|
||||
<input type="range" min=2 max=10 id="stickers-per-row" id="stickers-per-row"
|
||||
|
|
Loading…
Reference in a new issue