enhance(client): make possible to hide ads

Resolve #9590
Resolve #8996
This commit is contained in:
syuilo 2023-01-16 11:21:04 +09:00
parent 60d9bb0218
commit fe0bb21b37
6 changed files with 51 additions and 2 deletions

View file

@ -982,6 +982,7 @@ _role:
userEachUserListsMax: "ユーザーリスト内のユーザーの最大数" userEachUserListsMax: "ユーザーリスト内のユーザーの最大数"
rateLimitFactor: "レートリミット" rateLimitFactor: "レートリミット"
descriptionOfRateLimitFactor: "小さいほど制限が緩和され、大きいほど制限が強化されます。" descriptionOfRateLimitFactor: "小さいほど制限が緩和され、大きいほど制限が強化されます。"
canHideAds: "広告の非表示"
_condition: _condition:
isLocal: "ローカルユーザー" isLocal: "ローカルユーザー"
isRemote: "リモートユーザー" isRemote: "リモートユーザー"
@ -1032,6 +1033,7 @@ _accountDelete:
_ad: _ad:
back: "戻る" back: "戻る"
reduceFrequencyOfThisAd: "この広告の表示頻度を下げる" reduceFrequencyOfThisAd: "この広告の表示頻度を下げる"
hide: "表示しない"
_forgotPassword: _forgotPassword:
enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。" enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。"

View file

@ -19,6 +19,7 @@ export type RolePolicies = {
canPublicNote: boolean; canPublicNote: boolean;
canInvite: boolean; canInvite: boolean;
canManageCustomEmojis: boolean; canManageCustomEmojis: boolean;
canHideAds: boolean;
driveCapacityMb: number; driveCapacityMb: number;
pinLimit: number; pinLimit: number;
antennaLimit: number; antennaLimit: number;
@ -37,6 +38,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
canPublicNote: true, canPublicNote: true,
canInvite: false, canInvite: false,
canManageCustomEmojis: false, canManageCustomEmojis: false,
canHideAds: false,
driveCapacityMb: 100, driveCapacityMb: 100,
pinLimit: 5, pinLimit: 5,
antennaLimit: 5, antennaLimit: 5,
@ -223,6 +225,7 @@ export class RoleService implements OnApplicationShutdown {
canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)), canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)),
canInvite: calc('canInvite', vs => vs.some(v => v === true)), canInvite: calc('canInvite', vs => vs.some(v => v === true)),
canManageCustomEmojis: calc('canManageCustomEmojis', vs => vs.some(v => v === true)), canManageCustomEmojis: calc('canManageCustomEmojis', vs => vs.some(v => v === true)),
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)), driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)),
pinLimit: calc('pinLimit', vs => Math.max(...vs)), pinLimit: calc('pinLimit', vs => Math.max(...vs)),
antennaLimit: calc('antennaLimit', vs => Math.max(...vs)), antennaLimit: calc('antennaLimit', vs => Math.max(...vs)),

View file

@ -1,5 +1,5 @@
<template> <template>
<div v-if="chosen" :class="$style.root"> <div v-if="chosen && !shouldHide" :class="$style.root">
<div v-if="!showMenu" :class="[$style.main, $style['form_' + chosen.place]]"> <div v-if="!showMenu" :class="[$style.main, $style['form_' + chosen.place]]">
<a :href="chosen.url" target="_blank" :class="$style.link"> <a :href="chosen.url" target="_blank" :class="$style.link">
<img :src="chosen.imageUrl" :class="$style.img"> <img :src="chosen.imageUrl" :class="$style.img">
@ -11,6 +11,7 @@
<div>Ads by {{ host }}</div> <div>Ads by {{ host }}</div>
<!--<MkButton class="button" primary>{{ $ts._ad.like }}</MkButton>--> <!--<MkButton class="button" primary>{{ $ts._ad.like }}</MkButton>-->
<MkButton v-if="chosen.ratio !== 0" :class="$style.menuButton" @click="reduceFrequency">{{ $ts._ad.reduceFrequencyOfThisAd }}</MkButton> <MkButton v-if="chosen.ratio !== 0" :class="$style.menuButton" @click="reduceFrequency">{{ $ts._ad.reduceFrequencyOfThisAd }}</MkButton>
<MkButton v-if="$i && $i.policies.canHideAds" :class="$style.menuButton" @click="hide">{{ $ts._ad.hide }}</MkButton>
<button class="_textButton" @click="toggleMenu">{{ $ts._ad.back }}</button> <button class="_textButton" @click="toggleMenu">{{ $ts._ad.back }}</button>
</div> </div>
</div> </div>
@ -25,6 +26,7 @@ import { host } from '@/config';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import * as os from '@/os'; import * as os from '@/os';
import { $i } from '@/account';
type Ad = (typeof instance)['ads'][number]; type Ad = (typeof instance)['ads'][number];
@ -81,6 +83,7 @@ const choseAd = (): Ad | null => {
}; };
const chosen = ref(choseAd()); const chosen = ref(choseAd());
let shouldHide = $ref(chosen.value && $i && $i.policies.canHideAds && defaultStore.state.hiddenAds.includes(chosen.value.id));
function reduceFrequency(): void { function reduceFrequency(): void {
if (chosen.value == null) return; if (chosen.value == null) return;
@ -90,6 +93,13 @@ function reduceFrequency(): void {
chosen.value = choseAd(); chosen.value = choseAd();
showMenu.value = false; showMenu.value = false;
} }
function hide() {
if (chosen.value == null) return;
defaultStore.push('hiddenAds', chosen.value.id);
os.success();
shouldHide = true;
}
</script> </script>
<style lang="scss" module> <style lang="scss" module>

View file

@ -335,6 +335,26 @@
</MkRange> </MkRange>
</div> </div>
</MkFolder> </MkFolder>
<MkFolder v-if="matchQuery([i18n.ts._role._options.canHideAds, 'canHideAds'])">
<template #label>{{ i18n.ts._role._options.canHideAds }}</template>
<template #suffix>
<span v-if="policies.canHideAds.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span>
<span v-else>{{ policies.canHideAds.value ? i18n.ts.yes : i18n.ts.no }}</span>
<span :class="$style.priorityIndicator"><i :class="getPriorityIcon(policies.canHideAds)"></i></span>
</template>
<div class="_gaps">
<MkSwitch v-model="policies.canHideAds.useDefault" :readonly="readonly">
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
</MkSwitch>
<MkSwitch v-model="policies.canHideAds.value" :disabled="policies.canHideAds.useDefault" :readonly="readonly">
<template #label>{{ i18n.ts.enable }}</template>
</MkSwitch>
<MkRange v-model="policies.canHideAds.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
<template #label>{{ i18n.ts._role.priority }}</template>
</MkRange>
</div>
</MkFolder>
</div> </div>
</FormSlot> </FormSlot>
@ -376,6 +396,7 @@ const ROLE_POLICIES = [
'canPublicNote', 'canPublicNote',
'canInvite', 'canInvite',
'canManageCustomEmojis', 'canManageCustomEmojis',
'canHideAds',
'driveCapacityMb', 'driveCapacityMb',
'pinLimit', 'pinLimit',
'antennaLimit', 'antennaLimit',

View file

@ -121,6 +121,14 @@
</MkInput> </MkInput>
</MkFolder> </MkFolder>
<MkFolder>
<template #label>{{ i18n.ts._role._options.canHideAds }}</template>
<template #suffix>{{ policies.canHideAds ? i18n.ts.yes : i18n.ts.no }}</template>
<MkSwitch v-model="policies.canHideAds">
<template #label>{{ i18n.ts.enable }}</template>
</MkSwitch>
</MkFolder>
<MkButton primary rounded @click="updateBaseRole">{{ i18n.ts.save }}</MkButton> <MkButton primary rounded @click="updateBaseRole">{{ i18n.ts.save }}</MkButton>
</div> </div>
</MkFolder> </MkFolder>
@ -156,6 +164,7 @@ const ROLE_POLICIES = [
'canPublicNote', 'canPublicNote',
'canInvite', 'canInvite',
'canManageCustomEmojis', 'canManageCustomEmojis',
'canHideAds',
'driveCapacityMb', 'driveCapacityMb',
'pinLimit', 'pinLimit',
'antennaLimit', 'antennaLimit',

View file

@ -86,6 +86,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'account', where: 'account',
default: [] as string[], default: [] as string[],
}, },
hiddenAds: {
where: 'account',
default: [] as string[],
},
menu: { menu: {
where: 'deviceAccount', where: 'deviceAccount',
@ -293,10 +297,10 @@ interface Watcher {
/** /**
* () * ()
*/ */
import { miLocalStorage } from './local-storage';
import lightTheme from '@/themes/l-light.json5'; import lightTheme from '@/themes/l-light.json5';
import darkTheme from '@/themes/d-green-lime.json5'; import darkTheme from '@/themes/d-green-lime.json5';
import { Note, UserDetailed } from 'misskey-js/built/entities'; import { Note, UserDetailed } from 'misskey-js/built/entities';
import { miLocalStorage } from './local-storage';
export class ColdDeviceStorage { export class ColdDeviceStorage {
public static default = { public static default = {