mirror of
https://github.com/kokonect-link/cherrypick
synced 2024-11-23 22:56:53 +09:00
feat(client): ページの更新が必要なときに静かに通知する機能を追加
This commit is contained in:
parent
2cc10aa02d
commit
d56b50a5f1
@ -65,6 +65,7 @@
|
||||
- 노트 사이를 띄우는 옵션 활성화 시 알림 페이지의 노트도 띄우도록
|
||||
- 안테나, 그룹, 리스트, 클립 페이지의 생성 버튼을 헤더로 이동
|
||||
- 채팅 디자인 일부 개선
|
||||
- 페이지 새로 고침 팝업을 조용히 알리는 기능 추가
|
||||
- Fix: (Friendly) 위젯 영역에 safe-area-inset-bottom이 적용되지 않음
|
||||
- Fix: (Friendly) 플로팅 메뉴를 길게 눌렀을 때 프로필 이미지를 드래그 할 수 있는 문제
|
||||
- Fix: 위젯 편집 시 헤더 이외의 영역을 눌렀을 때 위젯 설정이 뜨는 문제
|
||||
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
_lang_: "English"
|
||||
requireRefresh: "When the page needs to refresh"
|
||||
performanceWarning: "High resource usage can result in higher device temperatures and faster battery consumption"
|
||||
photosensitiveSeizuresWarning: "Can cause photosensitive seizures"
|
||||
friendlyEnableNotification: "Enable/Disable the notification area"
|
||||
@ -1099,6 +1100,9 @@ later: "Later"
|
||||
goToMisskey: "To CherryPick"
|
||||
additionalEmojiDictionary: "Additional emoji dictionaries"
|
||||
installed: "Installed"
|
||||
_requireRefreshBehavior:
|
||||
dialog: "Show warning dialog"
|
||||
quiet: "Show unobtrusive alert"
|
||||
_initialAccountSetting:
|
||||
accountCreated: "Your account was successfully created!"
|
||||
letsStartAccountSetup: "For starters, let's set up your profile."
|
||||
|
11
locales/index.d.ts
vendored
11
locales/index.d.ts
vendored
@ -3,6 +3,10 @@
|
||||
// Do not edit this file directly.
|
||||
export interface Locale {
|
||||
"_lang_": string;
|
||||
"requireRefresh": string;
|
||||
"performanceWarning": string;
|
||||
"photosensitiveSeizuresWarning": string;
|
||||
"friendlyEnableNotification": string;
|
||||
"useBoldFont": string;
|
||||
"newNoteReceivedNotification": string;
|
||||
"disableRightClick": string;
|
||||
@ -1099,9 +1103,10 @@ export interface Locale {
|
||||
"goToMisskey": string;
|
||||
"additionalEmojiDictionary": string;
|
||||
"installed": string;
|
||||
"performanceWarning": string;
|
||||
"photosensitiveSeizuresWarning": string;
|
||||
"friendlyEnableNotification": string;
|
||||
"_requireRefreshBehavior": {
|
||||
"dialog": string;
|
||||
"quiet": string;
|
||||
};
|
||||
"_initialAccountSetting": {
|
||||
"accountCreated": string;
|
||||
"letsStartAccountSetup": string;
|
||||
|
@ -1,5 +1,6 @@
|
||||
_lang_: "日本語"
|
||||
|
||||
requireRefresh: "페이지 새로 고침이 필요할 때"
|
||||
performanceWarning: "リソースを多く使用するため、デバイスの温度が高くなり、バッテリーの消耗が速くなる可能性があります"
|
||||
photosensitiveSeizuresWarning: "光敏感性発作を起こす可能性があります"
|
||||
friendlyEnableNotification: "通知領域を有効化/無効化"
|
||||
@ -1100,6 +1101,10 @@ goToMisskey: "CherryPickへ"
|
||||
additionalEmojiDictionary: "絵文字の追加辞書"
|
||||
installed: "インストール済み"
|
||||
|
||||
_requireRefreshBehavior:
|
||||
dialog: "ダイアログで通知"
|
||||
quiet: "控えめに通知"
|
||||
|
||||
_initialAccountSetting:
|
||||
accountCreated: "アカウントの作成が完了しました!"
|
||||
letsStartAccountSetup: "アカウントの初期設定を行いましょう。"
|
||||
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
_lang_: "한국어"
|
||||
requireRefresh: "페이지 새로 고침이 필요할 때"
|
||||
performanceWarning: "리소스를 많이 사용하므로, 디바이스의 온도가 높아지고 배터리의 소모가 빨라질 수 있어요"
|
||||
photosensitiveSeizuresWarning: "광과민성 발작을 일으킬 수 있어요"
|
||||
friendlyEnableNotification: "알림 영역 활성화/비활성화"
|
||||
@ -1100,6 +1101,9 @@ later: "나중에"
|
||||
goToMisskey: "CherryPick으로"
|
||||
additionalEmojiDictionary: "이모지 추가 사전"
|
||||
installed: "설치됨"
|
||||
_requireRefreshBehavior:
|
||||
dialog: "알림창 표시"
|
||||
quiet: "조용히 알림"
|
||||
_initialAccountSetting:
|
||||
accountCreated: "계정 생성이 완료되었어요!"
|
||||
letsStartAccountSetup: "계정의 초기 설정을 진행해 볼까요?"
|
||||
|
@ -71,18 +71,21 @@ import { $i } from '@/account';
|
||||
import { defaultStore } from '@/store';
|
||||
import { miLocalStorage } from '@/local-storage';
|
||||
import { unisonReload } from '@/scripts/unison-reload';
|
||||
import { eventBus } from '@/scripts/cherrypick/eventBus';
|
||||
|
||||
const fontSizeBefore = ref(miLocalStorage.getItem('fontSize'));
|
||||
const useBoldFont = ref(miLocalStorage.getItem('useBoldFont'));
|
||||
|
||||
async function reloadAsk() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
if (defaultStore.state.requireRefreshBehavior === 'dialog') {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
unisonReload();
|
||||
unisonReload();
|
||||
} else eventBus.emit('hasRequireRefresh', true);
|
||||
}
|
||||
|
||||
const fontSize = computed(defaultStore.makeGetterSetter('fontSize'));
|
||||
|
@ -215,6 +215,11 @@
|
||||
<option value="quiet">{{ i18n.ts._serverDisconnectedBehavior.quiet }}</option>
|
||||
<option value="none">{{ i18n.ts._serverDisconnectedBehavior.none }}</option>
|
||||
</MkSelect>
|
||||
<MkSelect v-model="requireRefreshBehavior">
|
||||
<template #label>{{ i18n.ts.requireRefresh }}</template>
|
||||
<option value="dialog">{{ i18n.ts._requireRefreshBehavior.dialog }}</option>
|
||||
<option value="quiet">{{ i18n.ts._requireRefreshBehavior.quiet }}</option>
|
||||
</MkSelect>
|
||||
<MkSelect v-model="newNoteReceivedNotificationBehavior">
|
||||
<template #label>{{ i18n.ts.newNoteReceivedNotification }}</template>
|
||||
<option value="default">{{ i18n.ts._newNoteReceivedNotificationBehavior.default }}</option>
|
||||
@ -264,6 +269,7 @@ import { unisonReload } from '@/scripts/unison-reload';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import { miLocalStorage } from '@/local-storage';
|
||||
import { eventBus } from '@/scripts/cherrypick/eventBus';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
|
||||
const lang = ref(miLocalStorage.getItem('lang'));
|
||||
@ -274,13 +280,15 @@ const fontSizeBefore = ref(miLocalStorage.getItem('fontSize'));
|
||||
const useBoldFont = ref(miLocalStorage.getItem('useBoldFont'));
|
||||
|
||||
async function reloadAsk() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
if (requireRefreshBehavior.value === 'dialog') {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
unisonReload();
|
||||
unisonReload();
|
||||
} else eventBus.emit('hasRequireRefresh', true);
|
||||
}
|
||||
|
||||
const overridedDeviceKind = computed(defaultStore.makeGetterSetter('overridedDeviceKind'));
|
||||
@ -319,6 +327,7 @@ const postFormVisibilityHotkey = computed(defaultStore.makeGetterSetter('postFor
|
||||
const newNoteReceivedNotificationBehavior = computed(defaultStore.makeGetterSetter('newNoteReceivedNotificationBehavior'));
|
||||
const fontSize = computed(defaultStore.makeGetterSetter('fontSize'));
|
||||
const collapseDefault = computed(defaultStore.makeGetterSetter('collapseDefault'));
|
||||
const requireRefreshBehavior = computed(defaultStore.makeGetterSetter('requireRefreshBehavior'));
|
||||
|
||||
watch(lang, () => {
|
||||
miLocalStorage.setItem('lang', lang.value as string);
|
||||
|
@ -52,6 +52,7 @@ import { defaultStore } from '@/store';
|
||||
import { unisonReload } from '@/scripts/unison-reload';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import { eventBus } from '@/scripts/cherrypick/eventBus';
|
||||
import { deepClone } from '@/scripts/clone';
|
||||
|
||||
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
||||
@ -64,13 +65,15 @@ const items = ref(defaultStore.state.menu.map(x => ({
|
||||
const menuDisplay = computed(defaultStore.makeGetterSetter('menuDisplay'));
|
||||
|
||||
async function reloadAsk() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
if (defaultStore.state.requireRefreshBehavior === 'dialog') {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
unisonReload();
|
||||
unisonReload();
|
||||
} else eventBus.emit('hasRequireRefresh', true);
|
||||
}
|
||||
|
||||
async function addItem() {
|
||||
|
@ -87,6 +87,7 @@ import { signout, $i } from '@/account';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import { unisonReload } from '@/scripts/unison-reload';
|
||||
import { eventBus } from '@/scripts/cherrypick/eventBus';
|
||||
import FormSection from '@/components/form/section.vue';
|
||||
|
||||
const reportError = computed(defaultStore.makeGetterSetter('reportError'));
|
||||
@ -128,13 +129,15 @@ async function deleteAccount() {
|
||||
}
|
||||
|
||||
async function reloadAsk() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
if (defaultStore.state.requireRefreshBehavior === 'dialog') {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
unisonReload();
|
||||
unisonReload();
|
||||
} else eventBus.emit('hasRequireRefresh', true);
|
||||
}
|
||||
|
||||
watch([
|
||||
|
@ -91,6 +91,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
|
||||
'postFormVisibilityHotkey',
|
||||
'newNoteReceivedNotificationBehavior',
|
||||
'collapseDefault',
|
||||
'requireRefreshBehavior',
|
||||
];
|
||||
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
|
||||
'lightTheme',
|
||||
|
@ -156,13 +156,15 @@ function focus(): void {
|
||||
}
|
||||
|
||||
async function reloadAsk() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
if (defaultStore.state.requireRefreshBehavior === 'dialog') {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
unisonReload();
|
||||
unisonReload();
|
||||
} else eventBus.emit('hasRequireRefresh', true);
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => [{
|
||||
|
@ -367,6 +367,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||
where: 'account',
|
||||
default: true,
|
||||
},
|
||||
requireRefreshBehavior: {
|
||||
where: 'device',
|
||||
default: 'dialog' as 'quiet' | 'dialog',
|
||||
},
|
||||
}));
|
||||
|
||||
// TODO: 他のタブと永続化されたstateを同期
|
||||
|
@ -1,4 +1,11 @@
|
||||
<template>
|
||||
<div v-if="hasRequireRefresh && defaultStore.state.requireRefreshBehavior === 'quiet'" :class="$style.root" class="_panel _shadow" @click="resetRequireRefresh">
|
||||
<div><i class="ti ti-alert-circle"></i> {{ i18n.ts.reloadToApplySetting2 }}</div>
|
||||
<div :class="$style.command" class="_buttons">
|
||||
<MkButton small primary @click="reload">{{ i18n.ts.reload }}</MkButton>
|
||||
<MkButton small>{{ i18n.ts.doNothing }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="hasDisconnected && defaultStore.state.serverDisconnectedBehavior === 'quiet'" :class="$style.root" class="_panel _shadow" @click="resetDisconnected">
|
||||
<div><i class="ti ti-alert-triangle"></i> {{ i18n.ts.disconnectedFromServer }}</div>
|
||||
<div :class="$style.command" class="_buttons">
|
||||
@ -9,15 +16,17 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onUnmounted } from 'vue';
|
||||
import { onMounted, onUnmounted } from 'vue';
|
||||
import { useStream } from '@/stream';
|
||||
import { i18n } from '@/i18n';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os';
|
||||
import { defaultStore } from '@/store';
|
||||
import { eventBus } from '@/scripts/cherrypick/eventBus';
|
||||
|
||||
const zIndex = os.claimZIndex('high');
|
||||
|
||||
let hasRequireRefresh = $ref(false);
|
||||
let hasDisconnected = $ref(false);
|
||||
|
||||
function onDisconnected() {
|
||||
@ -28,12 +37,22 @@ function resetDisconnected() {
|
||||
hasDisconnected = false;
|
||||
}
|
||||
|
||||
function resetRequireRefresh() {
|
||||
hasRequireRefresh = false;
|
||||
}
|
||||
|
||||
function reload() {
|
||||
location.reload();
|
||||
}
|
||||
|
||||
useStream().on('_disconnected_', onDisconnected);
|
||||
|
||||
onMounted(() => {
|
||||
eventBus.on('hasRequireRefresh', (hasRequireRefresh_receive) => {
|
||||
hasRequireRefresh = hasRequireRefresh_receive;
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
useStream().off('_disconnected_', onDisconnected);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user