Skip to content

Commit

Permalink
Add: JS側を実装
Browse files Browse the repository at this point in the history
  • Loading branch information
sevenc-nanashi committed Nov 15, 2023
1 parent 0e872e1 commit be8b525
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 14 deletions.
1 change: 1 addition & 0 deletions android/app/capacitor.build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ android {

apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':capacitor-preferences')
implementation project(':capacitor-splash-screen')

}
Expand Down
3 changes: 3 additions & 0 deletions android/capacitor.settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@
include ':capacitor-android'
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')

include ':capacitor-preferences'
project(':capacitor-preferences').projectDir = new File('../node_modules/@capacitor/preferences/android')

include ':capacitor-splash-screen'
project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android')
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"dependencies": {
"@capacitor/android": "5.5.1",
"@capacitor/core": "5.5.1",
"@capacitor/preferences": "5.0.6",
"@capacitor/splash-screen": "5.0.2",
"@gtm-support/vue-gtm": "1.2.3",
"@quasar/extras": "1.10.10",
Expand Down
167 changes: 153 additions & 14 deletions src/mobile/engine/dict.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,162 @@
import { Preferences } from "@capacitor/preferences";
import { v4 as uuidv4 } from "uuid";
import { ApiProvider } from ".";
import { UserDictWord } from "@/openapi";

type InternalUserDict = Record<string, InternalDictWord>;

const preferenceKey = "userDict";
const getUserDictWords = async () => {
const userDictJson = await Preferences.get({ key: preferenceKey });
const dict: InternalUserDict = userDictJson.value
? JSON.parse(userDictJson.value)
: {};
return dict;
};
const setUserDictWords = async (dict: InternalUserDict) => {
await Preferences.set({ key: preferenceKey, value: JSON.stringify(dict) });
};

type InternalWordType =
| "PROPER_NOUN"
| "COMMON_NOUN"
| "VERB"
| "ADJECTIVE"
| "SUFFIX";
type InternalDictWord = {
priority: number;
accentType: number;
surface: string;
pronunciation: string;
wordType: InternalWordType;
};
const internalWordTypeMap: Record<
InternalWordType,
{
partOfSpeech: string;
partOfSpeechDetail1: string;
partOfSpeechDetail2: string;
partOfSpeechDetail3: string;
}
> = {
PROPER_NOUN: {
partOfSpeech: "名詞",
partOfSpeechDetail1: "固有名詞",
partOfSpeechDetail2: "一般",
partOfSpeechDetail3: "*",
},
COMMON_NOUN: {
partOfSpeech: "名詞",
partOfSpeechDetail1: "一般",
partOfSpeechDetail2: "*",
partOfSpeechDetail3: "*",
},
VERB: {
partOfSpeech: "動詞",
partOfSpeechDetail1: "自立",
partOfSpeechDetail2: "*",
partOfSpeechDetail3: "*",
},
ADJECTIVE: {
partOfSpeech: "形容詞",
partOfSpeechDetail1: "自立",
partOfSpeechDetail2: "*",
partOfSpeechDetail3: "*",
},
SUFFIX: {
partOfSpeech: "名詞",
partOfSpeechDetail1: "接尾",
partOfSpeechDetail2: "一般",
partOfSpeechDetail3: "*",
},
};
const apiWordToInternalWord = (word: UserDictWord): InternalDictWord => {
const wordType = Object.entries(internalWordTypeMap).find(
([, value]) =>
value.partOfSpeech === word.partOfSpeech &&
value.partOfSpeechDetail1 === word.partOfSpeechDetail1 &&
value.partOfSpeechDetail2 === word.partOfSpeechDetail2 &&
value.partOfSpeechDetail3 === word.partOfSpeechDetail3
)?.[0] as InternalWordType | undefined;
if (!wordType) {
throw new Error("wordType not found");
}
return {
surface: word.surface,
pronunciation: word.pronunciation,
accentType: word.accentType,
priority: word.priority,
wordType,
};
};

const dictProvider: ApiProvider = () => {
// TODO:
// ユーザー辞書機能がCoreに実装されるまで、必要最低限のモックにしておく。
// cf: https://github.com/VOICEVOX/voicevox_core/issues/265
return {
async getUserDictWordsUserDictGet() {
return {};
const dict = await getUserDictWords();

return Object.fromEntries(
Object.entries(dict).map<[string, UserDictWord]>(([uuid, word]) => [
uuid,
{
surface: word.surface,
pronunciation: word.pronunciation,
accentType: word.accentType,
priority: word.priority,
...internalWordTypeMap[word.wordType],
// 本来はもっとプロパティがあるが、
// https://github.com/VOICEVOX/voicevox_core/blob/main/crates/voicevox_core/src/user_dict/part_of_speech_data.rs のような
// 対応表をもってくるのは面倒なので、とりあえずこれだけ用意しておく。
} as UserDictWord,
])
);
},
async addUserDictWordUserDictWordPost(word) {
if (!word.wordType) {
throw new Error("wordType is required");
}
const uuid = uuidv4();
const dict = await getUserDictWords();
dict[uuid] = {
surface: word.surface,
pronunciation: word.pronunciation,
accentType: word.accentType,
priority: word.priority ?? 5,
wordType: word.wordType,
};
await setUserDictWords(dict);
return uuid;
},
async deleteUserDictWordUserDictWordWordUuidDelete(req) {
const dict = await getUserDictWords();
delete dict[req.wordUuid];
await setUserDictWords(dict);
return;
},
async rewriteUserDictWordUserDictWordWordUuidPut(req) {
const dict = await getUserDictWords();
const word = dict[req.wordUuid];
if (!word) {
throw new Error("wordUuid not found");
}
dict[req.wordUuid] = {
surface: req.surface,
pronunciation: req.pronunciation,
accentType: req.accentType,
priority: req.priority || word.priority,
wordType: req.wordType || word.wordType,
};
await setUserDictWords(dict);
return;
},
// async addUserDictWordUserDictWordPost() {
// return;
// },
// async deleteUserDictWordUserDictWordWordUuidDelete() {
// return;
// },
// async rewriteUserDictWordUserDictWordWordUuidPut() {
// return;
// },
async importUserDictWordsImportUserDictPost() {
async importUserDictWordsImportUserDictPost(req) {
const dict = await getUserDictWords();
for (const [uuid, word] of Object.entries(req.requestBody)) {
if (dict[uuid] && !req.override) {
continue;
}
dict[uuid] = apiWordToInternalWord(word);
}
return;
},
};
Expand Down
2 changes: 2 additions & 0 deletions src/mobile/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export type VoicevoxCorePlugin = {
speakerId: number;
enableInterrogativeUpspeak: boolean;
}) => Promise<{ value: string }>;

userDictLoad: (obj: { dictJson: string }) => Promise<void>;
};

const loadPlugin = () => {
Expand Down

0 comments on commit be8b525

Please sign in to comment.