diff --git a/src/app.js b/src/app.js index 3df07c45..585f8935 100644 --- a/src/app.js +++ b/src/app.js @@ -48,6 +48,7 @@ import ModerationTab from './views/tabs/Moderation.vue'; import ChartsTab from './views/tabs/Charts.vue'; import SideBar from './views/SideBar.vue'; import NavMenu from './views/NavMenu.vue'; +import FriendsListTab from './views/tabs/FriendsList.vue'; // components import SimpleSwitch from './components/settings/SimpleSwitch.vue'; @@ -188,6 +189,7 @@ console.log(`isLinux: ${LINUX}`); // tabs ModerationTab, ChartsTab, + FriendsListTab, // - others SideBar, NavMenu, @@ -212,7 +214,12 @@ console.log(`isLinux: ${LINUX}`); getWorldName: this.getWorldName, userImage: this.userImage, userStatusClass: this.userStatusClass, - getGroupName: this.getGroupName + getGroupName: this.getGroupName, + userImageFull: this.userImageFull, + showFullscreenImageDialog: this.showFullscreenImageDialog, + statusClass: this.statusClass, + getFaviconUrl: this.getFaviconUrl, + openExternalLink: this.openExternalLink }; }, el: '#root', @@ -2964,8 +2971,6 @@ console.log(`isLinux: ${LINUX}`); } if (index === 'notification') { this.unseenNotifications = []; - } else if (index === 'friendsList') { - this.friendsListSearchChange(); } }; @@ -4311,34 +4316,6 @@ console.log(`isLinux: ${LINUX}`); $app.data.quickSearchItems = []; - var localeIncludes = function (str, search, comparer) { - // These checks are stolen from https://stackoverflow.com/a/69623589/11030436 - if (search === '') { - return true; - } else if (!str || !search) { - return false; - } - const strObj = String(str); - const searchObj = String(search); - - if (strObj.length === 0) { - return false; - } - - if (searchObj.length > strObj.length) { - return false; - } - - // Now simply loop through each substring and compare them - for (let i = 0; i < str.length - searchObj.length + 1; i++) { - const substr = strObj.substring(i, i + searchObj.length); - if (comparer.compare(substr, searchObj) === 0) { - return true; - } - } - return false; - }; - // Making a persistent comparer increases perf by like 10x lmao $app.data._stringComparer = undefined; $app.computed.stringComparer = function () { @@ -4365,14 +4342,14 @@ console.log(`isLinux: ${LINUX}`); } const cleanName = removeConfusables(ctx.name); - let match = localeIncludes( + let match = $utils.localeIncludes( cleanName, cleanQuery, this.stringComparer ); if (!match) { // Also check regular name in case search is with special characters - match = localeIncludes( + match = $utils.localeIncludes( ctx.name, cleanQuery, this.stringComparer @@ -4381,10 +4358,14 @@ console.log(`isLinux: ${LINUX}`); // Use query with whitespace for notes and memos as people are more // likely to include spaces in memos and notes if (!match && ctx.memo) { - match = localeIncludes(ctx.memo, query, this.stringComparer); + match = $utils.localeIncludes( + ctx.memo, + query, + this.stringComparer + ); } if (!match && ctx.ref.note) { - match = localeIncludes( + match = $utils.localeIncludes( ctx.ref.note, query, this.stringComparer @@ -6988,23 +6969,6 @@ console.log(`isLinux: ${LINUX}`); layout: 'table', visible: false }; - $app.data.friendsListTable = { - data: [], - tableProps: { - stripe: true, - size: 'mini', - defaultSort: { - prop: '$friendNumber', - order: 'descending' - } - }, - pageSize: 100, - paginationProps: { - small: true, - layout: 'sizes,prev,pager,next,total', - pageSizes: [50, 100, 250, 500] - } - }; $app.data.socialStatusHistoryTable = { data: [], tableProps: { @@ -14225,80 +14189,8 @@ console.log(`isLinux: ${LINUX}`); // #endregion // #region | App: Friends List - API.$on('LOGIN', function () { - $app.friendsListTable.data = []; - }); - - $app.methods.selectFriendsListRow = function (val) { - if (val === null) { - return; - } - if (!val.id) { - this.lookupUser(val); - return; - } - this.showUserDialog(val.id); - }; - $app.data.friendsListSearch = ''; - $app.data.friendsListSearchFilterVIP = false; - $app.data.friendsListSearchFilters = []; - $app.data.friendsListSelectAllCheckbox = false; - $app.data.friendsListBulkUnfriendMode = false; - $app.data.friendsListBulkUnfriendForceUpdate = 0; - - $app.methods.toggleFriendsListBulkUnfriendMode = function () { - if (!this.friendsListBulkUnfriendMode) { - this.friendsListTable.data.forEach((ref) => { - ref.$selected = false; - }); - } - }; - - $app.methods.showBulkUnfriendSelectionConfirm = function () { - var pendingUnfriendList = this.friendsListTable.data.reduce( - (acc, ctx) => { - if (ctx.$selected) { - acc.push(ctx.displayName); - } - return acc; - }, - [] - ); - var elementsTicked = pendingUnfriendList.length; - if (elementsTicked === 0) { - return; - } - this.$confirm( - `Are you sure you want to delete ${elementsTicked} friends? - This can negatively affect your trust rank, - This action cannot be undone.`, - `Delete ${elementsTicked} friends?`, - { - confirmButtonText: 'Confirm', - cancelButtonText: 'Cancel', - type: 'info', - showInput: true, - inputType: 'textarea', - inputValue: pendingUnfriendList.join('\r\n'), - callback: (action) => { - if (action === 'confirm') { - this.bulkUnfriendSelection(); - } - } - } - ); - }; - - $app.methods.bulkUnfriendSelection = function () { - for (var ctx of this.friendsListTable.data) { - if (ctx.$selected) { - friendRequest.deleteFriend({ - userId: ctx.id - }); - } - } - }; + // $app.data.friendsListSelectAllCheckbox = false; // $app.methods.showBulkUnfriendAllConfirm = function () { // this.$confirm( @@ -14327,91 +14219,6 @@ console.log(`isLinux: ${LINUX}`); // } // }; - $app.methods.friendsListSearchChange = function () { - let query; - let cleanedQuery; - this.friendsListTable.data = []; - let filters = [...this.friendsListSearchFilters]; - if (filters.length === 0) { - filters = ['Display Name', 'Rank', 'Status', 'Bio', 'Memo']; - } - const results = []; - if (this.friendsListSearch) { - query = this.friendsListSearch; - cleanedQuery = removeWhitespace(query); - } - - for (const ctx of this.friends.values()) { - if (typeof ctx.ref === 'undefined') { - continue; - } - if (typeof ctx.ref.$selected === 'undefined') { - ctx.ref.$selected = false; - } - if (this.friendsListSearchFilterVIP && !ctx.isVIP) { - continue; - } - if (query && filters) { - let match = false; - if ( - !match && - filters.includes('Display Name') && - ctx.ref.displayName - ) { - match = - localeIncludes( - ctx.ref.displayName, - cleanedQuery, - this.stringComparer - ) || - localeIncludes( - removeConfusables(ctx.ref.displayName), - cleanedQuery, - this.stringComparer - ); - } - if (!match && filters.includes('Memo') && ctx.memo) { - match = localeIncludes( - ctx.memo, - query, - this.stringComparer - ); - } - if (!match && filters.includes('Bio') && ctx.ref.bio) { - match = localeIncludes( - ctx.ref.bio, - query, - this.stringComparer - ); - } - if ( - !match && - filters.includes('Status') && - ctx.ref.statusDescription - ) { - match = localeIncludes( - ctx.ref.statusDescription, - query, - this.stringComparer - ); - } - if (!match && filters.includes('Rank')) { - match = String(ctx.ref.$trustLevel) - .toUpperCase() - .includes(query.toUpperCase()); - } - if (!match) { - continue; - } - } - results.push(ctx.ref); - } - this.getAllUserStats(); - requestAnimationFrame(() => { - this.friendsListTable.data = results; - }); - }; - $app.methods.getAllUserStats = async function () { var userIds = []; var displayNames = []; @@ -14481,60 +14288,6 @@ console.log(`isLinux: ${LINUX}`); /* eslint-enable require-atomic-updates */ }; - $app.watch.friendsListSearch = $app.methods.friendsListSearchChange; - $app.data.friendsListLoading = false; - $app.data.friendsListLoadingProgress = ''; - - $app.methods.friendsListLoadUsers = async function () { - this.friendsListLoading = true; - var i = 0; - var toFetch = []; - for (var ctx of this.friends.values()) { - if (ctx.ref && !ctx.ref.date_joined) { - toFetch.push(ctx.id); - } - } - var length = toFetch.length; - for (var userId of toFetch) { - if (!this.friendsListLoading) { - this.friendsListLoadingProgress = ''; - return; - } - i++; - this.friendsListLoadingProgress = `${i}/${length}`; - try { - await userRequest.getUser({ - userId - }); - } catch (err) { - console.error(err); - } - } - this.friendsListLoadingProgress = ''; - this.friendsListLoading = false; - }; - - $app.methods.sortAlphabetically = function (a, b, field) { - if (!a[field] || !b[field]) { - return 0; - } - return a[field].toLowerCase().localeCompare(b[field].toLowerCase()); - }; - - $app.methods.sortLanguages = function (a, b) { - var sortedA = []; - var sortedB = []; - a.$languages.forEach((item) => { - sortedA.push(item.value); - }); - b.$languages.forEach((item) => { - sortedB.push(item.value); - }); - sortedA.sort(); - sortedB.sort(); - return JSON.stringify(sortedA).localeCompare(JSON.stringify(sortedB)); - }; - $app.methods.genMd5 = async function (file) { var response = await AppApi.MD5File(file); return response; diff --git a/src/app.pug b/src/app.pug index 06d4054b..e806957f 100644 --- a/src/app.pug +++ b/src/app.pug @@ -67,8 +67,18 @@ doctype html +profileTab //- friends list - include ./mixins/tabs/friendsList.pug - +friendsListTab + friends-list-tab( + :menu-active-index='menuActiveIndex' + :friends='friends' + :hide-tooltips='hideTooltips' + :random-user-colours='randomUserColours' + :sort-status='sortStatus' + :language-class='languageClass' + :confirm-delete-friend='confirmDeleteFriend' + :friends-list-search.sync='friendsListSearch' + @get-all-user-stats='getAllUserStats' + @lookup-user='lookupUser' + :string-comparer='stringComparer') //- charts keep-alive diff --git a/src/app.scss b/src/app.scss index bac8279d..97f88b89 100644 --- a/src/app.scss +++ b/src/app.scss @@ -106,10 +106,6 @@ -webkit-line-clamp: 2; } -.el-table__row:hover .el-table__cell .cell { - -webkit-line-clamp: unset; -} - .el-dialog__body { padding: 20px; word-break: break-word; diff --git a/src/classes/utils.js b/src/classes/utils.js index 251c9c22..814fbeba 100644 --- a/src/classes/utils.js +++ b/src/classes/utils.js @@ -375,5 +375,32 @@ export default { .join(', '); document.body.style.fontFamily = `${CJKFamily}, ${otherFonts}`; } + }, + localeIncludes(str, search, comparer) { + // These checks are stolen from https://stackoverflow.com/a/69623589/11030436 + if (search === '') { + return true; + } else if (!str || !search) { + return false; + } + const strObj = String(str); + const searchObj = String(search); + + if (strObj.length === 0) { + return false; + } + + if (searchObj.length > strObj.length) { + return false; + } + + // Now simply loop through each substring and compare them + for (let i = 0; i < str.length - searchObj.length + 1; i++) { + const substr = strObj.substring(i, i + searchObj.length); + if (comparer.compare(substr, searchObj) === 0) { + return true; + } + } + return false; } }; diff --git a/src/mixins/tabs/friendsList.pug b/src/mixins/tabs/friendsList.pug deleted file mode 100644 index 9d656a4e..00000000 --- a/src/mixins/tabs/friendsList.pug +++ /dev/null @@ -1,194 +0,0 @@ -mixin friendsListTab - .x-container(v-show='menuActiveIndex === "friendsList"') - div(style='padding: 0px 10px 0px 10px') - span.header {{ $t('view.friend_list.header') }} - div(style='float: right; font-size: 13px') - div(v-if='friendsListBulkUnfriendMode' style='display: inline-block; margin-right: 10px') - el-button(size='small' @click='showBulkUnfriendSelectionConfirm') {{ $t('view.friend_list.bulk_unfriend_selection') }} - //- el-button(size="small" @click="showBulkUnfriendAllConfirm" style="margin-right:5px") Bulk Unfriend All - div(style='display: inline-block; margin-right: 10px') - span.name {{ $t('view.friend_list.bulk_unfriend') }} - el-switch( - @change='toggleFriendsListBulkUnfriendMode' - v-model='friendsListBulkUnfriendMode' - style='margin-left: 5px') - span {{ $t('view.friend_list.load') }} - template(v-if='friendsListLoading') - span(v-text='friendsListLoadingProgress' style='margin-left: 5px') - el-tooltip( - placement='top' - :content='$t("view.friend_list.cancel_tooltip")' - :disabled='hideTooltips') - el-button( - @click='friendsListLoading = false' - size='mini' - icon='el-icon-loading' - circle - style='margin-left: 5px') - template(v-else) - el-tooltip(placement='top' :content='$t("view.friend_list.load_tooltip")' :disabled='hideTooltips') - el-button( - @click='friendsListLoadUsers' - size='mini' - icon='el-icon-refresh-left' - circle - style='margin-left: 5px') - div(style='margin: 10px 0 0 10px; display: flex; align-items: center') - div(style='flex: none; margin-right: 10px; display: flex; align-items: center') - el-tooltip( - placement='bottom' - :content='$t("view.friend_list.favorites_only_tooltip")' - :disabled='hideTooltips') - el-switch( - v-model='friendsListSearchFilterVIP' - @change='friendsListSearchChange' - active-color='#13ce66') - el-input( - v-model='friendsListSearch' - :placeholder='$t("view.friend_list.search_placeholder")' - @change='friendsListSearchChange' - clearable - style='flex: 1') - el-select( - v-model='friendsListSearchFilters' - multiple - clearable - collapse-tags - style='flex: none; width: 200px; margin: 0 10px' - @change='friendsListSearchChange' - :placeholder='$t("view.friend_list.filter_placeholder")') - el-option( - v-for='type in ["Display Name", "User Name", "Rank", "Status", "Bio", "Memo"]' - :key='type' - :label='type' - :value='type') - el-tooltip(placement='top' :content='$t("view.friend_list.refresh_tooltip")' :disabled='hideTooltips') - el-button( - type='default' - @click='friendsListSearchChange' - icon='el-icon-refresh' - circle - style='flex: none') - data-tables( - v-bind='friendsListTable' - @row-click='selectFriendsListRow' - :table-props='{ height: "calc(100vh - 170px)", size: "mini" }' - style='margin-top: 10px; cursor: pointer') - el-table-column( - width='55' - prop='$selected' - v-if='friendsListBulkUnfriendMode' - :key='friendsListBulkUnfriendForceUpdate') - template(#default='scope') - el-button(type='text' size='mini' @click.stop) - el-checkbox(v-model='scope.row.$selected' @change='friendsListBulkUnfriendForceUpdate++') - el-table-column(:label='$t("table.friendList.no")' width='70' prop='$friendNumber' sortable='custom') - template(#default='scope') - span {{ scope.row.$friendNumber ? scope.row.$friendNumber : '' }} - el-table-column(:label='$t("table.friendList.avatar")' width='70' prop='photo') - template(#default='scope') - el-popover(placement='right' height='500px' trigger='hover') - img.friends-list-avatar(slot='reference' v-lazy='userImage(scope.row)') - img.friends-list-avatar( - v-lazy='userImageFull(scope.row)' - style='height: 500px; cursor: pointer' - @click='showFullscreenImageDialog(userImageFull(scope.row))') - el-table-column( - :label='$t("table.friendList.displayName")' - min-width='140' - prop='displayName' - sortable - :sort-method='(a, b) => sortAlphabetically(a, b, "displayName")') - template(#default='scope') - span.name( - v-if='randomUserColours' - v-text='scope.row.displayName' - :style='{ color: scope.row.$userColour }') - span.name(v-else v-text='scope.row.displayName') - el-table-column( - :label='$t("table.friendList.rank")' - width='110' - prop='$trustSortNum' - sortable='custom') - template(#default='scope') - span.name( - v-if='randomUserColours' - v-text='scope.row.$trustLevel' - :class='scope.row.$trustClass') - span.name(v-else v-text='scope.row.$trustLevel' :style='{ color: scope.row.$userColour }') - el-table-column( - :label='$t("table.friendList.status")' - min-width='180' - prop='status' - sortable - :sort-method='(a, b) => sortStatus(a.status, b.status)') - template(#default='scope') - i.x-user-status( - v-if='scope.row.status !== "offline"' - :class='statusClass(scope.row.status)' - style='margin-right: 3px') - span(v-text='scope.row.statusDescription') - el-table-column( - :label='$t("table.friendList.language")' - width='110' - prop='$languages' - sortable - :sort-method='(a, b) => sortLanguages(a, b)') - template(#default='scope') - el-tooltip(v-for='item in scope.row.$languages' :key='item.key' placement='top') - template(#content) - span {{ item.value }} ({{ item.key }}) - span.flags( - :class='languageClass(item.key)' - style='display: inline-block; margin-right: 5px') - el-table-column(:label='$t("table.friendList.bioLink")' width='100' prop='bioLinks') - template(#default='scope') - el-tooltip(v-if='link' v-for='(link, index) in scope.row.bioLinks' :key='index') - template(#content) - span(v-text='link') - img( - :src='getFaviconUrl(link)' - style='width: 16px; height: 16px; vertical-align: middle; margin-right: 5px; cursor: pointer' - @click.stop='openExternalLink(link)') - el-table-column(:label='$t("table.friendList.joinCount")' width='120' prop='$joinCount' sortable) - el-table-column(:label='$t("table.friendList.timeTogether")' width='140' prop='$timeSpent' sortable) - template(#default='scope') - span(v-if='scope.row.$timeSpent') {{ timeToText(scope.row.$timeSpent) }} - el-table-column( - :label='$t("table.friendList.lastSeen")' - width='170' - prop='$lastSeen' - sortable - :sort-method='(a, b) => sortAlphabetically(a, b, "$lastSeen")') - template(#default='scope') - span {{ scope.row.$lastSeen | formatDate('long') }} - el-table-column( - :label='$t("table.friendList.lastActivity")' - width='170' - prop='last_activity' - sortable - :sort-method='(a, b) => sortAlphabetically(a, b, "last_activity")') - template(#default='scope') - span {{ scope.row.last_activity | formatDate('long') }} - el-table-column( - :label='$t("table.friendList.lastLogin")' - width='170' - prop='last_login' - sortable - :sort-method='(a, b) => sortAlphabetically(a, b, "last_login")') - template(#default='scope') - span {{ scope.row.last_login | formatDate('long') }} - el-table-column( - :label='$t("table.friendList.dateJoined")' - width='120' - prop='date_joined' - sortable - :sort-method='(a, b) => sortAlphabetically(a, b, "date_joined")') - el-table-column(:label='$t("table.friendList.unfriend")' width='100' align='center') - template(#default='scope') - el-button( - type='text' - icon='el-icon-close' - style='color: #f56c6c' - size='mini' - @click.stop='confirmDeleteFriend(scope.row.id)') diff --git a/src/views/dialogs/WorldDialog.vue b/src/views/dialogs/WorldDialog.vue index 68e7b025..22111382 100644 --- a/src/views/dialogs/WorldDialog.vue +++ b/src/views/dialogs/WorldDialog.vue @@ -70,14 +70,14 @@ effect="plain" size="mini" style="margin-right: 5px; margin-top: 5px"> - PC + PC + {{ worldDialog.bundleSizes['standalonewindows'].fileSize }} + - - {{ worldDialog.bundleSizes['standalonewindows'].fileSize }} - + - Android + Android + {{ worldDialog.bundleSizes['android'].fileSize }} + - - {{ worldDialog.bundleSizes['android'].fileSize }} - + - iOS + iOS + {{ worldDialog.bundleSizes['ios'].fileSize }} + - - {{ worldDialog.bundleSizes['ios'].fileSize }} - + + + + + {{ $t('view.friend_list.header') }} + + + + {{ $t('view.friend_list.bulk_unfriend_selection') }} + + + + + {{ $t('view.friend_list.bulk_unfriend') }} + + + {{ $t('view.friend_list.load') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ scope.row.$friendNumber ? scope.row.$friendNumber : '' }} + + + + + + + + + + + + + {{ + scope.row.displayName + }} + + + + + + + + + + + + + + + + + + + {{ item.value }} ({{ item.key }}) + + + + + + + + + + + + + + + + + + + {{ timeToText(scope.row.$timeSpent) }} + + + + + {{ scope.row.$lastSeen | formatDate('long') }} + + + + + {{ scope.row.last_activity | formatDate('long') }} + + + + + {{ scope.row.last_login | formatDate('long') }} + + + + + + + + + + + + + +