fchat-rising/chat/UserView.vue

286 lines
8.2 KiB
Vue
Raw Permalink Normal View History

2019-07-15 16:59:16 +00:00
<!-- Linebreaks inside this template will break BBCode views -->
2023-03-30 00:23:54 +00:00
<template><span :class="userClass" v-bind:bbcodeTag.prop="'user'" v-bind:character.prop="character" v-bind:channel.prop="channel" @mouseover.prevent="show()" @mouseenter.prevent="show()" @mouseleave.prevent="dismiss()" @click.middle.prevent.stop="toggleStickyness()" @click.right.passive="dismiss(true)" @click.left.passive="dismiss(true)"><img v-if="!!avatar" :src="avatarUrl" class="user-avatar" /><span v-if="!!statusClass" :class="statusClass"></span><span v-if="!!rankIcon" :class="rankIcon"></span><span v-if="!!smartFilterIcon" :class="smartFilterIcon"></span>{{character.name}}<span v-if="!!matchClass" :class="matchClass">{{getMatchScoreTitle(matchScore)}}</span></span></template>
2019-07-15 16:59:16 +00:00
<script lang="ts">
import { Component, Hook, Prop, Watch } from '@f-list/vue-ts';
2019-07-15 16:59:16 +00:00
import Vue from 'vue';
import {Channel, Character} from '../fchat';
2021-03-25 20:53:37 +00:00
import { Score } from '../learn/matcher';
2019-07-15 16:59:16 +00:00
import core from './core';
2020-03-15 16:23:39 +00:00
import { EventBus } from './preview/event-bus';
2021-03-25 20:53:37 +00:00
import { kinkMatchWeights, Scoring } from '../learn/matcher-types';
2023-03-30 00:23:54 +00:00
import { characterImage } from './common';
2019-07-15 16:59:16 +00:00
export function getStatusIcon(status: Character.Status): string {
switch(status) {
case 'online':
return 'far fa-user';
case 'looking':
return 'fa fa-eye';
case 'dnd':
return 'fa fa-minus-circle';
case 'offline':
return 'fa fa-ban';
case 'away':
return 'far fa-circle';
case 'busy':
return 'fa fa-cog';
case 'idle':
return 'far fa-clock';
case 'crown':
return 'fa fa-birthday-cake';
}
}
2020-10-25 22:55:21 +00:00
export interface StatusClasses {
rankIcon: string | null;
2022-01-02 22:37:57 +00:00
smartFilterIcon: string | null;
2020-10-25 22:55:21 +00:00
statusClass: string | null;
matchClass: string | null;
2020-11-21 20:41:08 +00:00
matchScore: number | string | null;
2020-10-25 22:55:21 +00:00
userClass: string;
isBookmark: boolean;
}
export function getStatusClasses(
character: Character,
channel: Channel | undefined,
showStatus: boolean,
showBookmark: boolean,
showMatch: boolean
): StatusClasses {
let rankIcon: string | null = null;
let statusClass = null;
let matchClass = null;
let matchScore = null;
2022-01-02 22:37:57 +00:00
let smartFilterIcon: string | null = null;
2020-10-25 22:55:21 +00:00
if(character.isChatOp) {
rankIcon = 'far fa-gem';
} else if(channel !== undefined) {
rankIcon = (channel.owner === character.name)
? 'fa fa-key'
: channel.opList.indexOf(character.name) !== -1
? (channel.id.substr(0, 4) === 'adh-' ? 'fa fa-shield-alt' : 'fa fa-star')
: null;
}
if ((showStatus) || (character.status === 'crown'))
statusClass = `fa-fw ${getStatusIcon(character.status)}`;
2022-01-03 18:09:42 +00:00
const cache = (((showMatch) && (core.state.settings.risingAdScore)) || (core.state.settings.risingFilter.showFilterIcon))
2022-01-02 22:37:57 +00:00
? core.cache.profileCache.getSync(character.name)
: undefined;
2020-10-25 22:55:21 +00:00
2022-01-02 22:37:57 +00:00
// undefined == not interested
// null == no cache hit
2022-01-03 18:09:42 +00:00
if ((cache === null) && (showMatch)) {
2022-01-02 22:37:57 +00:00
void core.cache.addProfile(character.name);
}
if ((core.state.settings.risingAdScore) && (showMatch) && (cache)) {
if ((cache.match.searchScore >= kinkMatchWeights.unicornThreshold) && (cache.match.matchScore === Scoring.MATCH)) {
matchClass = 'match-found unicorn';
matchScore = 'unicorn';
2020-10-25 22:55:21 +00:00
} else {
2022-01-02 22:37:57 +00:00
matchClass = `match-found ${Score.getClasses(cache.match.matchScore)}`;
matchScore = cache.match.matchScore;
2020-10-25 22:55:21 +00:00
}
}
2022-01-02 22:37:57 +00:00
if (core.state.settings.risingFilter.showFilterIcon && cache?.match.isFiltered) {
smartFilterIcon = 'user-filter fas fa-filter';
}
2024-01-27 03:45:59 +00:00
const baseGender = character.overrides.gender || character.gender;
const gender = baseGender !== undefined ? baseGender.toLowerCase() : 'none';
2020-10-25 22:55:21 +00:00
const isBookmark = (showBookmark) && (core.connection.isOpen) && (core.state.settings.colorBookmarks) &&
((character.isFriend) || (character.isBookmarked));
const userClass = `user-view gender-${gender}${isBookmark ? ' user-bookmark' : ''}`;
return {
2021-02-01 18:16:30 +00:00
rankIcon: rankIcon ? `user-rank ${rankIcon}` : null,
statusClass: statusClass ? `user-status ${statusClass}` : null,
2020-10-25 22:55:21 +00:00
matchClass,
matchScore,
userClass,
2022-01-02 22:37:57 +00:00
smartFilterIcon,
2020-10-25 22:55:21 +00:00
isBookmark
};
}
2019-07-15 16:59:16 +00:00
@Component({
components: {
}
})
export default class UserView extends Vue {
@Prop({required: true})
readonly character!: Character;
@Prop()
readonly channel?: Channel;
@Prop()
readonly showStatus?: boolean = true;
2021-01-31 00:46:27 +00:00
@Prop({default: true})
readonly bookmark?: boolean = true;
2019-07-15 16:59:16 +00:00
@Prop()
readonly match?: boolean = false;
2020-10-25 22:55:21 +00:00
@Prop({default: true})
readonly preview: boolean = true;
2023-03-30 00:23:54 +00:00
@Prop({default: false})
readonly avatar: boolean = false;
2019-07-15 16:59:16 +00:00
userClass = '';
rankIcon: string | null = null;
2022-01-02 22:37:57 +00:00
smartFilterIcon: string | null = null;
2019-07-15 16:59:16 +00:00
statusClass: string | null = null;
matchClass: string | null = null;
2020-11-21 20:41:08 +00:00
matchScore: number | string | null = null;
2023-03-30 00:23:54 +00:00
avatarUrl: string | null = null;
2019-07-15 16:59:16 +00:00
// tslint:disable-next-line no-any
scoreWatcher: ((event: any) => void) | null = null;
@Hook('mounted')
onMounted(): void {
this.update();
if ((this.match) && (!this.matchClass)) {
if (this.scoreWatcher) {
EventBus.$off('character-score', this.scoreWatcher);
}
// tslint:disable-next-line no-unsafe-any no-any
this.scoreWatcher = (event: any): void => {
2019-07-30 01:32:33 +00:00
// console.log('scoreWatcher', event);
2019-07-15 16:59:16 +00:00
// tslint:disable-next-line no-unsafe-any no-any
2019-07-30 01:32:33 +00:00
if ((event.character) && (event.character.character.name === this.character.name)) {
2019-07-15 16:59:16 +00:00
this.update();
if (this.scoreWatcher) {
EventBus.$off('character-score', this.scoreWatcher);
this.scoreWatcher = null;
2019-07-15 16:59:16 +00:00
}
}
};
EventBus.$on(
'character-score',
this.scoreWatcher
);
}
}
@Hook('beforeDestroy')
onBeforeDestroy(): void {
if (this.scoreWatcher)
EventBus.$off('character-score', this.scoreWatcher);
2020-10-25 22:55:21 +00:00
this.dismiss();
2019-07-15 16:59:16 +00:00
}
2020-10-25 22:55:21 +00:00
@Hook('deactivated')
deactivate(): void {
this.dismiss();
}
2019-07-15 16:59:16 +00:00
@Hook('beforeUpdate')
onBeforeUpdate(): void {
this.update();
}
@Watch('character.status')
onStatusUpdate(): void {
this.update();
}
2019-07-15 16:59:16 +00:00
2024-01-27 03:45:59 +00:00
@Watch('character.overrides.avatarUrl')
onAvatarUrlUpdate(): void {
this.update();
}
2019-07-15 16:59:16 +00:00
update(): void {
2021-01-24 04:45:31 +00:00
// console.log('user.view.update', this.character.name);
2020-10-25 22:55:21 +00:00
const res = getStatusClasses(this.character, this.channel, !!this.showStatus, !!this.bookmark, !!this.match);
2019-07-15 16:59:16 +00:00
2020-10-25 22:55:21 +00:00
this.rankIcon = res.rankIcon;
2022-01-02 22:37:57 +00:00
this.smartFilterIcon = res.smartFilterIcon;
2020-10-25 22:55:21 +00:00
this.statusClass = res.statusClass;
this.matchClass = res.matchClass;
this.matchScore = res.matchScore;
this.userClass = res.userClass;
2024-01-27 03:45:59 +00:00
this.avatarUrl = this.character.overrides.avatarUrl || characterImage(this.character.name);
2019-07-15 16:59:16 +00:00
}
2020-11-21 20:41:08 +00:00
getMatchScoreTitle(score: number | string | null): string {
2019-07-15 16:59:16 +00:00
switch (score) {
2020-11-21 20:41:08 +00:00
case 'unicorn':
return 'Unicorn';
2019-07-15 16:59:16 +00:00
case Scoring.MATCH:
return 'Great';
case Scoring.WEAK_MATCH:
return 'Good';
case Scoring.WEAK_MISMATCH:
return 'Maybe';
case Scoring.MISMATCH:
return 'No';
}
return '';
}
2020-10-25 22:55:21 +00:00
getCharacterUrl(): string {
return `flist-character://${this.character.name}`;
}
2019-07-15 16:59:16 +00:00
2020-10-25 22:55:21 +00:00
dismiss(force: boolean = false): void {
if (!this.preview) {
return;
}
2019-07-15 16:59:16 +00:00
2020-10-25 22:55:21 +00:00
EventBus.$emit('imagepreview-dismiss', {url: this.getCharacterUrl(), force});
}
show(): void {
if (!this.preview) {
return;
2019-07-15 16:59:16 +00:00
}
2020-10-25 22:55:21 +00:00
EventBus.$emit('imagepreview-show', {url: this.getCharacterUrl()});
2019-07-15 16:59:16 +00:00
}
2020-10-25 22:55:21 +00:00
toggleStickyness(): void {
if (!this.preview) {
return;
}
EventBus.$emit('imagepreview-toggle-stickyness', {url: this.getCharacterUrl()});
}
}
2019-07-15 16:59:16 +00:00
</script>