Species search

This commit is contained in:
Mr. Stallion 2020-04-11 15:23:53 -05:00
parent 73528dd51d
commit 326e1b9445
6 changed files with 92 additions and 23 deletions

View File

@ -11,6 +11,11 @@
v-model="data[item]" :placeholder="l('filter')" :title="l('characterSearch.' + item)" :options="options[item]" :key="item">
</filterable-select>
<filterable-select v-model="data.species" :multiple="true" :placeholder="l('filter')"
:title="l('characterSearch.species')" :options="options.species">
<template slot-scope="s">{{s.option.name}}</template>
</filterable-select>
<div v-if="searchString" class="search-string">
Searching for <span>{{searchString}}</span>
</div>
@ -49,12 +54,13 @@
import Modal from '../components/Modal.vue';
import {characterImage} from './common';
import core from './core';
import { Character, Connection, SearchData, SearchKink } from './interfaces';
import { Character, Connection, ExtendedSearchData, SearchData, SearchKink, SearchSpecies } from './interfaces';
import l from './localize';
import UserView from './UserView.vue';
import * as _ from 'lodash';
import {EventBus} from './preview/event-bus';
import CharacterSearchHistory from './CharacterSearchHistory.vue';
import { Matcher, Species, speciesNames } from '../learn/matcher';
type Options = {
kinks: SearchKink[],
@ -102,9 +108,9 @@
results: Character[] | undefined;
resultsComplete = false;
characterImage = characterImage;
options!: SearchData;
data: SearchData = {kinks: [], genders: [], orientations: [], languages: [], furryprefs: [], roles: [], positions: []};
listItems: ReadonlyArray<keyof SearchData> = ['genders', 'orientations', 'languages', 'furryprefs', 'roles', 'positions'];
options!: ExtendedSearchData;
data: ExtendedSearchData = {kinks: [], genders: [], orientations: [], languages: [], furryprefs: [], roles: [], positions: [], species: []};
listItems: ReadonlyArray<keyof SearchData> = ['genders', 'orientations', 'languages', 'furryprefs', 'roles', 'positions']; // SearchData is correct
searchString = '';
@ -124,7 +130,8 @@
languages: options.listitems.filter((x) => x.name === 'languagepreference').map((x) => x.value),
furryprefs: options.listitems.filter((x) => x.name === 'furrypref').map((x) => x.value),
roles: options.listitems.filter((x) => x.name === 'subdom').map((x) => x.value),
positions: options.listitems.filter((x) => x.name === 'position').map((x) => x.value)
positions: options.listitems.filter((x) => x.name === 'position').map((x) => x.value),
species: this.getSpeciesOptions()
});
}
@ -144,7 +151,9 @@
});
core.connection.onMessage('FKS', (data) => {
this.results = data.characters.map((x) => core.characters.get(x))
.filter((x) => core.state.hiddenUsers.indexOf(x.name) === -1 && !x.isIgnored).sort(sort);
.filter((x) => core.state.hiddenUsers.indexOf(x.name) === -1 && !x.isIgnored)
.filter((x) => this.isSpeciesMatch(x))
.sort(sort);
this.resultsComplete = this.checkResultCompletion();
});
@ -164,7 +173,11 @@
// tslint:disable-next-line no-unsafe-any no-any
&& (_.find(this.results, (c: Character) => c.name === event.character.character.name))
) {
this.results = this.results.sort(sort);
this.results = (_.filter(
this.results,
(x) => this.isSpeciesMatch(x)
) as Character[]).sort(sort);
this.resultsComplete = this.checkResultCompletion();
}
};
@ -203,6 +216,51 @@
}
isSpeciesMatch(c: Character): boolean {
if (this.data.species.length === 0) {
return true;
}
const knownCharacter = core.cache.profileCache.getSync(c.name);
if (!knownCharacter) {
return true;
}
const species = Matcher.species(knownCharacter.character.character);
if (!species) {
return false;
}
return !!_.find(this.data.species, (s) => (s.id === species));
}
getSpeciesOptions(): SearchSpecies[] {
const species = _.map(
_.filter(Species, (s) => (_.isString(s))) as unknown[] as string[],
(speciesName: string) => {
const speciesId = (Species as any)[speciesName];
if (speciesId in speciesNames) {
return {
name: `${speciesNames[speciesId].substr(0, 1).toUpperCase()}${speciesNames[speciesId].substr(1)} (species)`,
id: speciesId
};
}
return {
name: `${speciesName}s (species)`,
id: speciesId
};
}
);
return _.sortBy(species, 'name');
}
checkResultCompletion(): boolean {
return _.every(
this.results,
@ -223,11 +281,11 @@
reset(): void {
this.data = {kinks: [], genders: [], orientations: [], languages: [], furryprefs: [], roles: [], positions: []};
this.data = {kinks: [], genders: [], orientations: [], languages: [], furryprefs: [], roles: [], positions: [], species: []};
}
updateSearch(data?: SearchData): void {
updateSearch(data?: ExtendedSearchData): void {
if (data) {
// this.data = {kinks: [], genders: [], orientations: [], languages: [], furryprefs: [], roles: [], positions: []};
// this.data = data;
@ -245,7 +303,7 @@
}
)
)
) as SearchData;
) as ExtendedSearchData;
}
}
@ -258,7 +316,7 @@
this.error = '';
const data: Connection.ClientCommands['FKS'] & {[key: string]: (string | number)[]} = {kinks: []};
for(const key in this.data) {
const item = this.data[<keyof SearchData>key];
const item = this.data[<keyof SearchData>key]; // SearchData is correct
if(item.length > 0)
data[key] = key === 'kinks' ? (<SearchKink[]>item).map((x) => x.id) : (<string[]>item);
}
@ -274,11 +332,16 @@
}
async updateSearchHistory(data: SearchData): Promise<void> {
async updateSearchHistory(data: ExtendedSearchData): Promise<void> {
const history = (await core.settingsStore.get('searchHistory')) || [];
const dataStr = JSON.stringify(data, null, 0);
const filteredHistory = _.reject(history, (h: SearchData) => (JSON.stringify(h, null, 0) === dataStr));
const newHistory: SearchData[] = _.take(_.concat([data], filteredHistory), 15);
const filteredHistory = _.map(
_.reject(history, (h: SearchData) => (JSON.stringify(h, null, 0) === dataStr)),
(h) => _.merge({ species: [] }, h)
) as ExtendedSearchData[];
const newHistory: ExtendedSearchData[] = _.take(_.concat([data], filteredHistory), 15);
await core.settingsStore.set('searchHistory', newHistory);
}

View File

@ -26,19 +26,19 @@
import core from './core';
import { BBCodeView } from '../bbcode/view';
import * as _ from 'lodash';
import { SearchData } from './interfaces';
import { ExtendedSearchData, SearchData } from './interfaces';
@Component({
components: {modal: Modal, dropdown: Dropdown, bbcode: BBCodeView(core.bbCodeParser)}
})
export default class CharacterSearchHistory extends CustomDialog {
@Prop({required: true})
readonly callback!: (searchData: SearchData) => void;
readonly callback!: (searchData: ExtendedSearchData) => void;
@Prop({required: true})
readonly curSearch!: SearchData | undefined;
readonly curSearch!: ExtendedSearchData | undefined;
history: SearchData[] = [];
history: (ExtendedSearchData|SearchData)[] = [];
selectedSearch: number | null = null;
@ -64,7 +64,7 @@
selectStatus(): void {
if (this.selectedSearch !== null) {
this.callback(this.history[this.selectedSearch]);
this.callback(_.merge({species: []}, this.history[this.selectedSearch]) as ExtendedSearchData);
}
}
@ -74,7 +74,7 @@
}
describeSearch(searchData: SearchData): string {
describeSearch(searchData: SearchData | ExtendedSearchData): string {
return _.join(
_.map(
// tslint:disable-next-line no-unsafe-any no-any

View File

@ -144,6 +144,7 @@ export interface Logs {
}
export type SearchKink = {id: number, name: string, description: string};
export type SearchSpecies = {id: number, name: string};
export interface SearchData {
kinks: SearchKink[]
@ -155,6 +156,9 @@ export interface SearchData {
positions: string[]
}
export interface ExtendedSearchData extends SearchData {
species: SearchSpecies[];
}
export namespace Settings {
export type Keys = {
@ -166,7 +170,7 @@ export namespace Settings {
recentChannels: Conversation.RecentChannelConversation[]
hiddenUsers: string[]
statusHistory: string[]
searchHistory: SearchData[]
searchHistory: (ExtendedSearchData | SearchData)[]
};
export interface Store {

View File

@ -229,6 +229,7 @@ Once this process has started, do not interrupt it or your logs will get corrupt
'characterSearch.furryprefs': 'Furry preferences',
'characterSearch.roles': 'Dom/sub roles',
'characterSearch.positions': 'Positions',
'characterSearch.species': 'Species (beta)',
'characterSearch.error.noResults': 'There were no search results.',
'characterSearch.error.throttle': 'You must wait five seconds between searches.',
'characterSearch.error.tooManyResults': 'There are too many search results, please narrow your search.',

View File

@ -180,7 +180,7 @@ interface SpeciesStrMap {
[key: number]: string;
}
const speciesNames: SpeciesStrMap = {
export const speciesNames: SpeciesStrMap = {
[Species.MarineMammal]: 'marine mammals',
[Species.Elf]: 'elves',
[Species.Fish]: 'fishes',
@ -195,7 +195,7 @@ const speciesMapping: SpeciesMap = {
'appaloosa', 'friesian', 'draft', 'draught', 'alicorn', 'amazon', 'amazonian', 'horsie', 'hoss', 'pegasus', 'colt', 'filly'],
[Species.Feline]: ['cat', 'kitten', 'catgirl', 'neko', 'tiger', 'puma', 'lion', 'lioness',
'tigress', 'feline', 'jaguar', 'cheetah', 'lynx', 'leopard', 'cougar', 'kitty', 'migote', 'miqo\'te', 'miqote', 'ocelot',
'sabertooth', 'saber tooth', 'tabby'],
'sabertooth', 'saber tooth', 'tabby', 'liger'],
[Species.Canine]: ['dog', 'wolf', 'dingo', 'coyote', 'jackal', 'canine', 'doberman', 'husky', 'hound', 'akita', 'pitbull', 'pit bull', 'terrier',
'bull terrier', 'australian shepherd', 'australian shepard', 'german shepherd', 'german shepard', 'malinois', 'woof', 'labrador', 'collie',
'canis', 'canid', 'chihuahua', 'poodle', 'chinchilla', 'chowchow', 'corgi', 'anubis', 'anubian', 'dalmatian', 'inumimi', 'lupine', 'malamute', 'mastiff',

View File

@ -44,6 +44,7 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0
* Display match score in search results
* Current search filters are listed in the search dialog
* Search filters can be reset
* Search results can be filtered by species
* Last 15 searches are stored and can be accessed from the 'Search' dialog
* Character status
* Last 10 status messages are stored and can be accessed from the 'Set status' dialog