fix(number-fields): избегаем потери точности длинных чисел

- number-поля теперь рендерятся как text + inputMode=numeric,
  чтобы браузер не округлял значения через input type=number
- пробелы при вставке в number-поля удаляются
- бэкенд нормализует значения number-полей в строку перед сохранением
- добавлен хелпер normalizeFieldValueForStorage

Closes: искажение расчётного счёта и других длинных числовых полей
This commit is contained in:
2026-07-07 21:03:40 +03:00
commit 1f5ecb6da4
1089 changed files with 237546 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
let withMainApplication, withAndroidManifest;
try {
const cp = require('@expo/config-plugins');
withMainApplication = cp.withMainApplication;
withAndroidManifest = cp.withAndroidManifest;
} catch {
// @expo/config-plugins not available locally (no mobile/node_modules).
// EAS cloud servers install it; just pass through the config unchanged here.
module.exports = function withPushy(config) { return config; };
return;
}
function withPushyMainApplication(config) {
return withMainApplication(config, (config) => {
const contents = config.modResults.contents;
const filePath = config.modResults.path || '';
const isKotlin = filePath.endsWith('.kt');
const importStatement = isKotlin
? 'import me.pushy.sdk.Pushy'
: 'import me.pushy.sdk.Pushy;';
let updated = contents;
// --- Import injection -----------------------------------------------
if (!updated.includes('me.pushy.sdk.Pushy')) {
// Match 'import android.app.Application' with or without semicolon
const importRegex = /(import android\.app\.Application[;]?)/;
if (importRegex.test(updated)) {
updated = updated.replace(importRegex, `$1\n${importStatement}`);
} else {
console.warn('[withPushy] Could not find import anchor in MainApplication; Pushy import not injected.');
}
}
// --- Pushy.listen() injection ----------------------------------------
if (!updated.includes('Pushy.listen(this)')) {
// Match 'super.onCreate()' or 'super.onCreate();' with leading whitespace.
// Use [ \t]* (not \s*) to avoid consuming the newline after the call,
// which would merge the next statement onto the same line and break Kotlin syntax.
const onCreateRegex = /([ \t]*super\.onCreate\(\)[ \t]*;?)/;
if (onCreateRegex.test(updated)) {
const callStatement = isKotlin
? '\n Pushy.listen(this)'
: '\n Pushy.listen(this);';
// Replace only the first occurrence (the one inside onCreate)
updated = updated.replace(onCreateRegex, `$1${callStatement}`);
} else {
console.warn('[withPushy] Could not find super.onCreate() in MainApplication; Pushy.listen not injected.');
}
}
config.modResults.contents = updated;
return config;
});
}
function withPushyManifest(config) {
return withAndroidManifest(config, (config) => {
const manifest = config.modResults.manifest;
if (!manifest['uses-permission']) {
manifest['uses-permission'] = [];
}
const perms = manifest['uses-permission'];
const wakeLock = 'android.permission.WAKE_LOCK';
if (!perms.some((p) => p.$?.['android:name'] === wakeLock)) {
perms.push({ $: { 'android:name': wakeLock } });
}
return config;
});
}
module.exports = function withPushy(config) {
config = withPushyMainApplication(config);
config = withPushyManifest(config);
return config;
};