From e45410191cbc89a0acdf9a0b47ccc41a0870a6b2 Mon Sep 17 00:00:00 2001 From: Natsumi Date: Fri, 12 Aug 2022 00:26:19 +1200 Subject: [PATCH] Local avatar history --- html/src/app.js | 71 ++++++++++++++++++++++++++++++++- html/src/index.pug | 20 ++++++++++ html/src/repository/database.js | 64 +++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 1 deletion(-) diff --git a/html/src/app.js b/html/src/app.js index 607f2212..8c7b1a61 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -1255,6 +1255,9 @@ speechSynthesis.getVoices(); API.applyCurrentUser = function (json) { var ref = this.currentUser; if (this.isLoggedIn) { + if (json.currentAvatar !== ref.currentAvatar) { + $app.addAvatarToHistory(json.currentAvatar); + } Object.assign(ref, json); if (ref.homeLocation !== ref.$homeLocation.tag) { ref.$homeLocation = this.parseLocation(ref.homeLocation); @@ -18949,7 +18952,8 @@ speechSynthesis.getVoices(); API.cachedAvatars.forEach((ref, id) => { if ( !API.cachedFavoritesByObjectId.has(id) && - ref.authorId !== API.currentUser.id + ref.authorId !== API.currentUser.id && + !$app.avatarHistory.has(id) ) { API.cachedAvatars.delete(id); } @@ -19660,6 +19664,71 @@ speechSynthesis.getVoices(); API.currentUser.$travelingToTime = this.lastLocationDestinationTime; }; + $app.data.avatarHistory = new Set(); + $app.data.avatarHistoryArray = []; + + API.$on('LOGIN', async function () { + $app.avatarHistory = new Set(); + var historyArray = await database.getAvatarHistory(); + $app.avatarHistoryArray = historyArray; + for (var i = 0; i < historyArray.length; i++) { + $app.avatarHistory.add(historyArray[i].id); + this.applyAvatar(historyArray[i]); + } + }); + + $app.methods.addAvatarToHistory = function (avatarId) { + var historyArray = $app.avatarHistoryArray; + for (var i = 0; i < historyArray.length; ++i) { + if (historyArray[i].id === avatarId) { + historyArray.splice(i, 1); + } + } + this.avatarHistory.delete(avatarId); + this.avatarHistory.add(avatarId); + database.addAvatarToHistory(avatarId); + API.getAvatar({avatarId}); + }; + + API.$on('AVATAR', function (args) { + var ref = args.json; + // if in history add/update cache + if ($app.avatarHistory.has(ref.id)) { + database.addAvatarToCache(ref); + + // only add to array if not in array + var inArray = false; + var historyArray = $app.avatarHistoryArray; + for (var i = 0; i < historyArray.length; ++i) { + if (historyArray[i].id === ref.id) { + inArray = true; + } + } + if (!inArray) { + $app.avatarHistoryArray.unshift(ref); + } + } + }); + + $app.methods.promptClearAvatarHistory = function () { + this.$confirm('Continue? Clear Avatar History', 'Confirm', { + confirmButtonText: 'Confirm', + cancelButtonText: 'Cancel', + type: 'info', + callback: (action) => { + if (action === 'confirm') { + this.clearAvatarHistory(); + } + } + }); + }; + + $app.methods.clearAvatarHistory = function () { + this.avatarHistory = new Set(); + this.avatarHistoryArray = []; + database.clearAvatarHistory(); + }; + $app = new Vue($app); window.$app = $app; })(); diff --git a/html/src/index.pug b/html/src/index.pug index b96ef683..b625faa6 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -603,6 +603,26 @@ html .detail span.name(v-text="favorite.name || favorite.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="deleteFavorite(favorite.id)" style="margin-left:5px") + el-collapse-item + template(slot="title") + span(style="font-weight:bold;font-size:14px;margin-left:10px") Local History + span(style="color:#909399;font-size:12px;margin-left:10px") {{ avatarHistoryArray.length }}/100 + el-tooltip(placement="right" content="Clear" :disabled="hideTooltips") + el-button(@click.stop="promptClearAvatarHistory" size="mini" icon="el-icon-delete" circle style="margin-left:5px") + .x-friend-list(v-if="avatarHistoryArray.length" style="margin-top:10px") + div(style="display:inline-block;width:300px;margin-right:15px" v-for="favorite in avatarHistoryArray" :key="favorite.id" @click="showAvatarDialog(favorite.id)") + .x-friend-item + .avatar + img(v-lazy="favorite.thumbnailImageUrl") + .detail + span.name(v-text="favorite.name") + span.extra(v-text="favorite.authorName") + template(v-if="API.cachedFavoritesByObjectId.has(favorite.id)") + el-tooltip(placement="left" content="Unfavorite" :disabled="hideTooltips") + el-button(@click.stop="deleteFavorite(favorite.id)" type="default" icon="el-icon-star-on" size="mini" circle) + template(v-else) + el-tooltip(placement="left" content="Favorite" :disabled="hideTooltips") + el-button(@click.stop="showFavoriteDialog('avatar', favorite.id)" type="default" icon="el-icon-star-off" size="mini" circle) //- friendLog .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'friendLog'" v-if="$refs.menu && $refs.menu.activeIndex === 'friendLog'") diff --git a/html/src/repository/database.js b/html/src/repository/database.js index 568cc201..f63a47f6 100644 --- a/html/src/repository/database.js +++ b/html/src/repository/database.js @@ -32,6 +32,9 @@ class Database { await sqliteService.executeNonQuery( `CREATE TABLE IF NOT EXISTS ${Database.userPrefix}_moderation (user_id TEXT PRIMARY KEY, updated_at TEXT, display_name TEXT, block INTEGER, mute INTEGER)` ); + await sqliteService.executeNonQuery( + `CREATE TABLE IF NOT EXISTS ${Database.userPrefix}_avatar_history (avatar_id TEXT PRIMARY KEY, created_at TEXT)` + ); await sqliteService.executeNonQuery( `CREATE TABLE IF NOT EXISTS memos (user_id TEXT PRIMARY KEY, edited_at TEXT, memo TEXT)` ); @@ -53,6 +56,9 @@ class Database { await sqliteService.executeNonQuery( `CREATE TABLE IF NOT EXISTS gamelog_event (id INTEGER PRIMARY KEY, created_at TEXT, data TEXT, UNIQUE(created_at, data))` ); + await sqliteService.executeNonQuery( + `CREATE TABLE IF NOT EXISTS cache_avatar (id TEXT PRIMARY KEY, added_at TEXT, author_id TEXT, author_name TEXT, created_at TEXT, description TEXT, image_url TEXT, name TEXT, release_status TEXT, thumbnail_image_url TEXT, updated_at TEXT, version INTEGER)` + ); } async getFeedDatabase() { @@ -1426,6 +1432,64 @@ class Database { AND ((trust_level = 'Veteran User' AND previous_trust_level = 'Trusted User') OR (trust_level = 'Trusted User' AND previous_trust_level = 'Veteran User'))` ); } + + addAvatarToCache(entry) { + sqliteService.executeNonQuery( + `INSERT OR REPLACE INTO cache_avatar (id, added_at, author_id, author_name, created_at, description, image_url, name, release_status, thumbnail_image_url, updated_at, version) VALUES (@id, @added_at, @author_id, @author_name, @created_at, @description, @image_url, @name, @release_status, @thumbnail_image_url, @updated_at, @version)`, + { + '@id': entry.id, + '@added_at': new Date().toJSON(), + '@author_id': entry.authorId, + '@author_name': entry.authorName, + '@created_at': entry.created_at, + '@description': entry.description, + '@image_url': entry.imageUrl, + '@name': entry.name, + '@release_status': entry.releaseStatus, + '@thumbnail_image_url': entry.thumbnailImageUrl, + '@updated_at': entry.updated_at, + '@version': entry.version + } + ); + } + + addAvatarToHistory(avatarId) { + sqliteService.executeNonQuery( + `INSERT OR REPLACE INTO ${Database.userPrefix}_avatar_history (avatar_id, created_at) VALUES (@avatar_id, @created_at)`, + { + '@avatar_id': avatarId, + '@created_at': new Date().toJSON() + } + ); + } + + async getAvatarHistory() { + var data = []; + await sqliteService.execute((dbRow) => { + var row = { + id: dbRow[0], + authorId: dbRow[4], + authorName: dbRow[5], + created_at: dbRow[6], + description: dbRow[7], + imageUrl: dbRow[8], + name: dbRow[9], + releaseStatus: dbRow[10], + thumbnailImageUrl: dbRow[11], + updated_at: dbRow[12], + version: dbRow[13] + }; + data.unshift(row); + }, `SELECT * FROM ${Database.userPrefix}_avatar_history INNER JOIN cache_avatar ON cache_avatar.id = ${Database.userPrefix}_avatar_history.avatar_id LIMIT 100`); + return data; + } + + clearAvatarHistory() { + sqliteService.executeNonQuery( + `DELETE FROM ${Database.userPrefix}_avatar_history` + ); + sqliteService.executeNonQuery('DELETE FROM cache_avatar'); + } } var self = new Database();