Skip to content

Commit

Permalink
Added "Developer mode" to enable special developer features
Browse files Browse the repository at this point in the history
Added first developer mode feature: extra translation file loading
  • Loading branch information
nicorac committed Dec 6, 2024
1 parent 5549317 commit 1e1d212
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 26 deletions.
9 changes: 7 additions & 2 deletions src/app/pages/about/about.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@
</div>

<div class="item">
<ion-label class="ion-text-wrap">
<ion-label class="ion-text-wrap" (click)="versionClick()">
<h2>{{ 'ABOUT_VERSION' | translatePipe }}</h2>
<p>{{ version.version }}</p>
<p>
{{ version.version }}
@if (settings.developerMode) {
<i>({{ 'ABOUT_DEV_MODE_ENABLED' | translatePipe }})</i>
}
</p>
</ion-label>
</div>

Expand Down
46 changes: 46 additions & 0 deletions src/app/pages/about/about.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { AppRoutesEnum } from 'src/app/app-routing.module';
import { HeaderComponent } from 'src/app/components/header/header.component';
import { IonicBundleModule } from 'src/app/IonicBundle.module';
import { TranslatePipe } from 'src/app/pipes/translate.pipe';
import { I18nService } from 'src/app/services/i18n.service';
import { MessageBoxService } from 'src/app/services/message-box.service';
import { SettingsService } from 'src/app/services/settings.service';
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { Platform } from '@ionic/angular';
Expand Down Expand Up @@ -31,8 +34,11 @@ export class AboutPage {
};

constructor(
private i18n: I18nService,
private mbs: MessageBoxService,
protected platform: Platform,
protected router: Router,
protected settings: SettingsService,
) {
// subscribe to hardware back button events
this.backSub = this.platform.backButton.subscribeWithPriority(10, () => this.router.navigateByUrl(AppRoutesEnum.Main));
Expand All @@ -42,4 +48,44 @@ export class AboutPage {
this.backSub?.unsubscribe();
}

/**
* Clicking 5 times in a row on version label will make the user a developer
*/
protected async versionClick() {

const MIN_CLICK_COUNT = 5;

if (this.versionClickTimeout) {
clearTimeout(this.versionClickTimeout);
this.versionClickTimeout = undefined;
}

this.versionClickCount++;
if (this.versionClickCount === MIN_CLICK_COUNT) {
this.settings.developerMode = !this.settings.developerMode;
await this.settings.save();
// notify the user about the change
await this.mbs.showConfirm({
header: this.i18n.get('SETTINGS_DEV_SECTION'),
message: this.i18n.get(this.settings.developerMode ? 'ABOUT_DEV_MODE_ENABLED' : 'ABOUT_DEV_MODE_DISABLED'),
showCancelButton: false,
backdropDismiss: false,
onConfirm: () => {
// reload page to force translations reload (if needed)
location.reload();
},
});
this.versionClickCount = 0;
}
else {
this.versionClickTimeout = setTimeout(() => {
this.versionClickTimeout = undefined;
this.versionClickCount = 0;
}, 1000);
}

}
protected versionClickCount = 0;
private versionClickTimeout: ReturnType<typeof setTimeout> | undefined;

}
25 changes: 14 additions & 11 deletions src/app/pages/settings/settings.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,26 @@ <h4>{{ 'SETTINGS_GENERAL_SECTION' | translatePipe }}</h4>

<ion-item>
<div class="wrapper">

<div class="label">
{{ 'SETTINGS_LANGUAGE' | translatePipe }}
<div class="help">{{ 'SETTINGS_LANGUAGE_TEXT' | translatePipe }}<br/>
(<a href="{{ version.addLanguageUri }}">{{ 'SETTINGS_LANGUAGE_ADD' | translatePipe }}</a>)
</div>
</div>
<ion-select
[(ngModel)]="settings.culture"
(ngModelChange)="clearPipesCache()"
>
<ion-select-option [value]="''">
{{ 'SETTINGS_SYSTEM_DEFAULT' | translatePipe }} ({{ settings.defaultCulture }})
</ion-select-option>
@for (c of i18n.getDefinedCultures(); track c) {
<ion-select-option [value]="c.id">{{ c.name }} ({{ c.id }})</ion-select-option>
}
</ion-select>
<div>
<ion-select
[(ngModel)]="settings.culture"
(ngModelChange)="clearPipesCache()"
>
<ion-select-option [value]="''">
{{ 'SETTINGS_SYSTEM_DEFAULT' | translatePipe }} ({{ settings.defaultCulture }})
</ion-select-option>
@for (c of i18n.getDefinedCultures(); track c) {
<ion-select-option [value]="c.id">{{ c.name }} ({{ c.id }})</ion-select-option>
}
</ion-select>
</div>
</div>
</ion-item>

Expand Down
39 changes: 36 additions & 3 deletions src/app/services/i18n.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { AndroidSAF, Encoding } from 'src/plugins/androidsaf';
import { Injectable } from '@angular/core';
import { SettingsService } from './settings.service';

export type I18nKey = Uppercase<string>;
export type TranslationArgs = number | { [key:string]:(string|number) };
Expand Down Expand Up @@ -29,10 +31,17 @@ export class I18nService {

private _cultureDefs: Culture[] = [];
private _currentCulture = FALLBACK_CULTURE;

// CAN'T use DI because of circular dependency, set in initialize() function
private settings!: SettingsService;

constructor() { }
constructor(
) { }

async initialize() {
async initialize(settings: SettingsService) {

// store settings instance
this.settings = settings;

// cleanup local storage
let keys = [];
Expand Down Expand Up @@ -93,6 +102,24 @@ export class I18nService {
...await this.getJsonContent(`${LANG_BASE_URL}/${culture}.json`),
}

// try to load x file
if (this.settings.developerMode) {
// get URI of developer lang file
const { uri: devLangFileUri } = await AndroidSAF.getFileUri({
directoryUri: this.settings.recordingsDirectoryUri,
name: `i18n.json`,
});
if (devLangFileUri) {
const { content: devLangFileContent } = await AndroidSAF.readFile({ fileUri: devLangFileUri, encoding: Encoding.UTF8 });
if (devLangFileContent) {
content = {
...content,
...await JSON.parse(devLangFileContent),
}
}
}
}

// store content
Object.entries(content).forEach(([key, value]) => {
localStorage.setItem(TRANSLATION_KEY_PREFIX + key, value);
Expand All @@ -101,7 +128,13 @@ export class I18nService {
}

private async getJsonContent<T>(filename: string): Promise<T> {
return await (await fetch(filename)).json();
const content = await fetch(filename);
if (content.status !== 404) {
return await content.json();
}
else {
return <T>{};
}
}

/**
Expand Down
25 changes: 16 additions & 9 deletions src/app/services/message-box.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export class MessageBoxService {
buttons?: (AlertButton | string)[],
inputs?: AlertInput[],
cssClass?: string,
backdropDismiss?: boolean,
}) {

// prepend custom class (if not already there)
Expand Down Expand Up @@ -75,19 +76,23 @@ export class MessageBoxService {
// merge defaults
options = { ...new MessageBoxOptionsConfirm(), ...options };

const buttons = [];
if (options.showCancelButton) {
buttons.push({ text: options.cancelText ?? this.i18n.get('LBL_CANCEL'), handler: () => options.onCancel?.() });
}
buttons.push({
text: options.confirmText ?? this.i18n.get('LBL_OK'),
handler: () => {
options.onConfirm?.();
},
});

const mb = await this.getAlert({
header: options.header,
message: this.formatMessage(options.message),
buttons: [
{ text: options.cancelText ?? this.i18n.get('LBL_CANCEL'), handler: () => options.onCancel?.() },
{
text: options.confirmText ?? this.i18n.get('LBL_OK'),
handler: () => {
options.onConfirm?.();
},
}
],
buttons,
cssClass: 'msgbox-confirm',
backdropDismiss: options.backdropDismiss,
});
await mb.present();

Expand Down Expand Up @@ -187,6 +192,7 @@ export class mbOptionsBase {
header?: string;
message?: MessageType = '';
confirmText?: string = 'Ok';
backdropDismiss? = true;
onConfirm?: () => void;
}

Expand All @@ -203,6 +209,7 @@ export class MessageBoxOptions {
* Options for an error messagebox
*/
export class MessageBoxOptionsConfirm extends mbOptionsBase {
showCancelButton? = true;
cancelText?: string;
onCancel?: () => void;
}
Expand Down
6 changes: 6 additions & 0 deletions src/app/services/settings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ export class SettingsService {
@JsonProperty()
public keepAwakeWhenPlaying = true;

/**
* Developer mode is enabled
*/
@JsonProperty()
public developerMode = false;

constructor(
private mbs: MessageBoxService,
) { }
Expand Down
3 changes: 3 additions & 0 deletions src/assets/i18n/en-US.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"ABOUT_COPYRIGHT": "Copyright",
"ABOUT_DESCRIPTION": "%appName% is a companion app for %bcrLink% (Basic Call Recorder), to ease management of its recordings database",
"ABOUT_DEV_MODE_DISABLED": "Developer mode disabled",
"ABOUT_DEV_MODE_ENABLED": "Developer mode enabled",
"ABOUT_DONATIONS": "Donations",
"ABOUT_DONATIONS_TEXT": "This app is free as in beer and as in speech, nothing to pay, no ads. If you appreciate my work and want to support it, feel free to use one the links below.",
"ABOUT_HOMEPAGE": "Homepage",
Expand Down Expand Up @@ -115,6 +117,7 @@
"SETTINGS_GENERAL_SECTION": "General",
"SETTINGS_LANGUAGE": "Language",
"SETTINGS_LANGUAGE_ADD": "add new language",
"SETTINGS_LANGUAGE_IMPORT_FILE": "Import translation file",
"SETTINGS_LANGUAGE_TEXT": "Application language",
"SETTINGS_MAKE_SELECTION": "Make a selection",
"SETTINGS_PLAYER_ENABLE_EARPIECE": "Enable earpiece",
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/it-IT.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"ABOUT_COPYRIGHT": "Copyright",
"ABOUT_DESCRIPTION": "%appName% è una app che permette di gestire con facilità le registrazioni di %bcrLink% (Basic Call Recorder) e di altri registratori di chiamata",
"ABOUT_DEV_MODE_DISABLED": "Modalità sviluppatore disattivata",
"ABOUT_DEV_MODE_ENABLED": "Modalità sviluppatore attivata",
"ABOUT_DONATIONS": "Donazioni",
"ABOUT_DONATIONS_TEXT": "Questa app è gratuita e libera. Se apprezzi il mio lavoro e vuoi supportarlo con una donazione, usa uno dei link qui sotto.",
"ABOUT_HOMEPAGE": "Homepage",
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function initializeApp(i18n: I18nService, settings: SettingsService, platform: P
await settings.initialize();

// initialize i18n & load culture
await i18n.initialize();
await i18n.initialize(settings);
await i18n.load(settings.culture ? settings.culture : settings.defaultCulture);

// intercept unmanaged errors
Expand Down

0 comments on commit 1e1d212

Please sign in to comment.