From 21ff1d25b9ee6a428e3ece1eec5c11a33c756480 Mon Sep 17 00:00:00 2001 From: "Mr. Stallion" Date: Sat, 11 Mar 2023 21:43:58 -0800 Subject: [PATCH] Profile analyzer --- CHANGELOG.md | 10 ++ CONTRIBUTORS.md | 1 + README.md | 8 +- chat/ChatView.vue | 24 ++- chat/ConversationView.vue | 66 ++++++- chat/UserMenu.vue | 20 ++- chat/ads/AdLauncher.vue | 18 +- chat/character/memo.ts | 53 ++++++ chat/preview/CharacterPreview.vue | 14 +- chat/preview/assets/browser.pre.js | 4 + chat/preview/event-bus.ts | 3 +- chat/preview/image-dom-mutator.ts | 2 +- chat/preview/image-url-mutator.ts | 11 +- chat/preview/test-urls.txt | 7 + components/Modal.vue | 5 +- docs/_config.yml | 2 +- electron/Index.vue | 16 +- electron/package.json | 2 +- learn/matcher.ts | 4 + learn/recommend/ProfileAnalysis.vue | 91 ++++++++++ learn/recommend/profile-recommendation.ts | 203 ++++++++++++++++++++++ package.json | 2 +- site/character_page/character_page.vue | 4 + site/character_page/interfaces.ts | 12 +- site/character_page/memo_dialog.vue | 12 +- 25 files changed, 556 insertions(+), 38 deletions(-) create mode 100644 chat/character/memo.ts create mode 100644 learn/recommend/ProfileAnalysis.vue create mode 100644 learn/recommend/profile-recommendation.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c4bf120..adc0d79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 1.21.0 +* Added clearer broadcast messages +* Removed extra arrow from gallery view (credit: [@FatCatClient](https://github.com/FatCatClient)) +* Added profile analyser to help improve profile matching +* Dictionary lookup view now has a 'open in browser' button +* Character memos are now displayed more prominently +* Fixed redgifs.com V3 image previews +* Fixed rule34video.com image previews +* 'Select all channels' for Post Ads + ## 1.20.0 * Kink scoring is skipped if characters have only a few shared kinks * Kink scoring gives more weight to 'favorite' and 'no' categories diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 591bcc6..79d5d43 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -4,4 +4,5 @@ This project contains contributions from: * [Mr Stallion, esq.](https://github.com/mrstallion) * [ButterCheezii](https://github.com/ButterCheezii) +* [FatCatClient](https://github.com/FatCatClient) * [F-List Team](https://github.com/f-list) (original F-Chat 3.0 client) diff --git a/README.md b/README.md index 2e14e2c..2393c7d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Download -[Windows](https://github.com/mrstallion/fchat-rising/releases/download/v1.20.0/F-Chat-Rising-1.20.0-win.exe) (82 MB) -| [MacOS Intel](https://github.com/mrstallion/fchat-rising/releases/download/v1.20.0/F-Chat-Rising-1.20.0-macos-intel.dmg) (82 MB) -| [MacOS M1](https://github.com/mrstallion/fchat-rising/releases/download/v1.20.0/F-Chat-Rising-1.20.0-macos-m1.dmg) (84 MB) -| [Linux](https://github.com/mrstallion/fchat-rising/releases/download/v1.20.0/F-Chat-Rising-1.20.0-linux.AppImage) (82 MB) +[Windows](https://github.com/mrstallion/fchat-rising/releases/download/v1.21.0/F-Chat-Rising-1.21.0-win.exe) (82 MB) +| [MacOS Intel](https://github.com/mrstallion/fchat-rising/releases/download/v1.21.0/F-Chat-Rising-1.21.0-macos-intel.dmg) (82 MB) +| [MacOS M1](https://github.com/mrstallion/fchat-rising/releases/download/v1.21.0/F-Chat-Rising-1.21.0-macos-m1.dmg) (84 MB) +| [Linux](https://github.com/mrstallion/fchat-rising/releases/download/v1.21.0/F-Chat-Rising-1.21.0-linux.AppImage) (82 MB) # F-Chat Rising diff --git a/chat/ChatView.vue b/chat/ChatView.vue index 03a4ae9..dd7fbb3 100644 --- a/chat/ChatView.vue +++ b/chat/ChatView.vue @@ -31,6 +31,10 @@ +
+ Profile Analyzer +
+
@@ -114,6 +118,15 @@ + + + + + +
/me @@ -148,6 +161,8 @@ // import { EventBus } from './preview/event-bus'; import AdCenterDialog from './ads/AdCenter.vue'; import AdLauncherDialog from './ads/AdLauncher.vue'; + import Modal from '../components/Modal.vue'; + import ProfileAnalysis from '../learn/recommend/ProfileAnalysis.vue'; const unreadClasses = { [Conversation.UnreadState.None]: '', @@ -164,7 +179,9 @@ 'add-pm-partner': PmPartnerAdder, 'note-status': NoteStatus, adCenter: AdCenterDialog, - adLauncher: AdLauncherDialog + adLauncher: AdLauncherDialog, + modal: Modal, + 'profile-analysis': ProfileAnalysis } }) export default class ChatView extends Vue { @@ -370,6 +387,11 @@ (this.$refs['adLauncher']).show(); } + showProfileAnalyzer(): void { + (this.$refs.profileAnalysis as any).show(); + void (this.$refs.profileAnalysis as any).$children[0].analyze(); + } + showAddPmPartner(): void { (this.$refs['addPmPartnerDialog']).show(); } diff --git a/chat/ConversationView.vue b/chat/ConversationView.vue index 5d2a7d4..9d0f5dc 100644 --- a/chat/ConversationView.vue +++ b/chat/ConversationView.vue @@ -21,10 +21,15 @@ Channels + + + Memo +
{{l('status.' + conversation.character.status)}} +
Memo: {{ userMemo }}
@@ -178,6 +183,10 @@ + +
{{getByteLength(editorMemo)}} / 1000
+ +
@@ -186,12 +195,12 @@ import Vue from 'vue'; import {EditorButton, EditorSelection} from '../bbcode/editor'; import {BBCodeView} from '../bbcode/view'; - import {isShowing as anyDialogsShown} from '../components/Modal.vue'; + import Modal, {isShowing as anyDialogsShown} from '../components/Modal.vue'; import {Keys} from '../keys'; import CharacterAdView from './character/CharacterAdView.vue'; import {Editor} from './bbcode'; import CommandHelp from './CommandHelp.vue'; - import { characterImage, getByteLength, getKey } from './common'; + import { characterImage, errorToString, getByteLength, getKey } from './common'; import ConversationSettings from './ConversationSettings.vue'; import ConversationAdSettings from './ads/ConversationAdSettings.vue'; import core from './core'; @@ -207,6 +216,9 @@ import * as _ from 'lodash'; import Dropdown from '../components/Dropdown.vue'; import { EventBus } from './preview/event-bus'; + // import { CharacterMemo } from '../site/character_page/interfaces'; + import { MemoManager } from './character/memo'; + import { CharacterMemo } from '../site/character_page/interfaces'; @Component({ components: { @@ -221,7 +233,8 @@ 'ad-view': CharacterAdView, 'channel-list': CharacterChannelList, dropdown: Dropdown, - adSettings: ConversationAdSettings + adSettings: ConversationAdSettings, + modal: Modal } }) export default class ConversationView extends Vue { @@ -258,6 +271,10 @@ isPrivate = Conversation.isPrivate; showNonMatchingAds = true; + userMemo: string = ''; + editorMemo: string = ''; + memoManager?: MemoManager; + ownName?: string; @Hook('beforeMount') @@ -315,10 +332,15 @@ this.configUpdateHook = () => this.updateOwnName(); EventBus.$on('configuration-update', this.configUpdateHook); + + this.memoUpdateHook = (e: any) => this.refreshMemo(e); + EventBus.$on('character-memo', this.memoUpdateHook); } protected configUpdateHook: any; + protected memoUpdateHook: any; + @Hook('destroyed') destroyed(): void { window.removeEventListener('resize', this.resizeHandler); @@ -329,6 +351,7 @@ clearInterval(this.adCountdown); EventBus.$off('configuration-update', this.configUpdateHook); + EventBus.$off('character-memo', this.memoUpdateHook); } hideSearch(): void { @@ -355,13 +378,19 @@ } @Watch('conversation') - conversationChanged(): void { + async conversationChanged(): Promise { this.updateOwnName(); if(!anyDialogsShown) (this.$refs['textBox']).focus(); this.$nextTick(() => setTimeout(() => this.messageView.scrollTop = this.messageView.scrollHeight)); this.scrolledDown = true; this.refreshAutoPostingTimer(); + this.userMemo = ''; + + if (this.isPrivate(this.conversation)) { + const c = await core.cache.profileCache.get(this.conversation.name); + this.userMemo = c?.character?.memo?.memo || ''; + } } @Watch('conversation.messages') @@ -621,6 +650,35 @@ return (>message).sfc !== undefined; } + updateMemo(): void { + this.memoManager?.set(this.editorMemo).catch((e: object) => alert(errorToString(e))) + this.userMemo = this.editorMemo; + } + + refreshMemo(event: { character: string, memo: CharacterMemo }): void { + this.userMemo = event.memo.memo; + } + + async showMemo(): Promise { + if (this.isPrivate(this.conversation)) { + const c = this.conversation.character; + + this.editorMemo = ''; + + (this.$refs['userMemoEditor']).show(); + + try { + this.memoManager = new MemoManager(c.name); + await this.memoManager.load(); + + this.userMemo = this.memoManager.get().memo; + this.editorMemo = this.userMemo; + } catch(e) { + alert(errorToString(e)); + } + } + } + get characterImage(): string { return characterImage(this.conversation.name); } diff --git a/chat/UserMenu.vue b/chat/UserMenu.vue index be06699..9e81049 100644 --- a/chat/UserMenu.vue +++ b/chat/UserMenu.vue @@ -60,6 +60,7 @@ import ReportDialog from './ReportDialog.vue'; import { Matcher, MatchReport } from '../learn/matcher'; import _ from 'lodash'; import MatchTags from './preview/MatchTags.vue'; +import { MemoManager } from './character/memo'; @Component({ components: {'match-tags': MatchTags, bbcode: BBCodeView(core.bbCodeParser), modal: Modal, 'ad-view': CharacterAdView} @@ -76,9 +77,10 @@ import MatchTags from './preview/MatchTags.vue'; touchedElement: HTMLElement | undefined; channel: Channel | undefined; memo = ''; - memoId = 0; + // memoId = 0; memoLoading = false; match: MatchReport | null = null; + memoManager?: MemoManager; openConversation(jump: boolean): void { const conversation = core.conversations.getPrivate(this.character!); @@ -115,24 +117,24 @@ import MatchTags from './preview/MatchTags.vue'; async showMemo(): Promise { this.memoLoading = true; this.memo = ''; + this.memoManager = new MemoManager(this.character!.name); + (this.$refs['memo']).show(); + try { - const memo = await core.connection.queryApi<{note: string | null, id: number}>('character-memo-get2.php', - {target: this.character!.name}); - this.memoId = memo.id; - this.memo = memo.note !== null ? memo.note : ''; - this.memoLoading = false; + await this.memoManager.load(); + + this.memo = this.memoManager.get().memo; + this.memoLoading = false; } catch(e) { alert(errorToString(e)); } } updateMemo(): void { - core.connection.queryApi('character-memo-save.php', {target: this.memoId, note: this.memo}) - .catch((e: object) => alert(errorToString(e))); + this.memoManager?.set(this.memo).catch((e: object) => alert(errorToString(e))) } - showAdLogs(): void { if (!this.hasAdLogs()) { return; diff --git a/chat/ads/AdLauncher.vue b/chat/ads/AdLauncher.vue index 6c92143..12dcd83 100644 --- a/chat/ads/AdLauncher.vue +++ b/chat/ads/AdLauncher.vue @@ -1,5 +1,5 @@ @@ -133,6 +135,7 @@ // import { Sqlite3Store } from '../learn/store/sqlite3'; import CharacterPage from '../site/character_page/character_page.vue'; import WordDefinition from '../learn/dictionary/WordDefinition.vue'; + import ProfileAnalysis from '../learn/recommend/ProfileAnalysis.vue'; import {defaultHost, GeneralSettings, nativeRequire} from './common'; import { fixLogs /*SettingsStore, Logs as FSLogs*/ } from './filesystem'; import * as SlimcatImporter from './importer'; @@ -200,7 +203,8 @@ logs: Logs, 'word-definition': WordDefinition, BBCodeTester: BBCodeTester, - bbcode: BBCodeView(core.bbCodeParser) + bbcode: BBCodeView(core.bbCodeParser), + 'profile-analysis': ProfileAnalysis } }) export default class Index extends Vue { @@ -601,6 +605,14 @@ } + async openWordDefinitionInBrowser(): Promise { + await remote.shell.openExternal((this.$refs.wordDefinitionLookup as any).getWebUrl()); + + // tslint:disable-next-line: no-any no-unsafe-any + (this.$refs.wordDefinitionViewer as any).hide(); + } + + unpinUrlPreview(e: Event): void { const imagePreview = (this.$refs['chat'] as Chat)?.getChatView()?.getImagePreview(); diff --git a/electron/package.json b/electron/package.json index 166bc36..0385f28 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,6 +1,6 @@ { "name": "fchat", - "version": "1.20.0", + "version": "1.21.0", "author": "The F-List Team and Mister Stallion (Esq.)", "description": "F-List.net Chat Client", "main": "main.js", diff --git a/learn/matcher.ts b/learn/matcher.ts index 174d857..6a6e0e4 100644 --- a/learn/matcher.ts +++ b/learn/matcher.ts @@ -524,6 +524,10 @@ export class Matcher { return this.formatScoring(score, postLengthPreferenceMapping[theirLength]); } + static getSpeciesName(species: Species): string { + return speciesNames[species] || `${Species[species].toLowerCase()}s`; + } + private resolveSpeciesScore(): Score { const you = this.you; const theirAnalysis = this.theirAnalysis; diff --git a/learn/recommend/ProfileAnalysis.vue b/learn/recommend/ProfileAnalysis.vue new file mode 100644 index 0000000..98eb7dd --- /dev/null +++ b/learn/recommend/ProfileAnalysis.vue @@ -0,0 +1,91 @@ + + + diff --git a/learn/recommend/profile-recommendation.ts b/learn/recommend/profile-recommendation.ts new file mode 100644 index 0000000..b41e130 --- /dev/null +++ b/learn/recommend/profile-recommendation.ts @@ -0,0 +1,203 @@ +import _ from 'lodash'; + +import { CharacterAnalysis, Matcher } from '../matcher'; +import { FurryPreference, Kink, mammalSpecies, Species } from '../matcher-types'; + +export enum ProfileRecommendationLevel { + INFO = 'info', + NOTE = 'note', + CRITICAL = 'critical' +} + +export interface ProfileRecommendationUrlParams { + // TBD +} + +export interface ProfileRecommendation { + code: string; + level: ProfileRecommendationLevel; + title: string; + desc: string; + urlParams?: ProfileRecommendationUrlParams +} + +export class ProfileRecommendationAnalyzer { + protected recommendations: ProfileRecommendation[] = []; + + constructor(protected readonly profile: CharacterAnalysis) { + // + } + + protected add(code: string, level: ProfileRecommendationLevel, title: string, desc: string, urlParams?: ProfileRecommendationUrlParams): void { + this.recommendations.push({ code, level, title, desc, urlParams }); + } + + analyze(): ProfileRecommendation[] { + this.recommendations = []; + + this.checkMissingProperties(); + this.checkSpeciesPreferences(); + this.checkKinkCounts(); + this.checkCustomKinks(); + + this.checkPortrait(); + this.checkImages(); + this.checkInlineImage(); + this.checkDescriptionLength(); + + return this.recommendations; + } + + protected checkPortrait(): void { + // this.profile.character. + // do nothing + } + + protected checkImages(): void { + if (!this.profile.character.image_count) { + this.add(`ADD_IMAGE`, ProfileRecommendationLevel.CRITICAL, 'Add a profile image', 'Profiles with images are more attractive to other players.'); + } else if (this.profile.character.image_count > 1 && this.profile.character.image_count < 3) { + this.add(`ADD_MORE_IMAGES`, ProfileRecommendationLevel.NOTE, 'Add more profile images', 'Profiles with images are more attractive – try to have at least 3 images in your profile.'); + } + } + + protected checkInlineImage(): void { + if (_.keys(this.profile.character.inlines).length < 1) { + this.add(`ADD_INLINE_IMAGE`, ProfileRecommendationLevel.NOTE, 'Add an inline image', 'Profiles with inline images are more engaging to other players.'); + } + } + + protected checkDescriptionLength(): void { + const desc = this.profile.character.description.trim(); + + if (desc.length < 20) { + this.add(`ADD_DESCRIPTION`, ProfileRecommendationLevel.CRITICAL, 'Add description', 'Profiles with descriptions are more likely to draw attention from other players.'); + } else if (desc.length < 400) { + this.add(`EXPAND_DESCRIPTION`, ProfileRecommendationLevel.NOTE, 'Extend your description', 'Long descriptions are more attractive to other players. Try expanding your description to at least 400 characters.'); + } + } + + protected checkCustomKinks(): void { + const counts = _.reduce(this.profile.character.customs, (accum, kink) => { + if (kink) { + accum.total += 1; + + if (kink.description) { + accum.filled += 1; + } + } + + return accum; + }, { filled: 0, total: 0 }); + + if (counts.total === 0) { + this.add(`ADD_CUSTOM_KINK`, ProfileRecommendationLevel.CRITICAL, 'Add custom kinks', `Custom kinks will help your profile stand out. Try adding at least 5 custom kinks.`); + } else if (counts.total < 5) { + this.add(`ADD_MORE_CUSTOM_KINKS`, ProfileRecommendationLevel.NOTE, 'Add more custom kinks', `Players pay a lot of attention to custom kinks. Try adding at least 5 custom kinks.`); + } + + if (counts.filled < counts.total && counts.total > 0) { + this.add(`ADD_MORE_CUSTOM_KINK_DESCRIPTIONS`, ProfileRecommendationLevel.NOTE, 'Add descriptions to custom kinks', `Some or all of your custom kinks are missing descriptions. Add descriptions to your custom kinks to attract more players.`); + } + } + + protected checkKinkCounts(): void { + const counts = _.reduce(this.profile.character.kinks, (accum, kinkLevel) => { + if (_.isString(kinkLevel) && kinkLevel) { + accum[kinkLevel as keyof typeof accum] += 1; + } + + return accum; + }, { favorite: 0, yes: 0, maybe: 0, no: 0 }); + + const minCountPerType = 5; + const totalCount = counts.favorite + counts.yes + counts.maybe + counts.no; + + if (totalCount < 10) { + this.add(`ADD_MORE_KINKS`, ProfileRecommendationLevel.CRITICAL, `Add more kinks`, `You should have at least 10 kinks for the matching algorithm to work well.`); + } else { + _.each(counts, (count, key) => { + if (count < minCountPerType) { + this.add(`ADD_MORE_KINKS_${key.toString().toUpperCase()}`, ProfileRecommendationLevel.CRITICAL, `Add more '${key}' kinks`, `You should have at least ${minCountPerType} '${key}' kinks for the matching algorithm to work well.`); + } + }); + } + } + + protected checkMissingProperties(): void { + const p = this.profile; + + if (p.age === null) { + this.add('AGE', ProfileRecommendationLevel.CRITICAL, 'Enter age', 'Specifying the age of your character will improve your matches with other players.'); + } + + if (p.orientation === null) { + this.add('ORIENTATION', ProfileRecommendationLevel.CRITICAL, 'Enter sexual orientation', 'Specifying the sexual orientation of your character will improve your matches with other players.'); + } + + if (p.species === null) { + this.add('SPECIES', ProfileRecommendationLevel.CRITICAL, 'Enter species', 'Specifying the species of your character – even if it\'s \'human\' – will improve your matches with other players.'); + } + + if (p.furryPreference === null) { + this.add('FURRY_PREFERENCE', ProfileRecommendationLevel.CRITICAL, 'Enter furry preference', 'Specifying whether you like to play with anthro characters will improve your matches with other players.'); + } + + if (p.subDomRole === null) { + this.add('SUB_DOM_ROLE', ProfileRecommendationLevel.CRITICAL, 'Enter sub/dom role', 'Specifying your preferred sub/dom role will improve your matches with other players.'); + } + + if (p.position === null) { + this.add('POSITION', ProfileRecommendationLevel.CRITICAL, 'Enter position', 'Specifying your preferred position (e.g. "top", "bottom") will improve your matches with other players.'); + } + + if (p.postLengthPreference === null) { + this.add('POST_LENGTH', ProfileRecommendationLevel.CRITICAL, 'Enter post length preference', 'Specifying your post length preference will improve your matches with other players.'); + } + + if (p.bodyType === null) { + this.add('BODY_TYPE', ProfileRecommendationLevel.CRITICAL, 'Enter body type', 'Specifying your character\'s body type will improve your matches with other players.'); + } + } + + protected checkSpeciesPreferences(): void { + const p = this.profile; + const c = this.profile.character; + + if (p.furryPreference === null) { + return; + } + + if (p.furryPreference === FurryPreference.FurriesOnly) { + if (Matcher.getKinkPreference(c, Kink.Humans)! > 0) { + this.add('KINK_MISMATCH_FURRIES_ONLY_HUMAN', ProfileRecommendationLevel.NOTE, 'Inconsistent kink', 'Your "furries-only" profile has a positive "humans" kink. If you are open to playing with humans, consider updating your preference from "furries only" to "furs and humans".'); + } + } + + if (p.furryPreference === FurryPreference.HumansOnly) { + if (Matcher.getKinkPreference(c, Kink.AnimalsFerals)! >= 0 || Matcher.getKinkPreference(c, Kink.Zoophilia)! >= 0) { + // do nothing + } else { + const likedAnthros = this.getLikedAnimals(); + + _.each(likedAnthros, (species) => { + this.add('KINK_MISMATCH_HUMANS_ONLY_ANTHRO', ProfileRecommendationLevel.NOTE, 'Inconsistent kink', `Your "humans-only" profile has a positive "furry" kink (${Matcher.getSpeciesName(species)}). If you are open to playing with anthros, consider updating your preference from "humans only" to "furs and humans"`); + }); + } + } + + if (p.furryPreference !== FurryPreference.HumansOnly) { + const likedAnthros = this.getLikedAnimals(); + + if (likedAnthros && !_.difference(likedAnthros, [Kink.AnthroCharacters, Kink.Mammals, Kink.Humans] as any as Species[])) { + this.add('KINK_NO_SPECIES', ProfileRecommendationLevel.NOTE, 'Add preferred species', 'Specifying which anthro species you like (e.g. "equines", or "canines") in your kinks can improve your matches.'); + } + } + } + + protected getLikedAnimals(): Species[] { + const c = this.profile.character; + + return _.filter(mammalSpecies, (species) => Matcher.getKinkPreference(c, species)! > 0); + } +} diff --git a/package.json b/package.json index 6b656f2..9e80c74 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "f-list-rising", - "version": "1.20.0", + "version": "1.21.0", "author": "The F-List Team and and Mister Stallion (Esq.)", "description": "A heavily modded F-Chat 3.0 client for F-List", "license": "MIT", diff --git a/site/character_page/character_page.vue b/site/character_page/character_page.vue index 46510ba..7ebf793 100644 --- a/site/character_page/character_page.vue +++ b/site/character_page/character_page.vue @@ -340,10 +340,14 @@ memo(memo: {id: number, memo: string}): void { Vue.set(this.character!, 'memo', memo); + + void core.cache.profileCache.register(this.character!); } bookmarked(state: boolean): void { Vue.set(this.character!, 'bookmarked', state); + + void core.cache.profileCache.register(this.character!); } protected async loadSelfCharacter(): Promise { diff --git a/site/character_page/interfaces.ts b/site/character_page/interfaces.ts index 6dd006c..f689f38 100644 --- a/site/character_page/interfaces.ts +++ b/site/character_page/interfaces.ts @@ -96,15 +96,17 @@ export interface CharacterGroup { owner: boolean } +export interface CharacterMemo { + id: number; + memo: string; +} + export interface Character { readonly is_self: boolean character: CharacterInfo readonly settings: CharacterSettings readonly badges?: string[] - memo?: { - id: number - memo: string - } + memo?: CharacterMemo; readonly character_list?: { id: number name: string @@ -158,4 +160,4 @@ export interface FriendsByCharacter { pending: FriendRequest[] incoming: FriendRequest[] name: string -} \ No newline at end of file +} diff --git a/site/character_page/memo_dialog.vue b/site/character_page/memo_dialog.vue index dc8e22a..ecf3320 100644 --- a/site/character_page/memo_dialog.vue +++ b/site/character_page/memo_dialog.vue @@ -17,7 +17,8 @@ import Modal from '../../components/Modal.vue'; import {SimpleCharacter} from '../../interfaces'; import * as Utils from '../utils'; - import {methods} from './data_store'; + // import {methods} from './data_store'; + import { MemoManager } from '../../chat/character/memo'; export interface Memo { id: number @@ -61,8 +62,11 @@ async save(): Promise { try { this.saving = true; - const memoReply = await methods.memoUpdate(this.character.id, this.message); - this.$emit('memo', this.message !== '' ? memoReply : undefined); + + const memoManager = new MemoManager(this.character.name); + await memoManager.set(this.message); + + this.$emit('memo', memoManager.get()); this.hide(); } catch(e) { Utils.ajaxError(e, 'Unable to set memo.'); @@ -70,4 +74,4 @@ this.saving = false; } } - \ No newline at end of file +