Fixed kink group highlighting; fixed character kink comparison; added settings view for F-Chat Rising features; added UI for reming and reordering ads

This commit is contained in:
Mr. Stallion 2019-11-03 14:42:03 -06:00
parent 971f619e18
commit 598a67026d
14 changed files with 258 additions and 44 deletions

View File

@ -35,11 +35,18 @@
<option :value="setting.False">{{l('conversationSettings.false')}}</option>
</select>
</div>
<div class="form-group" v-for="(ad, index) in ads">
<label :for="'ad' + conversation.key + '-' + index" class="control-label">Channel Auto-Posting Ad #{{(index + 1)}}</label>
<h5>Auto-Posting Channel Ads</h5>
<div class="form-group ad-list" v-for="(ad, index) in ads">
<label :for="'ad' + conversation.key + '-' + index" class="control-label">Ad #{{(index + 1)}}
<a v-if="(index > 0)" @click="moveAdUp(index)" title="Move Up"><i class="fa fa-arrow-up"></i></a>
<a v-if="(index < ads.length - 1)" @click="moveAdDown(index)" title="Move Down"><i class="fa fa-arrow-down"></i></a>
<a @click="removeAd(index)" title="Remove Ad"><i class="fa fa-minus-circle"></i></a>
</label>
<textarea :id="'ad' + conversation.key + '-' + index" class="form-control" v-model="ads[index]"></textarea>
</div>
<button class="btn" @click="addAd()">Add Auto-Posting Ad</button>
<button class="btn btn-outline-secondary" @click="addAd()">Add Another</button>
</modal>
</template>
@ -97,5 +104,39 @@
addAd(): void {
this.ads.push('');
}
removeAd(index: number): void {
if (confirm('Are you sure you wish to remove this ad?')) {
this.ads.splice(index, 1);
}
}
moveAdUp(index: number): void {
const ad = this.ads.splice(index, 1);
this.ads.splice(index - 1, 0, ad[0]);
}
moveAdDown(index: number): void {
const ad = this.ads.splice(index, 1);
this.ads.splice(index + 1, 0, ad[0]);
}
}
</script>
</script>
<style lang="scss">
.form-group.ad-list label a {
padding-right: 0.3rem;
opacity:0.3
}
.form-group.ad-list label a:hover {
opacity:0.6
}
</style>

View File

@ -53,11 +53,14 @@
[url=https://imgur.com/gallery/ILsb94I]Imgur gallery[/url]
[url=https://imgur.com/CIKv6sA]Imgur image[/url]
[url=https://imgur.com/a/nMafj]Imgur album[/url]
*/
import * as _ from 'lodash';
import {Component, Hook} from '@f-list/vue-ts';
import Vue from 'vue';
import core from './core';
import { EventBus, EventBusEvent } from './event-bus';
import {domain} from '../bbcode/core';
import {ImagePreviewMutator} from './image-preview-mutator';
@ -224,7 +227,6 @@
'imagepreview-dismiss',
(eventData: EventBusEvent) => {
// console.log('Event dismiss', eventData.url);
this.dismiss(eventData.url as string, eventData.force as boolean);
}
);
@ -234,6 +236,10 @@
(eventData: EventBusEvent) => {
// console.log('Event show', eventData.url);
if (!core.state.settings.risingLinkPreview) {
return;
}
this.show(eventData.url as string);
}
);
@ -241,6 +247,10 @@
EventBus.$on(
'imagepreview-toggle-stickyness',
(eventData: EventBusEvent) => {
if (!core.state.settings.risingLinkPreview) {
return;
}
const eventUrl = this.jsMutator.mutateUrl(eventData.url as string);
if ((this.url === eventUrl) && (this.visible))

View File

@ -1,7 +1,7 @@
<template>
<modal :action="l('settings.action')" @submit="submit" @open="load()" id="settings" dialogClass="w-100">
<tabs style="flex-shrink:0;margin-bottom:10px" v-model="selectedTab"
:tabs="[l('settings.tabs.general'), l('settings.tabs.notifications'), l('settings.tabs.hideAds'), l('settings.tabs.import')]"></tabs>
:tabs="[l('settings.tabs.general'), l('settings.tabs.notifications'), 'Rising', l('settings.tabs.hideAds'), l('settings.tabs.import')]"></tabs>
<div v-show="selectedTab === '0'">
<div class="form-group">
<label class="control-label" for="disallowedTags">{{l('settings.disallowedTags')}}</label>
@ -119,6 +119,24 @@
</div>
</div>
<div v-show="selectedTab === '2'">
<div class="form-group">
<label class="control-label" for="risingAdScore">
<input type="checkbox" id="risingAdScore" v-model="risingAdScore"/>
Colorize ads, profiles, and names of compatible and incompatible characters
</label>
<label class="control-label" for="risingLinkPreview">
<input type="checkbox" id="risingLinkPreview" v-model="risingLinkPreview"/>
Show link previews when the mouse hovers over a link
</label>
<label class="control-label" for="risingAutoCompareKinks">
<input type="checkbox" id="risingAutoCompareKinks" v-model="risingAutoCompareKinks"/>
Automatically compare kinks when viewing a character profile
</label>
</div>
</div>
<div v-show="selectedTab === '3'">
<template v-if="hidden.length">
<div v-for="(user, i) in hidden">
<span class="fa fa-times" style="cursor:pointer" @click.stop="hidden.splice(i, 1)"></span>
@ -127,7 +145,7 @@
</template>
<template v-else>{{l('settings.hideAds.empty')}}</template>
</div>
<div v-show="selectedTab === '3'" style="display:flex;padding-top:10px">
<div v-show="selectedTab === '4'" style="display:flex;padding-top:10px">
<select id="import" class="form-control" v-model="importCharacter" style="flex:1;margin-right:10px">
<option value="">{{l('settings.import.selectCharacter')}}</option>
<option v-for="character in availableImports" :value="character">{{character}}</option>
@ -175,6 +193,10 @@
colorBookmarks!: boolean;
bbCodeBar!: boolean;
risingAdScore!: boolean;
risingLinkPreview!: boolean;
risingAutoCompareKinks!: boolean;
async load(): Promise<void> {
const settings = core.state.settings;
this.playSound = settings.playSound;
@ -198,6 +220,10 @@
this.colorBookmarks = settings.colorBookmarks;
this.bbCodeBar = settings.bbCodeBar;
this.availableImports = (await core.settingsStore.getAvailableCharacters()).filter((x) => x !== core.connection.character);
this.risingAdScore = settings.risingAdScore;
this.risingLinkPreview = settings.risingLinkPreview;
this.risingAutoCompareKinks = settings.risingAutoCompareKinks;
}
async doImport(): Promise<void> {
@ -240,7 +266,11 @@
showNeedsReply: this.showNeedsReply,
enterSend: this.enterSend,
colorBookmarks: this.colorBookmarks,
bbCodeBar: this.bbCodeBar
bbCodeBar: this.bbCodeBar,
risingAdScore: this.risingAdScore,
risingLinkPreview: this.risingLinkPreview,
risingAutoCompareKinks: this.risingAutoCompareKinks
};
if(this.notifications) await core.notifications.requestPermission();
}

View File

@ -113,6 +113,7 @@ export default class UserView extends Vue {
this.rankIcon = null;
this.statusClass = null;
this.matchClass = null;
this.matchScore = null;
// if (this.match) console.log('Update', this.character.name);
@ -131,7 +132,7 @@ export default class UserView extends Vue {
// if (this.match) console.log('Update prematch', this.character.name);
if (this.match) {
if ((core.state.settings.risingAdScore) && (this.match)) {
const cache = core.cache.profileCache.getSync(this.character.name);
if (cache) {

View File

@ -42,6 +42,10 @@ export class Settings implements ISettings {
enterSend = true;
colorBookmarks = false;
bbCodeBar = true;
risingAdScore = true;
risingLinkPreview = true;
risingAutoCompareKinks = true;
}

View File

@ -61,7 +61,43 @@ export class ImageUrlMutator {
}
);
// must be AFTER gallery test
this.add(
/^https?:\/\/imgur.com\/a\/([a-zA-Z0-9]+)/,
async(url: string, match: RegExpMatchArray): Promise<string> => {
// Imgur Album
const albumId = match[1];
try {
const result = await Axios.get(
`https://api.imgur.com/3/album/${albumId}/images`,
{
headers: {
Authorization: `Client-ID ${ImageUrlMutator.IMGUR_CLIENT_ID}`
}
}
);
const imageUrl = _.get(result, 'data.data.0.link', null);
if (!imageUrl) {
return url;
}
const imageCount = _.get(result, 'data.data.length', 1);
if (this.debug)
console.log('Imgur album', url, imageUrl, imageCount);
return `${imageUrl}?flist_gallery_image_count=${imageCount}`;
} catch (err) {
console.error('Imgur Album Failure', url, err);
return url;
}
}
);
// must be AFTER gallery & album test
this.add(
/^https?:\/\/imgur.com\/([a-zA-Z0-9]+)/,
async(url: string, match: RegExpMatchArray): Promise<string> => {

View File

@ -181,6 +181,10 @@ export namespace Settings {
readonly enterSend: boolean;
readonly colorBookmarks: boolean;
readonly bbCodeBar: boolean;
readonly risingAdScore: boolean;
readonly risingLinkPreview: boolean;
readonly risingAutoCompareKinks: boolean;
}
}

View File

@ -104,7 +104,7 @@ export default class MessageView extends Vue {
}
getMessageScoreClasses(message: Conversation.Message): string {
if (message.type !== Conversation.Message.Type.Ad) {
if ((!core.state.settings.risingAdScore) || (message.type !== Conversation.Message.Type.Ad)) {
return '';
}

View File

@ -49,6 +49,10 @@ export class CacheManager {
}
async queueForFetching(name: string, skipCacheCheck: boolean = false): Promise<void> {
if (!core.state.settings.risingAdScore) {
return;
}
if (!skipCacheCheck) {
const c = await this.profileCache.get(name);

View File

@ -72,11 +72,7 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0
* Fix broken BBCode, such as `[big]` in character profiles
* Reposition ad settings and toggle
* Save character status messages
* Bug: Images tab count is off
* Configuration dialog for the player to change match weighs, preview settings, etc.
* Conversation bot API
* Character comparison should consider D/s preference
* Fix collapsible details on character view
* Filter unmatching ads is not channel specific -- it's either on everywhere or nowhere

View File

@ -36,7 +36,7 @@
<div class="card-body">
<div class="tab-content">
<div role="tabpanel" class="tab-pane" :class="{active: tab === '0'}" id="overview">
<match-report :characterMatch="characterMatch" :minimized="character.is_self"></match-report>
<match-report :characterMatch="characterMatch" :minimized="character.is_self" v-if="shouldShowMatch()"></match-report>
<div v-bbcode="character.character.description" style="margin-bottom: 10px"></div>
<character-kinks :character="character" :oldApi="oldApi" ref="tab0"></character-kinks>
</div>
@ -138,7 +138,6 @@
images: CharacterImage[] | null = null;
selfCharacter: Character | undefined;
characterMatch: MatchReport | undefined;
@ -184,6 +183,10 @@
}
shouldShowMatch(): boolean {
return core.state.settings.risingAdScore;
}
async reload(): Promise<void> {
await this.load(true, true);
}
@ -409,9 +412,16 @@
.character-kink {
.popover {
display:block;
bottom:100%;
top:initial;
// margin-bottom:5px;
min-width: 200px;
margin-bottom: 0;
padding-bottom: 0;
opacity: 1;
}
p {
@ -476,6 +486,29 @@
color: #ededf6;
font-weight: normal;
}
&.highlighted {
.kink-name, i {
font-weight: bold;
color: #ffffff;
}
}
}
.character-kinks-block {
.highlighting {
.character-kink.stock-kink {
.kink-name {
opacity: 0.4;
}
&.highlighted {
.kink-name {
opacity: 1;
}
}
}
}
}
@ -739,44 +772,86 @@
}
$scoreMatchBg: rgb(0, 142, 0);
$scoreMatchFg: rgb(0, 113, 0);
$scoreWeakMatchBg: rgb(0, 80, 0);
$scoreWeakMatchFg: rgb(0, 64, 0);
$scoreWeakMismatchBg: rgb(152, 134, 0);
$scoreWeakMismatchFg: rgb(142, 126, 0);
$scoreMismatchBg: rgb(171, 0, 0);
$scoreMismatchFg: rgb(128, 0, 0);
.character-kinks-block .character-kink.comparison-favorite,
.match-report .scores .match-score.match,
.infotag.match {
background-color: rgb(0, 142, 0);
border: solid 1px rgb(0, 113, 0);
// background-color: #007700;
// border: 1px solid #003e00;
background-color: $scoreMatchBg;
border: solid 1px $scoreMatchFg;
}
.character-kinks-block .character-kink.comparison-yes,
.match-report .scores .match-score.weak-match,
.infotag.weak-match {
background-color: rgb(0, 80, 0);
border: 1px solid rgb(0, 64, 0);
// background-color: #004200;
// border: 1px solid #002900;
background-color: $scoreWeakMatchBg;
border: 1px solid $scoreWeakMatchFg;
}
.character-kinks-block .character-kink.comparison-maybe,
.match-report .scores .match-score.weak-mismatch,
.infotag.weak-mismatch {
background-color: rgb(152, 134, 0);
border: 1px solid rgb(142, 126, 0);
// border: 1px solid #613e00;
// background-color: #905d01;
background-color: $scoreWeakMismatchBg;
border: 1px solid $scoreWeakMismatchFg;
}
.character-kinks-block .character-kink.comparison-no,
.match-report .scores .match-score.mismatch,
.infotag.mismatch {
background-color: rgb(171, 0, 0);
border: 1px solid rgb(128, 0, 0);
background-color: $scoreMismatchBg;
border: 1px solid $scoreMismatchFg;
}
// border: 1px solid #420200;
// background-color: #710300;
.character-kinks-block .highlighting {
.character-kink {
&.comparison-favorite {
background-color: adjust-color($scoreMatchBg, $alpha: -0.6);
border-color: adjust-color($scoreMatchFg, $alpha: -0.6);
&.highlighted {
background-color: $scoreMatchBg;
border-color: $scoreMatchFg;
}
}
&.comparison-yes {
background-color: adjust-color($scoreWeakMatchBg, $alpha: -0.6);
border-color: adjust-color($scoreWeakMatchFg, $alpha: -0.6);
&.highlighted {
background-color: $scoreWeakMatchBg;
border-color: $scoreWeakMatchFg;
}
}
&.comparison-maybe {
background-color: adjust-color($scoreWeakMismatchBg, $alpha: -0.6);
border-color: adjust-color($scoreWeakMismatchFg, $alpha: -0.6);
&.highlighted {
background-color: $scoreWeakMismatchBg;
border-color: $scoreWeakMismatchFg;
}
}
&.comparison-no {
background-color: adjust-color($scoreMismatchBg, $alpha: -0.6);
border-color: adjust-color($scoreMismatchFg, $alpha: -0.6);
&.highlighted {
background-color: $scoreMismatchBg;
border-color: $scoreMismatchFg;
}
}
}
}

View File

@ -9,6 +9,7 @@
<script lang="ts">
import {Component, Prop} from '@f-list/vue-ts';
import Vue from 'vue';
import core from '../../chat/core';
import {formatContactLink, formatContactValue} from './contact_utils';
import { DisplayInfotag } from './interfaces';
// import { Character as CharacterInfo } from '../../interfaces';
@ -33,7 +34,7 @@
// console.log(`Infotag ${this.infotag.id}: ${this.label}`);
const id = this.infotag.id;
if (this.characterMatch) {
if ((core.state.settings.risingAdScore) && (this.characterMatch)) {
const scores = this.theirInterestIsRelevant(id)
? this.characterMatch.them.scores
: (this.yourInterestIsRelevant(id) ? this.characterMatch.you.scores : null);

View File

@ -11,7 +11,7 @@
:highlights="highlights"></kink>
</div>
</template>
<div class="popover popover-top" v-if="((showTooltip) && ((!kink.isCustom) || (!expandedCustom)))" style="display:block;bottom:100%;top:initial;margin-bottom:5px">
<div class="popover popover-top" v-if="((showTooltip) && ((!kink.isCustom) || (!expandedCustom)))">
<div class="arrow" style="left:10%"></div>
<h5 class="popover-header">{{kink.name}}</h5>
<div class="popover-body"><p>{{kink.description}}</p></div>

View File

@ -2,12 +2,12 @@
<div class="character-kinks-block" @contextmenu="contextMenu" @touchstart="contextMenu" @touchend="contextMenu">
<div class="compare-highlight-block d-flex justify-content-between">
<div class="expand-custom-kinks-block form-inline">
<button class="btn btn-primary" @click="toggleExpandedCustomKinks" :disabled="loading">Expand Custom Kinks</button>
<button class="btn btn-primary" @click="toggleExpandedCustomKinks" :disabled="loading">{{(expandedCustoms ? 'Collapse' : 'Expand')}} Custom Kinks</button>
</div>
<div v-if="shared.authenticated" class="quick-compare-block form-inline">
<character-select v-model="characterToCompare"></character-select>
<button class="btn btn-outline-secondary" @click="compareKinks" :disabled="loading || !characterToCompare">
<button class="btn btn-outline-secondary" @click="compareKinks()" :disabled="loading || !characterToCompare">
{{ compareButtonText }}
</button>
</div>
@ -19,7 +19,7 @@
</select>
</div>
</div>
<div class="form-row mt-3">
<div class="form-row mt-3" :class="{ highlighting: !!highlightGroup }">
<div class="col-sm-6 col-lg-3">
<div class="card bg-light">
<div class="card-header">
@ -98,6 +98,8 @@
highlighting: {[key: string]: boolean} = {};
comparison: {[key: string]: KinkChoice} = {};
_ = _;
expandedCustoms = false;
@ -191,7 +193,9 @@
if ((this.character) && (this.character.is_self))
return;
await this.compareKinks(core.characters.ownProfile);
if (core.state.settings.risingAutoCompareKinks) {
await this.compareKinks(core.characters.ownProfile);
}
}
@Watch('character')
@ -202,8 +206,16 @@
await this.compareKinks(core.characters.ownProfile);
}
get kinkGroups(): {[key: string]: KinkGroup | undefined} {
return this.shared.kinks.kink_groups;
get kinkGroups(): KinkGroup[] {
const groups = this.shared.kinks.kink_groups;
return _.sortBy(
_.filter(
groups,
(g) => (!_.isUndefined(g))
),
'name'
) as KinkGroup[];
}
get compareButtonText(): string {