From 69d6d3d359faee1c9d0236a948a8e572360e8c24 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 6 Feb 2024 11:16:29 +0000 Subject: [PATCH 1/6] Refetch federation balances on updates --- src/routes/settings/ManageFederations.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/routes/settings/ManageFederations.tsx b/src/routes/settings/ManageFederations.tsx index e3860dea..9a2a5b67 100644 --- a/src/routes/settings/ManageFederations.tsx +++ b/src/routes/settings/ManageFederations.tsx @@ -5,6 +5,7 @@ import { setValue, SubmitHandler } from "@modular-forms/solid"; +import { FederationBalance } from "@mutinywallet/mutiny-wasm"; import { useSearchParams } from "@solidjs/router"; import { createResource, @@ -51,7 +52,15 @@ export type MutinyFederationIdentity = { federation_expiry_timestamp: number; }; -function AddFederationForm() { +type RefetchType = ( + info?: unknown +) => + | FederationBalance[] + | Promise + | null + | undefined; + +function AddFederationForm(props: { refetch?: RefetchType }) { const i18n = useI18n(); const [state, actions] = useMegaStore(); const [error, setError] = createSignal(); @@ -88,6 +97,9 @@ function AddFederationForm() { i18n.t("settings.manage_federations.federation_added_success") ); await actions.refreshFederations(); + if (props.refetch) { + await props.refetch(); + } reset(feedbackForm); } catch (e) { console.error("Error submitting federation:", e); @@ -225,7 +237,7 @@ export function ManageFederations() { const i18n = useI18n(); const [state, _actions] = useMegaStore(); - const [balances] = createResource(async () => { + const [balances, { refetch }] = createResource(async () => { try { const balances = await state.mutiny_wallet?.get_federation_balances(); @@ -253,7 +265,7 @@ export function ManageFederations() { {i18n.t("settings.manage_federations.learn_more")} - + From 8e04901e18bfea3fb16435ef516aa1757206a826 Mon Sep 17 00:00:00 2001 From: Paul Miller Date: Sat, 10 Feb 2024 19:15:57 +0000 Subject: [PATCH 2/6] show selected currency on currency chooser --- src/components/ChooseCurrency.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/components/ChooseCurrency.tsx b/src/components/ChooseCurrency.tsx index 3134282e..024e31ad 100644 --- a/src/components/ChooseCurrency.tsx +++ b/src/components/ChooseCurrency.tsx @@ -23,7 +23,7 @@ const COMBINED_OPTIONS: Currency[] = [USD_OPTION, BTC_OPTION, ...FIAT_OPTIONS]; export function ChooseCurrency() { const i18n = useI18n(); const [error, setError] = createSignal(); - const [_state, actions] = useMegaStore(); + const [state, actions] = useMegaStore(); const [loading, setLoading] = createSignal(false); const navigate = useNavigate(); @@ -37,7 +37,7 @@ export function ChooseCurrency() { const [_chooseCurrencyForm, { Form, Field }] = createForm({ initialValues: { - fiatCurrency: "" + fiatCurrency: state.fiat.value }, validate: (values) => { const errors: Record = {}; @@ -82,7 +82,12 @@ export function ChooseCurrency() { > {({ value, label }) => ( - + )} From 075c066fad039fe913f1bf52f55ab323c48fae4e Mon Sep 17 00:00:00 2001 From: Leonardo Lima Date: Mon, 22 Jan 2024 12:45:20 +0000 Subject: [PATCH 3/6] feat: add language selection on settings page --- src/components/ChooseLanguage.tsx | 95 +++++++++++++++++++++++++++++++ src/components/index.ts | 1 + src/i18n/config.ts | 6 +- src/i18n/en/translations.ts | 10 ++++ src/router.tsx | 2 + src/routes/settings/Language.tsx | 35 ++++++++++++ src/routes/settings/Root.tsx | 5 ++ src/routes/settings/index.ts | 1 + src/state/megaStore.tsx | 7 +++ src/utils/index.ts | 1 + src/utils/languages.ts | 20 +++++++ 11 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 src/components/ChooseLanguage.tsx create mode 100644 src/routes/settings/Language.tsx create mode 100644 src/utils/languages.ts diff --git a/src/components/ChooseLanguage.tsx b/src/components/ChooseLanguage.tsx new file mode 100644 index 00000000..360529da --- /dev/null +++ b/src/components/ChooseLanguage.tsx @@ -0,0 +1,95 @@ +import { createForm } from "@modular-forms/solid"; +import { useNavigate } from "@solidjs/router"; +import { createSignal, For, Show } from "solid-js"; + +import { Button, ExternalLink, InfoBox, NiceP, VStack } from "~/components"; +import { useI18n } from "~/i18n/context"; +import { useMegaStore } from "~/state/megaStore"; +import { eify, EN_OPTION, Language, LANGUAGE_OPTIONS, timeout } from "~/utils"; + +type ChooseLanguageForm = { + selectedLanguage: string; +}; + +const COMBINED_OPTIONS: Language[] = [EN_OPTION, ...LANGUAGE_OPTIONS]; + +export function ChooseLanguage() { + const i18n = useI18n(); + const [error, setError] = createSignal(); + const [state, actions] = useMegaStore(); + const [loading, setLoading] = createSignal(false); + const navigate = useNavigate(); + + const [_chooseLanguageForm, { Form, Field }] = + createForm({ + initialValues: { + selectedLanguage: state.lang ?? "" + }, + validate: (values) => { + const errors: Record = {}; + if (values.selectedLanguage === undefined) { + errors.selectedLanguage = i18n.t( + "settings.language.error_unsupported_language" + ); + } + return errors; + } + }); + + const handleFormSubmit = async (f: ChooseLanguageForm) => { + setLoading(true); + try { + actions.saveLanguage(f.selectedLanguage); + + await i18n.changeLanguage(f.selectedLanguage); + + await timeout(1000); + navigate("/"); + } catch (e) { + console.error(e); + setError(eify(e)); + setLoading(false); + } + }; + + return ( + +
+ {i18n.t("settings.language.caption")} + + {i18n.t("settings.language.request_language_support_link")} + +
+ + + {(field, props) => ( + + )} + + + {error()?.message} + +
+ + + + + ); +} diff --git a/src/components/index.ts b/src/components/index.ts index 3b6a779f..287c4e7d 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -9,6 +9,7 @@ export * from "./AmountEditable"; export * from "./BalanceBox"; export * from "./BetaWarningModal"; export * from "./ChooseCurrency"; +export * from "./ChooseLanguage"; export * from "./ContactEditor"; export * from "./ContactForm"; export * from "./ContactViewer"; diff --git a/src/i18n/config.ts b/src/i18n/config.ts index 41859469..1897837f 100644 --- a/src/i18n/config.ts +++ b/src/i18n/config.ts @@ -32,8 +32,10 @@ const i18n = use(LanguageDetector).init( fallbackNS: false, debug: true, detection: { - order: ["querystring", "navigator", "htmlTag"], - lookupQuerystring: "lang" + order: ["localStorage", "querystring", "navigator", "htmlTag"], + lookupQuerystring: "lang", + lookupLocalStorage: "i18nextLng", + caches: ["localStorage"] }, resources: resources // FIXME: this doesn't work when deployed diff --git a/src/i18n/en/translations.ts b/src/i18n/en/translations.ts index 44463015..4349a78b 100644 --- a/src/i18n/en/translations.ts +++ b/src/i18n/en/translations.ts @@ -432,6 +432,16 @@ export default { "Request support for more currencies", error_unsupported_currency: "Please Select a supported currency." }, + language: { + title: "Language", + caption: "Choose your preferred language", + select_language: "Select Language", + select_language_label: "Language", + select_language_caption: + "Choosing a new currency will change the wallet language, ignoring current browser language", + request_language_support_link: "Request support for more languages", + error_unsupported_language: "Please Select a supported language." + }, lnurl_auth: { title: "LNURL Auth", auth: "Auth", diff --git a/src/router.tsx b/src/router.tsx index 557331ee..bb8407c6 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -27,6 +27,7 @@ import { EmergencyKit, Encrypt, Gift, + Language, ManageFederations, Plus, Restore, @@ -111,6 +112,7 @@ export function Router() { + diff --git a/src/routes/settings/Language.tsx b/src/routes/settings/Language.tsx new file mode 100644 index 00000000..136ff736 --- /dev/null +++ b/src/routes/settings/Language.tsx @@ -0,0 +1,35 @@ +import { + BackLink, + Card, + ChooseLanguage, + DefaultMain, + LargeHeader, + MutinyWalletGuard, + NavBar, + SafeArea +} from "~/components"; +import { useI18n } from "~/i18n/context"; + +export function Language() { + const i18n = useI18n(); + return ( + + + + + + {i18n.t("settings.language.title")} + + + + +
+ + + + + ); +} diff --git a/src/routes/settings/Root.tsx b/src/routes/settings/Root.tsx index ee141774..d7e5e74c 100644 --- a/src/routes/settings/Root.tsx +++ b/src/routes/settings/Root.tsx @@ -118,6 +118,11 @@ export function Settings() { text: i18n.t("settings.currency.title"), caption: i18n.t("settings.currency.caption") }, + { + href: "/settings/language", + text: i18n.t("settings.language.title"), + caption: i18n.t("settings.language.caption") + }, { href: "/settings/servers", text: i18n.t("settings.servers.title"), diff --git a/src/routes/settings/index.ts b/src/routes/settings/index.ts index 0cf20685..3de23b8b 100644 --- a/src/routes/settings/index.ts +++ b/src/routes/settings/index.ts @@ -4,6 +4,7 @@ export * from "./Backup"; export * from "./Channels"; export * from "./Connections"; export * from "./Currency"; +export * from "./Language"; export * from "./EmergencyKit"; export * from "./Encrypt"; export * from "./Gift"; diff --git a/src/state/megaStore.tsx b/src/state/megaStore.tsx index 68c90417..e4e8b9e7 100644 --- a/src/state/megaStore.tsx +++ b/src/state/megaStore.tsx @@ -54,6 +54,7 @@ type MegaStore = [ price_sync_backoff_multiple?: number; price: number; fiat: Currency; + lang?: string; has_backed_up: boolean; wallet_loading: boolean; setup_error?: Error; @@ -83,6 +84,7 @@ type MegaStore = [ checkForSubscription(justPaid?: boolean): Promise; fetchPrice(fiat: Currency): Promise; saveFiat(fiat: Currency): void; + saveLanguage(lang: string): void; saveNpub(npub: string): void; setPreferredInvoiceType( type: "unified" | "lightning" | "onchain" @@ -132,6 +134,7 @@ export const Provider: ParentComponent = (props) => { load_stage: "fresh" as LoadStage, settings: undefined as MutinyWalletSettingStrings | undefined, safe_mode: searchParams.safe_mode === "true", + lang: localStorage.getItem("i18nexLng") || undefined, npub: localStorage.getItem("npub") || undefined, preferredInvoiceType: "unified" as "unified" | "lightning" | "onchain", betaWarned: localStorage.getItem("betaWarned") === "true", @@ -332,6 +335,10 @@ export const Provider: ParentComponent = (props) => { fiat: fiat }); }, + saveLanguage(lang: string) { + localStorage.setItem("i18nextLng", lang); + setState({ lang }); + }, saveNpub(npub: string) { localStorage.setItem("npub", npub); setState({ npub }); diff --git a/src/utils/index.ts b/src/utils/index.ts index 754f0922..cf118bb3 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -16,6 +16,7 @@ export * from "./vibrate"; export * from "./openLinkProgrammatically"; export * from "./nostr"; export * from "./currencies"; +export * from "./languages"; export * from "./bech32"; export * from "./keypad"; export * from "./debounce"; diff --git a/src/utils/languages.ts b/src/utils/languages.ts new file mode 100644 index 00000000..1a7c6978 --- /dev/null +++ b/src/utils/languages.ts @@ -0,0 +1,20 @@ +export interface Language { + value: string; + shortName: string; +} + +export const EN_OPTION: Language = { + value: "English", + shortName: "en" +}; + +export const LANGUAGE_OPTIONS: Language[] = [ + { + value: "Português", + shortName: "pt" + }, + { + value: "Korean", + shortName: "ko" + } +]; From 11bf4727baf3be1cefbfc4d8efb827c7ac82c318 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 13 Feb 2024 18:40:06 +0000 Subject: [PATCH 4/6] Bump to 0.5.9 --- android/app/build.gradle | 4 ++-- ios/App/App.xcodeproj/project.pbxproj | 4 ++-- package.json | 4 ++-- pnpm-lock.yaml | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 8a8948f1..718777d3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.mutinywallet.mutinywallet" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 49 - versionName "0.5.8" + versionCode 50 + versionName "0.5.9" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 0337b0fb..d9398078 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -360,7 +360,7 @@ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 1.5.8; + MARKETING_VERSION = 1.5.9; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = com.mutinywallet.mutiny; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -387,7 +387,7 @@ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 1.5.8; + MARKETING_VERSION = 1.5.9; PRODUCT_BUNDLE_IDENTIFIER = com.mutinywallet.mutiny; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/package.json b/package.json index 52fbf3fe..3f9510c8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mutiny-wallet", - "version": "0.5.8", + "version": "0.5.9", "license": "MIT", "packageManager": "pnpm@8.6.6", "scripts": { @@ -55,7 +55,7 @@ "@kobalte/core": "^0.9.8", "@kobalte/tailwindcss": "^0.5.0", "@modular-forms/solid": "^0.18.1", - "@mutinywallet/mutiny-wasm": "0.5.8", + "@mutinywallet/mutiny-wasm": "0.5.9", "@mutinywallet/waila-wasm": "^0.2.6", "@solid-primitives/upload": "^0.0.111", "@solidjs/meta": "^0.29.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1093e522..14598a6b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,8 +54,8 @@ importers: specifier: ^0.18.1 version: 0.18.1(solid-js@1.8.5) '@mutinywallet/mutiny-wasm': - specifier: 0.5.8 - version: 0.5.8 + specifier: 0.5.9 + version: 0.5.9 '@mutinywallet/waila-wasm': specifier: ^0.2.6 version: 0.2.6 @@ -2570,8 +2570,8 @@ packages: solid-js: 1.8.5 dev: false - /@mutinywallet/mutiny-wasm@0.5.8: - resolution: {integrity: sha512-Bwx3sMXuMiE876Kk1FI9uZoJMPkHc5RGFmUHsFeSMMGDxC2YLO5N5ilaIIig89ZbAYcBi7Y1N4Nq/2nZFcM+9A==} + /@mutinywallet/mutiny-wasm@0.5.9: + resolution: {integrity: sha512-skSSpMprn/iA6Zsk092S1UVCkgjaCfXZXdvzVahFLDDS/89GtxyHtSsY64Oy3KFCULB6X+UfFp9nRFHtWA7sIw==} dev: false /@mutinywallet/waila-wasm@0.2.6: From c1c346522f7400c86944168627d2d53cf8672f3d Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 13 Feb 2024 18:40:21 +0000 Subject: [PATCH 5/6] Remove no longer needed password handling for reading logs --- src/components/Logs.tsx | 59 +++-------------------------------------- 1 file changed, 3 insertions(+), 56 deletions(-) diff --git a/src/components/Logs.tsx b/src/components/Logs.tsx index ec31ab96..bd53cee9 100644 --- a/src/components/Logs.tsx +++ b/src/components/Logs.tsx @@ -1,15 +1,7 @@ import { MutinyWallet } from "@mutinywallet/mutiny-wasm"; import { createSignal, Show } from "solid-js"; -import { - Button, - InfoBox, - InnerCard, - NiceP, - SimpleDialog, - TextField, - VStack -} from "~/components"; +import { Button, InfoBox, InnerCard, NiceP, VStack } from "~/components"; import { useI18n } from "~/i18n/context"; import { downloadTextFile, eify } from "~/utils"; @@ -18,13 +10,11 @@ export function Logs() { // Create state for errors, password and dialog visibility const [error, setError] = createSignal(); - const [exportDecrypt, setExportDecrypt] = createSignal(false); - const [password, setPassword] = createSignal(); async function handleSave() { try { setError(undefined); - const logs = await MutinyWallet.get_logs(password()); // Use password if required + const logs = await MutinyWallet.get_logs(); await downloadTextFile( logs.join("") || "", "mutiny-logs.txt", @@ -32,26 +22,10 @@ export function Logs() { ); } catch (e) { console.error(e); - const err = eify(e); - if (err.message === "Incorrect password entered.") { - setExportDecrypt(true); - } else { - setError(err); - } + setError(eify(e)); } } - function savePassword(e: Event) { - e.preventDefault(); - handleSave(); - setPassword(undefined); // clear password after use - setExportDecrypt(false); // close the dialog - } - - function noop() { - // noop - } - return ( @@ -65,33 +39,6 @@ export function Logs() { {error()?.message} - -
-
- setPassword(e.currentTarget.value)} - error={""} - onBlur={noop} - onChange={noop} - /> - - {error()?.message} - - -
-
-
); } From 1b3cb09c655c26f2509e00f874de3a56d83ef35b Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 13 Feb 2024 15:58:43 +0000 Subject: [PATCH 6/6] Fix Switch/Show order --- src/components/ActivityDetailsModal.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ActivityDetailsModal.tsx b/src/components/ActivityDetailsModal.tsx index f9fffc10..3c29bdd3 100644 --- a/src/components/ActivityDetailsModal.tsx +++ b/src/components/ActivityDetailsModal.tsx @@ -571,8 +571,8 @@ export function ActivityDetailsModal(props: {
- - + + - - + +