app work
This commit is contained in:
parent
d4d9065781
commit
a0291b40b2
|
@ -0,0 +1,3 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="11" />
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google" />
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://maven.google.com" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
|
@ -9,10 +9,15 @@ android {
|
|||
|
||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
|
||||
|
||||
implementation project(':capacitor-app')
|
||||
implementation project(':capacitor-camera')
|
||||
implementation project(':capacitor-device')
|
||||
implementation project(':capacitor-preferences')
|
||||
implementation project(':capacitor-push-notifications')
|
||||
implementation project(':capacitor-status-bar')
|
||||
implementation "com.onesignal:OneSignal:4.8.5"
|
||||
}
|
||||
|
||||
apply from: "../../../../node_modules/.pnpm/onesignal-cordova-plugin@3.3.1/node_modules/onesignal-cordova-plugin/build-extras-onesignal.gradle"
|
||||
|
||||
if (hasProperty('postBuildExtras')) {
|
||||
postBuildExtras()
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
package org.calckey.app;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.webkit.WebSettings;
|
||||
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
import com.getcapacitor.Plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MainActivity extends BridgeActivity {
|
||||
void setDarkMode() {
|
||||
|
@ -34,15 +41,4 @@ public class MainActivity extends BridgeActivity {
|
|||
super.onResume();
|
||||
setDarkMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Initializes the Bridge
|
||||
this.init(savedInstanceState, new ArrayList<Class<? extends Plugin>>() {{
|
||||
// Additional plugins you've installed go here
|
||||
// Ex: add(TotallyAwesomePlugin.class);
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||
include ':capacitor-android'
|
||||
project(':capacitor-android').projectDir = new File('../../../node_modules/.pnpm/@capacitor+android@4.7.3_@capacitor+core@4.7.3/node_modules/@capacitor/android/capacitor')
|
||||
|
||||
include ':capacitor-app'
|
||||
project(':capacitor-app').projectDir = new File('../../../node_modules/.pnpm/@capacitor+app@4.1.1_@capacitor+core@4.7.3/node_modules/@capacitor/app/android')
|
||||
|
||||
include ':capacitor-camera'
|
||||
project(':capacitor-camera').projectDir = new File('../../../node_modules/.pnpm/@capacitor+camera@4.1.4_@capacitor+core@4.7.3/node_modules/@capacitor/camera/android')
|
||||
|
||||
include ':capacitor-device'
|
||||
project(':capacitor-device').projectDir = new File('../../../node_modules/.pnpm/@capacitor+device@4.1.0_@capacitor+core@4.7.3/node_modules/@capacitor/device/android')
|
||||
|
||||
include ':capacitor-preferences'
|
||||
project(':capacitor-preferences').projectDir = new File('../../../node_modules/.pnpm/@capacitor+preferences@4.0.2_@capacitor+core@4.7.3/node_modules/@capacitor/preferences/android')
|
||||
|
||||
include ':capacitor-push-notifications'
|
||||
project(':capacitor-push-notifications').projectDir = new File('../../../node_modules/.pnpm/@capacitor+push-notifications@4.1.2_@capacitor+core@4.7.3/node_modules/@capacitor/push-notifications/android')
|
||||
|
||||
include ':capacitor-status-bar'
|
||||
project(':capacitor-status-bar').projectDir = new File('../../../node_modules/.pnpm/@capacitor+status-bar@4.1.1_@capacitor+core@4.7.3/node_modules/@capacitor/status-bar/android')
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>remote-notification</string>
|
||||
</array>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
|
|
@ -11,7 +11,13 @@ install! 'cocoapods', :disable_input_output_paths => true
|
|||
def capacitor_pods
|
||||
pod 'Capacitor', :path => '../../../../node_modules/.pnpm/@capacitor+ios@4.7.3_@capacitor+core@4.7.3/node_modules/@capacitor/ios'
|
||||
pod 'CapacitorCordova', :path => '../../../../node_modules/.pnpm/@capacitor+ios@4.7.3_@capacitor+core@4.7.3/node_modules/@capacitor/ios'
|
||||
|
||||
pod 'CapacitorApp', :path => '../../../../node_modules/.pnpm/@capacitor+app@4.1.1_@capacitor+core@4.7.3/node_modules/@capacitor/app'
|
||||
pod 'CapacitorCamera', :path => '../../../../node_modules/.pnpm/@capacitor+camera@4.1.4_@capacitor+core@4.7.3/node_modules/@capacitor/camera'
|
||||
pod 'CapacitorDevice', :path => '../../../../node_modules/.pnpm/@capacitor+device@4.1.0_@capacitor+core@4.7.3/node_modules/@capacitor/device'
|
||||
pod 'CapacitorPreferences', :path => '../../../../node_modules/.pnpm/@capacitor+preferences@4.0.2_@capacitor+core@4.7.3/node_modules/@capacitor/preferences'
|
||||
pod 'CapacitorPushNotifications', :path => '../../../../node_modules/.pnpm/@capacitor+push-notifications@4.1.2_@capacitor+core@4.7.3/node_modules/@capacitor/push-notifications'
|
||||
pod 'CapacitorStatusBar', :path => '../../../../node_modules/.pnpm/@capacitor+status-bar@4.1.1_@capacitor+core@4.7.3/node_modules/@capacitor/status-bar'
|
||||
pod 'CordovaPluginsStatic', :path => '../capacitor-cordova-ios-plugins'
|
||||
end
|
||||
|
||||
target 'App' do
|
||||
|
|
|
@ -95,6 +95,7 @@
|
|||
"dependencies": {
|
||||
"@capacitor/android": "^4.7.3",
|
||||
"@capacitor/app": "^4.1.1",
|
||||
"@capacitor/camera": "^4.1.4",
|
||||
"@capacitor/core": "^4.7.3",
|
||||
"@capacitor/device": "^4.1.0",
|
||||
"@capacitor/ios": "^4.7.3",
|
||||
|
|
|
@ -4,6 +4,7 @@ import { showSuspendedDialog } from "./scripts/show-suspended-dialog";
|
|||
import { i18n } from "./i18n";
|
||||
import { del, get, set } from "@/scripts/idb-proxy";
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
import { apiUrl } from "@/config";
|
||||
// #v-endif
|
||||
|
@ -44,6 +45,7 @@ export async function signout() {
|
|||
|
||||
const accounts = await getAccounts();
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
//#region Remove service worker registration
|
||||
try {
|
||||
|
@ -117,7 +119,32 @@ export async function removeAccount(id: Account["id"]) {
|
|||
if (accounts.length > 0) await set("accounts", accounts);
|
||||
else await del("accounts");
|
||||
}
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
function fetchAccount(
|
||||
token: string,
|
||||
instanceUrl: string
|
||||
): Promise<Account & { instanceUrl: string }> {
|
||||
return new misskey.api.APIClient({ origin: instanceUrl, credential: token })
|
||||
.request("i")
|
||||
.then((res) => {
|
||||
return { ...(res as Account), token, instanceUrl };
|
||||
})
|
||||
.catch((res) => {
|
||||
if (res.error.id === "a8c724b3-6e9c-4b46-b1a8-bc3ed6258370") {
|
||||
showSuspendedDialog().then(() => {
|
||||
signout();
|
||||
});
|
||||
} else {
|
||||
alert({
|
||||
type: "error",
|
||||
title: i18n.ts.failedToFetchAccountInformation,
|
||||
text: JSON.stringify(res.error),
|
||||
});
|
||||
}
|
||||
return Promise.reject(res);
|
||||
});
|
||||
}
|
||||
// #v-else
|
||||
function fetchAccount(token: string): Promise<Account> {
|
||||
return new Promise((done, fail) => {
|
||||
// Fetch user
|
||||
|
@ -149,32 +176,7 @@ function fetchAccount(token: string): Promise<Account> {
|
|||
.catch(fail);
|
||||
});
|
||||
}
|
||||
|
||||
function fetchAccount(
|
||||
token: string,
|
||||
instanceUrl: string
|
||||
): Promise<Account & { instanceUrl: string }> {
|
||||
return new misskey.api.APIClient({ origin: instanceUrl, credential: token })
|
||||
.request("i")
|
||||
.then((res) => {
|
||||
return { ...(res as Account), token, instanceUrl };
|
||||
})
|
||||
.catch((res) => {
|
||||
if (res.error.id === "a8c724b3-6e9c-4b46-b1a8-bc3ed6258370") {
|
||||
showSuspendedDialog().then(() => {
|
||||
signout();
|
||||
});
|
||||
} else {
|
||||
alert({
|
||||
type: "error",
|
||||
title: i18n.ts.failedToFetchAccountInformation,
|
||||
text: JSON.stringify(res.error),
|
||||
});
|
||||
}
|
||||
return Promise.reject(res);
|
||||
});
|
||||
}
|
||||
|
||||
// #v-endif
|
||||
export function updateAccount(accountData: Object) {
|
||||
for (const [key, value] of Object.entries(accountData)) {
|
||||
$i[key] = value;
|
||||
|
@ -325,11 +327,30 @@ export async function openAccountMenu(
|
|||
const accountItemPromises = storedAccounts.map(
|
||||
(a) =>
|
||||
new Promise((res) => {
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
const client = new misskey.api.APIClient({
|
||||
origin: a.instanceUrl,
|
||||
credential: a.token,
|
||||
});
|
||||
client
|
||||
.request("users/show", {
|
||||
userIds: [a.id],
|
||||
})
|
||||
.then((accounts) => {
|
||||
const account = accounts.find((x) => x.id === a.id);
|
||||
if (account == null) return res(null);
|
||||
|
||||
client.request("meta").then((meta) => {
|
||||
res(createItem({ ...account, host: meta.name }));
|
||||
});
|
||||
});
|
||||
// #v-else
|
||||
accountsPromise.then((accounts) => {
|
||||
const account = accounts.find((x) => x.id === a.id);
|
||||
if (account == null) return res(null);
|
||||
res(createItem(account));
|
||||
});
|
||||
// #v-endif
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -357,12 +378,16 @@ export async function openAccountMenu(
|
|||
showSigninDialog();
|
||||
},
|
||||
},
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
{
|
||||
text: i18n.ts.createAccount,
|
||||
action: () => {
|
||||
createAccount();
|
||||
},
|
||||
},
|
||||
// #v-endif
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
<template>
|
||||
<MkA v-if="url.startsWith('/')" v-user-preview="canonical" class="akbvjaqn" :class="{ isMe }" :to="url" :style="{ background: bgCss }" @click.stop>
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
<img
|
||||
:class="$style.icon"
|
||||
:src="`${$i.instanceUrl}/avatar/@${username}@${host}`"
|
||||
alt=""
|
||||
/>
|
||||
// #v-else
|
||||
<img class="icon" :src="`/avatar/@${username}@${host}`" alt="">
|
||||
// #v-endif
|
||||
<span class="main">
|
||||
<span class="username">@{{ username }}</span>
|
||||
<span v-if="(host != localHost) || $store.state.showFullAcct" class="host">@{{ toUnicode(host) }}</span>
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
</a>
|
||||
<button v-else-if="item.type === 'user' && !items.hidden" :tabindex="i" class="_button item" :class="{ active: item.active }" :disabled="item.active" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
||||
<MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/>
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
[{{ item.user.host }}]
|
||||
// #v-endif
|
||||
<span v-if="item.indicate" class="indicator"><i class="ph-circle ph-fill"></i></span>
|
||||
</button>
|
||||
<span v-else-if="item.type === 'switch'" :tabindex="i" class="item" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
||||
|
|
|
@ -1,4 +1,56 @@
|
|||
<template>
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
<form class="eppvobhk" :class="{ signing }" @submit.prevent="onSubmit">
|
||||
<div class="normal-signin">
|
||||
{{ i18n.ts.ririca.instance }}
|
||||
<MkSelect v-model="instanceUrl" large :model-value="instances[0]?.url">
|
||||
<option value="other">
|
||||
{{ i18n.ts.ririca.selectInstanceYourself }}
|
||||
</option>
|
||||
<option
|
||||
v-for="(instance, i) in instances"
|
||||
:key="instance.url"
|
||||
:value="instance.url"
|
||||
:selected="i === 0"
|
||||
>
|
||||
{{ instance.name }}
|
||||
</option>
|
||||
</MkSelect>
|
||||
<template v-if="instanceUrl === 'other'">
|
||||
URL
|
||||
<MkInput
|
||||
v-model="instanceUrlOther"
|
||||
:spellcheck="false"
|
||||
autofocus
|
||||
required
|
||||
/>
|
||||
</template>
|
||||
{{ i18n.ts.ririca.accessToken }}
|
||||
<MkInput
|
||||
v-model="token"
|
||||
:spellcheck="false"
|
||||
autofocus
|
||||
required
|
||||
data-cy-signin-username
|
||||
></MkInput>
|
||||
<MkButton
|
||||
class="_formBlock"
|
||||
type="submit"
|
||||
primary
|
||||
:disabled="signing"
|
||||
style="margin: 0 auto"
|
||||
>
|
||||
{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}
|
||||
</MkButton>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: center"></div>
|
||||
<a
|
||||
href="https://misskey.io/notes/99l9jqqun2"
|
||||
target="_blank"
|
||||
style="color: var(--link); text-align: center"
|
||||
>{{ i18n.ts.ririca.howToCreateToken }}</a>
|
||||
</form>
|
||||
// #v-else
|
||||
<form class="eppvobhk _monolithic_" :class="{ signing, totpLogin }" @submit.prevent="onSubmit">
|
||||
<div class="auth _section _formRoot">
|
||||
<div v-show="withAvatar" class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null, marginBottom: message ? '1.5em' : null }"></div>
|
||||
|
@ -46,9 +98,11 @@
|
|||
<a v-if="meta && meta.enableDiscordIntegration" class="_borderButton _gap" :href="`${apiUrl}/signin/discord`"><i class="ph-discord-logo ph-bold ph-lg" style="margin-right: 4px;"></i>{{ i18n.t('signinWith', { x: 'Discord' }) }}</a>
|
||||
</div>
|
||||
</form>
|
||||
// #v-endif
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MkSelect from "@/components/form/select.vue";
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { toUnicode } from 'punycode/';
|
||||
import { showSuspendedDialog } from '../scripts/show-suspended-dialog';
|
||||
|
@ -67,14 +121,23 @@ let user = $ref(null);
|
|||
let username = $ref('');
|
||||
let password = $ref('');
|
||||
let token = $ref('');
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
let host = $ref(toUnicode(configHost));
|
||||
let totpLogin = $ref(false);
|
||||
// #v-endif
|
||||
let credential = $ref(null);
|
||||
let challengeData = $ref(null);
|
||||
let queryingKey = $ref(false);
|
||||
let hCaptchaResponse = $ref(null);
|
||||
let reCaptchaResponse = $ref(null);
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
const instanceUrl = $ref("");
|
||||
const instanceUrlOther = $ref("");
|
||||
// #v-endif
|
||||
|
||||
const meta = $computed(() => instance);
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
@ -111,10 +174,24 @@ function onUsernameChange() {
|
|||
|
||||
function onLogin(res) {
|
||||
if (props.autoSet) {
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
return login(res.i, res.instance);
|
||||
// #v-else
|
||||
return login(res.i);
|
||||
// #v-endif
|
||||
}
|
||||
}
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
const instanceUrlResult = $computed(() => {
|
||||
if (instanceUrl === "other") {
|
||||
// うっかりhttps://を入れてもreplaceされるから大丈夫
|
||||
// new URL.origin
|
||||
return new URL("https://" + instanceUrlOther.replace("https://", ""))
|
||||
.origin;
|
||||
}
|
||||
return "https://" + instanceUrl;
|
||||
});
|
||||
// #v-endif
|
||||
function queryKey() {
|
||||
queryingKey = true;
|
||||
return navigator.credentials.get({
|
||||
|
@ -145,8 +222,13 @@ function queryKey() {
|
|||
'g-recaptcha-response': reCaptchaResponse,
|
||||
});
|
||||
}).then(res => {
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
emit("login", { ...res, instance: instanceUrl });
|
||||
return onLogin({ ...res, instance: instanceUrl });
|
||||
// #v-else
|
||||
emit('login', res);
|
||||
return onLogin(res);
|
||||
// #v-endif
|
||||
}).catch(err => {
|
||||
if (err === null) return;
|
||||
os.alert({
|
||||
|
@ -160,6 +242,11 @@ function queryKey() {
|
|||
function onSubmit() {
|
||||
signing = true;
|
||||
console.log('submit');
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
if (!token.valueOf()) {
|
||||
login(token, instanceUrlResult);
|
||||
signing = false;
|
||||
// #v-else
|
||||
if (!totpLogin && user && user.twoFactorEnabled) {
|
||||
if (window.PublicKeyCredential && user.securityKeys) {
|
||||
os.api('signin', {
|
||||
|
@ -188,6 +275,7 @@ function onSubmit() {
|
|||
emit('login', res);
|
||||
onLogin(res);
|
||||
}).catch(loginFailed);
|
||||
// #v-endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,6 +328,15 @@ function resetPassword() {
|
|||
os.popup(defineAsyncComponent(() => import('@/components/MkForgotPassword.vue')), {}, {
|
||||
}, 'closed');
|
||||
}
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
let instances = $ref([]);
|
||||
fetch("https://api.calckey.org/instances.json").then((res) => {
|
||||
res.json().then((data) => {
|
||||
instances = data.instancesInfos;
|
||||
});
|
||||
});
|
||||
// #v-endif
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
<template>
|
||||
<img v-if="customEmoji" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt" decoding="async"/>
|
||||
<img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" :alt="alt" :title="alt" decoding="async"/>
|
||||
<img v-else-if="char && !useOsNativeEmojis" class="mk-emoji"
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
:src="char2path(char)"
|
||||
// #v-else
|
||||
:src="url"
|
||||
// #v-endif
|
||||
:alt="alt" :title="alt" decoding="async"/>
|
||||
<span v-else-if="char && useOsNativeEmojis">{{ char }}</span>
|
||||
<span v-else>{{ emoji }}</span>
|
||||
</template>
|
||||
|
@ -12,6 +18,7 @@ import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
|||
import { char2filePath } from '@/scripts/twemoji-base';
|
||||
import { defaultStore } from '@/store';
|
||||
import { instance } from '@/instance';
|
||||
import { url as instanceUrl } from "@/config";
|
||||
|
||||
const props = defineProps<{
|
||||
emoji: string;
|
||||
|
@ -28,7 +35,10 @@ const ce = computed(() => props.customEmojis ?? instance.emojis ?? []);
|
|||
const customEmoji = computed(() => isCustom.value ? ce.value.find(x => x.name === props.emoji.substr(1, props.emoji.length - 2)) : null);
|
||||
const url = computed(() => {
|
||||
if (char.value) {
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
// #v-else
|
||||
return char2filePath(char.value);
|
||||
// #v-endif
|
||||
} else {
|
||||
return defaultStore.state.disableShowingAnimatedImages
|
||||
? getStaticImageUrl(customEmoji.value.url)
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
import { $i } from "@/account";
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
const address = $i ? new URL($i.instanceUrl) : null;
|
||||
// #v-else
|
||||
const address = new URL(location.href);
|
||||
// #v-endif
|
||||
const siteName = (
|
||||
document.querySelector('meta[property="og:site_name"]') as HTMLMetaElement
|
||||
)?.content;
|
||||
|
||||
export const host = address.host;
|
||||
export const hostname = address.hostname;
|
||||
export const host = address?.host;
|
||||
export const hostname = address?.hostname;
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
export const url = $i?.instanceUrl;
|
||||
// #v-else
|
||||
export const url = address.origin;
|
||||
// #v-endif
|
||||
export const apiUrl = `${url}/api`;
|
||||
export const wsUrl = `${url
|
||||
.replace("http://", "ws://")
|
||||
|
|
|
@ -50,10 +50,11 @@ import { reloadChannel } from "@/scripts/unison-reload";
|
|||
import { reactionPicker } from "@/scripts/reaction-picker";
|
||||
import { getUrlWithoutLoginId } from "@/scripts/login-id";
|
||||
import { getAccountFromId } from "@/scripts/get-account-from-id";
|
||||
import { Device } from "@capacitor/device";
|
||||
import { Device, DeviceInfo } from "@capacitor/device";
|
||||
import { App } from "@capacitor/app";
|
||||
import lightTheme from "@/themes/_light.json5";
|
||||
export let storedDeviceInfo: Object;
|
||||
import lightThemeDefault from "@/themes/_light.json5";
|
||||
import OneSignal from "onesignal-cordova-plugin";
|
||||
export let storedDeviceInfo: DeviceInfo;
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
const onesignal_app_id = "efe09597-0778-4156-97b7-0bf8f52c21a7";
|
||||
// #v-endif
|
||||
|
@ -122,7 +123,7 @@ const onesignal_app_id = "efe09597-0778-4156-97b7-0bf8f52c21a7";
|
|||
|
||||
let isMobileApp = false;
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
isMobileApp = false;
|
||||
isMobileApp = true;
|
||||
// #v-endif
|
||||
|
||||
// If mobile, insert the viewport meta tag
|
||||
|
@ -214,11 +215,13 @@ const onesignal_app_id = "efe09597-0778-4156-97b7-0bf8f52c21a7";
|
|||
if (_DEV_) {
|
||||
console.log("not signed in");
|
||||
}
|
||||
applyTheme(lightTheme);
|
||||
applyTheme(lightThemeDefault);
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
const fetchInstanceMetaPromise = fetchInstance();
|
||||
|
||||
fetchInstanceMetaPromise.then(() => {
|
||||
|
@ -227,7 +230,7 @@ const onesignal_app_id = "efe09597-0778-4156-97b7-0bf8f52c21a7";
|
|||
// Init service worker
|
||||
initializeSw();
|
||||
});
|
||||
|
||||
// #v-endif
|
||||
const app = createApp(
|
||||
window.location.search === "?zen"
|
||||
? defineAsyncComponent(() => import("@/ui/zen.vue"))
|
||||
|
@ -287,7 +290,11 @@ const onesignal_app_id = "efe09597-0778-4156-97b7-0bf8f52c21a7";
|
|||
window.onerror = null;
|
||||
window.onunhandledrejection = null;
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
reactionPicker.init();
|
||||
// #v-endif
|
||||
|
||||
if (splash) {
|
||||
splash.style.opacity = "0";
|
||||
|
@ -325,6 +332,45 @@ const onesignal_app_id = "efe09597-0778-4156-97b7-0bf8f52c21a7";
|
|||
}
|
||||
}
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
App.addListener("backButton", (canGoBack) => {
|
||||
if (canGoBack) {
|
||||
history.back();
|
||||
} else {
|
||||
App.exitApp();
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
async function afterLoginSetup() {
|
||||
if (!$i) return;
|
||||
const hotkeys = {
|
||||
d: (): void => {
|
||||
defaultStore.set("darkMode", !defaultStore.state.darkMode);
|
||||
},
|
||||
s: search,
|
||||
["p|n"]: post,
|
||||
};
|
||||
|
||||
//shortcut
|
||||
document.addEventListener("keydown", makeHotkey(hotkeys));
|
||||
reactionPicker.init();
|
||||
const fetchInstanceMetaPromise = fetchInstance();
|
||||
|
||||
fetchInstanceMetaPromise.then(() => {
|
||||
localStorage.setItem("v", instance.version);
|
||||
|
||||
// Init service worker
|
||||
initializeSw();
|
||||
});
|
||||
|
||||
applyTheme(
|
||||
defaultStore.reactiveState.darkMode.value ?
|
||||
ColdDeviceStorage.get("darkTheme") :
|
||||
ColdDeviceStorage.get("lightTheme")
|
||||
)
|
||||
// #v-endif
|
||||
|
||||
// NOTE: この処理は必ず↑のクライアント更新時処理より後に来ること(テーマ再構築のため)
|
||||
watch(
|
||||
defaultStore.reactiveState.darkMode,
|
||||
|
@ -365,6 +411,9 @@ const onesignal_app_id = "efe09597-0778-4156-97b7-0bf8f52c21a7";
|
|||
});
|
||||
//#endregion
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
fetchInstanceMetaPromise.then(() => {
|
||||
if (defaultStore.state.themeInitial) {
|
||||
if (instance.defaultLightTheme != null)
|
||||
|
@ -380,6 +429,7 @@ const onesignal_app_id = "efe09597-0778-4156-97b7-0bf8f52c21a7";
|
|||
defaultStore.set("themeInitial", false);
|
||||
}
|
||||
});
|
||||
// #v-endif
|
||||
|
||||
watch(
|
||||
defaultStore.reactiveState.useBlurEffectForModal,
|
||||
|
@ -436,12 +486,16 @@ const onesignal_app_id = "efe09597-0778-4156-97b7-0bf8f52c21a7";
|
|||
});
|
||||
}
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
const hotkeys = {
|
||||
d: (): void => {
|
||||
defaultStore.set("darkMode", !defaultStore.state.darkMode);
|
||||
},
|
||||
s: search,
|
||||
};
|
||||
// #v-endif
|
||||
|
||||
if ($i) {
|
||||
// only add post shortcuts if logged in
|
||||
|
@ -544,6 +598,45 @@ const onesignal_app_id = "efe09597-0778-4156-97b7-0bf8f52c21a7";
|
|||
});
|
||||
}
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
if (storedDeviceInfo.platform === "web") return;
|
||||
OneSignal.setAppId(onesignal_app_id);
|
||||
const deviceId = await Device.getId();
|
||||
OneSignal.setExternalUserId(deviceId.uuid);
|
||||
/*const res = await fetch(import.meta.env.VITE_NOTIFICATION_TOKEN_ENDPOINT, {
|
||||
method: "POST", // *GET, POST, PUT, DELETE, etc.
|
||||
mode: "cors", // no-cors, *cors, same-origin
|
||||
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
|
||||
credentials: "same-origin", // include, *same-origin, omit
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
redirect: "follow", // manual, *follow, error
|
||||
referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
|
||||
body: JSON.stringify({
|
||||
misskey_token: $i.token,
|
||||
device_id: deviceId.uuid,
|
||||
instance_url: $i.instanceUrl,
|
||||
}),
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
// throw err
|
||||
});
|
||||
console.info(res);*/
|
||||
OneSignal.setNotificationOpenedHandler(function (jsonData) {
|
||||
console.log(`notificationOpenedCallback: ${JSON.stringify(jsonData)}`);
|
||||
});
|
||||
// Prompts the user for notification permissions.
|
||||
// * Since this shows a generic native prompt, we recommend instead using an In-App Message to prompt for notification permission (See step 7) to better communicate to your users what notifications they will get.
|
||||
OneSignal.promptForPushNotificationsWithUserResponse(function (accepted) {
|
||||
console.log(`User accepted notifications: ${accepted}`);
|
||||
});
|
||||
// #v-endif
|
||||
|
||||
// shortcut
|
||||
document.addEventListener("keydown", makeHotkey(hotkeys));
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
}
|
||||
// #v-else
|
||||
})();
|
||||
// #v-endif
|
||||
|
|
|
@ -15,7 +15,11 @@ import { $i } from "@/account";
|
|||
export const pendingApiRequestsCount = ref(0);
|
||||
|
||||
const apiClient = new Misskey.api.APIClient({
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
origin: $i?.instanceUrl || window.location.origin,
|
||||
// #v-else
|
||||
origin: url,
|
||||
// #v-endif
|
||||
});
|
||||
|
||||
export const api = ((
|
||||
|
|
|
@ -78,6 +78,9 @@ import { definePageMetadata } from '@/scripts/page-metadata';
|
|||
import { deviceKind } from '@/scripts/device-kind';
|
||||
import 'swiper/scss';
|
||||
import 'swiper/scss/virtual';
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
import { Camera } from "@capacitor/camera";
|
||||
// #v-endif
|
||||
|
||||
if (defaultStore.reactiveState.tutorial.value !== -1) {
|
||||
os.popup(XTutorial, {}, {}, 'closed');
|
||||
|
@ -339,6 +342,13 @@ onMounted(() => {
|
|||
syncSlide(timelines.indexOf(swiperRef.activeIndex));
|
||||
});
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
const permissionState = await Camera.checkPermissions();
|
||||
if (!permissionState.camera) {
|
||||
Camera.requestPermissions({ permissions: ["photos", "camera"] });
|
||||
}
|
||||
// #v-endif
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
<template>
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
<div class="rsqzvsbo">
|
||||
// #v-else
|
||||
<div v-if="meta" class="rsqzvsbo">
|
||||
// #v-endif
|
||||
<div class="top">
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
<MkFeaturedPhotos class="bg"/>
|
||||
<XTimeline class="tl"/>
|
||||
// #v-endif
|
||||
<div class="shape1"></div>
|
||||
<div class="shape2"></div>
|
||||
<img src="/client-assets/misskey.svg" class="misskey"/>
|
||||
|
@ -20,20 +28,46 @@
|
|||
<MkEmoji :normal="true" :no-style="true" emoji="🍮"/>
|
||||
</div>
|
||||
<div class="main">
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
<img :src="$instance.iconUrl || $instance.faviconUrl || '/favicon.ico'" alt="" class="icon"/>
|
||||
// #v-endif
|
||||
<button class="_button _acrylic menu" @click="showMenu"><i class="ph-dots-three-outline ph-bold ph-lg"></i></button>
|
||||
<div class="fg">
|
||||
<h1>
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
<span class="text">Calckey Mobile</span>
|
||||
// #v-else
|
||||
<img class="logo" v-if="meta.logoImageUrl" :src="meta.logoImageUrl">
|
||||
<span v-else class="text">{{ instanceName }}</span>
|
||||
// #v-endif
|
||||
</h1>
|
||||
<div class="about">
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
<div class="desc" v-html="i18n.ts.headlineMisskey"></div>
|
||||
// #v-else
|
||||
<div class="desc" v-html="meta.description || i18n.ts.headlineMisskey"></div>
|
||||
// #v-endif
|
||||
</div>
|
||||
<div class="action">
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
<div>
|
||||
<input id="term" v-model="isTerm" type="checkbox" /><label
|
||||
for="term"
|
||||
>
|
||||
Agree to Privacy Policy and Terms of Use</label
|
||||
><br />
|
||||
<a href="https://riinswork.space/missRirica/privacy/">
|
||||
Read Privacy Policy and Terms of Use
|
||||
</a>
|
||||
</div>
|
||||
<MkButton inline rounded data-cy-signin :disabled="!isTerm" @click="signin()">{{ i18n.ts.login }}</MkButton>
|
||||
// #v-else
|
||||
<MkButton inline rounded gradate data-cy-signup style="margin-right: 12px;" @click="signup()">{{ i18n.ts.signup }}</MkButton>
|
||||
<MkButton inline rounded data-cy-signin @click="signin()">{{ i18n.ts.login }}</MkButton>
|
||||
<MkButton inline rounded style="margin-left: 12px; margin-top: 12px;" onclick="window.location.href='/explore'">Explore</MkButton>
|
||||
// #v-endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -60,16 +94,23 @@ import MkButton from '@/components/MkButton.vue';
|
|||
import XNote from '@/components/MkNote.vue';
|
||||
import MkFeaturedPhotos from '@/components/MkFeaturedPhotos.vue';
|
||||
import { host, instanceName } from '@/config';
|
||||
import { ref, watch } from "vue";
|
||||
import * as os from '@/os';
|
||||
import number from '@/filters/number';
|
||||
import { i18n } from '@/i18n';
|
||||
import { langs as _langs } from "@/config";
|
||||
|
||||
const langs = ref(_langs);
|
||||
const lang = ref(localStorage.getItem("lang"));
|
||||
|
||||
let isTerm = $ref();
|
||||
let meta = $ref();
|
||||
let stats = $ref();
|
||||
let tags = $ref();
|
||||
let onlineUsersCount = $ref();
|
||||
let instances = $ref();
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
os.api('meta', { detail: true }).then(_meta => {
|
||||
meta = _meta;
|
||||
});
|
||||
|
@ -95,19 +136,22 @@ os.api('federation/instances', {
|
|||
}).then(_instances => {
|
||||
instances = _instances;
|
||||
});
|
||||
|
||||
// #v-endif
|
||||
function signin() {
|
||||
os.popup(XSigninDialog, {
|
||||
autoSet: true,
|
||||
}, {}, 'closed');
|
||||
}
|
||||
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
function signup() {
|
||||
os.popup(XSignupDialog, {
|
||||
autoSet: true,
|
||||
}, {}, 'closed');
|
||||
}
|
||||
|
||||
// #v-endif
|
||||
function showMenu(ev) {
|
||||
os.popupMenu([{
|
||||
text: i18n.ts.instanceInfo,
|
||||
|
@ -123,6 +167,34 @@ function showMenu(ev) {
|
|||
},
|
||||
}], ev.currentTarget ?? ev.target);
|
||||
}
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
watch(lang, () => {
|
||||
localStorage.setItem("lang", lang.value as string);
|
||||
localStorage.removeItem("locale");
|
||||
});
|
||||
|
||||
watch([lang], async () => {
|
||||
await reloadAsk();
|
||||
});
|
||||
|
||||
async function reloadAsk() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: "info",
|
||||
text: i18n.ts.reloadToApplySetting,
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
unisonReload();
|
||||
}
|
||||
|
||||
function unisonReload(path?: string) {
|
||||
if (path !== undefined) {
|
||||
location.href = path;
|
||||
} else {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
// #v-endif
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -73,7 +73,11 @@ export default defineComponent({
|
|||
MkButton,
|
||||
XNote,
|
||||
MkFeaturedPhotos,
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
XTimeline,
|
||||
// #v-endif
|
||||
},
|
||||
|
||||
data() {
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
<template>
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
<XEntrance />
|
||||
// #v-else
|
||||
<div v-if="meta">
|
||||
<XSetup v-if="meta.requireSetup"/>
|
||||
<XEntrance v-else/>
|
||||
</div>
|
||||
// #v-endif
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import XEntrance from './welcome.entrance.a.vue';
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
//...
|
||||
// #v-else
|
||||
import { computed } from 'vue';
|
||||
import XSetup from './welcome.setup.vue';
|
||||
import XEntrance from './welcome.entrance.a.vue';
|
||||
import { instanceName } from '@/config';
|
||||
import * as os from '@/os';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
@ -27,4 +34,5 @@ definePageMetadata(computed(() => ({
|
|||
title: instanceName,
|
||||
icon: null,
|
||||
})));
|
||||
// #v-endif
|
||||
</script>
|
||||
|
|
|
@ -15,6 +15,9 @@ import lightTheme from "@/themes/_light.json5";
|
|||
import darkTheme from "@/themes/_dark.json5";
|
||||
import { deepClone } from "./clone";
|
||||
|
||||
import { StatusBar, Style } from "@capacitor/status-bar";
|
||||
import { storedDeviceInfo } from "@/init";
|
||||
|
||||
export const themeProps = Object.keys(lightTheme.props).filter(
|
||||
(key) => !key.startsWith("X"),
|
||||
);
|
||||
|
@ -140,6 +143,13 @@ function compile(theme: Theme): Record<string, string> {
|
|||
return color.saturate(arg);
|
||||
}
|
||||
}
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
if (storedDeviceInfo.platform === "ios") {
|
||||
StatusBar.setStyle({
|
||||
style: theme.base === "dark" ? Style.Dark : Style.Light,
|
||||
});
|
||||
}
|
||||
// #v-endif
|
||||
|
||||
// other case
|
||||
return tinycolor(val);
|
||||
|
|
|
@ -5,7 +5,11 @@ import { url } from "@/config";
|
|||
|
||||
export const stream = markRaw(
|
||||
new Misskey.Stream(
|
||||
// #v-ifdef VITE_CAPACITOR
|
||||
$i? $i.instanceUrl : "localhost",
|
||||
// #v-else
|
||||
url,
|
||||
// #v-endif
|
||||
$i
|
||||
? {
|
||||
token: $i.token,
|
||||
|
|
|
@ -81,7 +81,6 @@ const isTimelineAvailable = !instance.disableLocalTimeline || !instance.disableR
|
|||
let showMenu = $ref(false);
|
||||
let isDesktop = $ref(window.innerWidth >= DESKTOP_THRESHOLD);
|
||||
let narrow = $ref(window.innerWidth < 1280);
|
||||
let meta = $ref();
|
||||
|
||||
const keymap = $computed(() => {
|
||||
return {
|
||||
|
@ -95,10 +94,6 @@ const keymap = $computed(() => {
|
|||
|
||||
const root = $computed(() => mainRouter.currentRoute.value.name === 'index');
|
||||
|
||||
os.api('meta', { detail: true }).then(res => {
|
||||
meta = res;
|
||||
});
|
||||
|
||||
function signin() {
|
||||
os.popup(XSigninDialog, {
|
||||
autoSet: true,
|
||||
|
|
|
@ -598,6 +598,9 @@ importers:
|
|||
'@capacitor/app':
|
||||
specifier: ^4.1.1
|
||||
version: 4.1.1(@capacitor/core@4.7.3)
|
||||
'@capacitor/camera':
|
||||
specifier: ^4.1.4
|
||||
version: 4.1.4(@capacitor/core@4.7.3)
|
||||
'@capacitor/core':
|
||||
specifier: ^4.7.3
|
||||
version: 4.7.3
|
||||
|
@ -1119,6 +1122,14 @@ packages:
|
|||
'@capacitor/core': 4.7.3
|
||||
dev: false
|
||||
|
||||
/@capacitor/camera@4.1.4(@capacitor/core@4.7.3):
|
||||
resolution: {integrity: sha512-7f4n7PlnstYsdGyxc0Kc4hIyS6csFLOjXvffm7pJsuy9pSo+kfdOPdYgGg360QwbUAmA+Yv+J1ZW1eFIwgvWrQ==}
|
||||
peerDependencies:
|
||||
'@capacitor/core': ^4.0.0
|
||||
dependencies:
|
||||
'@capacitor/core': 4.7.3
|
||||
dev: false
|
||||
|
||||
/@capacitor/cli@4.7.3:
|
||||
resolution: {integrity: sha512-/9Vjl0A91UjRA0b8a5YCqHfHcM50vQ3Fh0typ3ScwYZhg3shkFtB03e8liAD/u0rhr/MerN8VGgN75QNEXN0Lg==}
|
||||
engines: {node: '>=12.4.0'}
|
||||
|
|
Loading…
Reference in New Issue