feat(app): add onboarding and harden alarms
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class NotaVersionPluri {
|
||||
const NotaVersionPluri({
|
||||
required this.version,
|
||||
required this.resumen,
|
||||
required this.markdown,
|
||||
});
|
||||
|
||||
final String version;
|
||||
final String resumen;
|
||||
final String markdown;
|
||||
}
|
||||
|
||||
class ContenidoAyudaPluri {
|
||||
const ContenidoAyudaPluri({
|
||||
required this.onboarding,
|
||||
required this.notas,
|
||||
required this.versionActual,
|
||||
});
|
||||
|
||||
final String onboarding;
|
||||
final List<NotaVersionPluri> notas;
|
||||
final String versionActual;
|
||||
}
|
||||
|
||||
class ServicioContenidoApp {
|
||||
static const _keyOnboardingVisto = 'pluri_onboarding_visto_v1';
|
||||
static const _keyVersionVista = 'pluri_ultima_version_novedades_v1';
|
||||
static const _versiones = ['0.1.47'];
|
||||
|
||||
Future<bool> debeMostrarInicio() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final info = await PackageInfo.fromPlatform();
|
||||
final versionActual = info.version;
|
||||
return !(prefs.getBool(_keyOnboardingVisto) ?? false) ||
|
||||
prefs.getString(_keyVersionVista) != versionActual;
|
||||
}
|
||||
|
||||
Future<void> marcarVisto() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final info = await PackageInfo.fromPlatform();
|
||||
await prefs.setBool(_keyOnboardingVisto, true);
|
||||
await prefs.setString(_keyVersionVista, info.version);
|
||||
}
|
||||
|
||||
Future<ContenidoAyudaPluri> cargar(
|
||||
String codigoIdioma, {
|
||||
bool soloPendientes = false,
|
||||
}) async {
|
||||
final info = await PackageInfo.fromPlatform();
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final ultimaVista = prefs.getString(_keyVersionVista);
|
||||
final idioma = _idiomaSoportado(codigoIdioma);
|
||||
final mostrarOnboarding =
|
||||
!soloPendientes || !(prefs.getBool(_keyOnboardingVisto) ?? false);
|
||||
final onboarding =
|
||||
mostrarOnboarding
|
||||
? await _cargarMarkdown(
|
||||
'assets/content/onboarding/$idioma.md',
|
||||
fallback: 'assets/content/onboarding/en.md',
|
||||
)
|
||||
: '';
|
||||
final notas = <NotaVersionPluri>[];
|
||||
for (final version in _versiones) {
|
||||
if (soloPendientes &&
|
||||
ultimaVista != null &&
|
||||
_compararVersiones(version, ultimaVista.split('+').first) <= 0) {
|
||||
continue;
|
||||
}
|
||||
final markdown = await _cargarMarkdown(
|
||||
'assets/content/updates/$idioma/$version.md',
|
||||
fallback: 'assets/content/updates/en/$version.md',
|
||||
);
|
||||
if (markdown.trim().isEmpty) continue;
|
||||
notas.add(
|
||||
NotaVersionPluri(
|
||||
version: version,
|
||||
resumen: _resumen(markdown),
|
||||
markdown: markdown,
|
||||
),
|
||||
);
|
||||
}
|
||||
return ContenidoAyudaPluri(
|
||||
onboarding: onboarding,
|
||||
notas: notas,
|
||||
versionActual: _versionCompleta(info),
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> _cargarMarkdown(
|
||||
String path, {
|
||||
required String fallback,
|
||||
}) async {
|
||||
try {
|
||||
return await rootBundle.loadString(path);
|
||||
} catch (_) {
|
||||
return rootBundle.loadString(fallback);
|
||||
}
|
||||
}
|
||||
|
||||
String _idiomaSoportado(String codigo) {
|
||||
const soportados = {
|
||||
'ar',
|
||||
'bn',
|
||||
'de',
|
||||
'en',
|
||||
'es',
|
||||
'fr',
|
||||
'hi',
|
||||
'id',
|
||||
'it',
|
||||
'ja',
|
||||
'pt',
|
||||
'ru',
|
||||
'zh',
|
||||
};
|
||||
return soportados.contains(codigo) ? codigo : 'en';
|
||||
}
|
||||
|
||||
String _resumen(String markdown) {
|
||||
for (final line in markdown.split('\n')) {
|
||||
final limpia = line.trim();
|
||||
if (limpia.toLowerCase().startsWith('resumen:')) {
|
||||
return limpia.substring(limpia.indexOf(':') + 1).trim();
|
||||
}
|
||||
if (limpia.toLowerCase().startsWith('summary:')) {
|
||||
return limpia.substring(limpia.indexOf(':') + 1).trim();
|
||||
}
|
||||
if (limpia.contains(':')) {
|
||||
final etiqueta = limpia.substring(0, limpia.indexOf(':')).toLowerCase();
|
||||
const etiquetasResumen = {
|
||||
'résumé',
|
||||
'zusammenfassung',
|
||||
'riepilogo',
|
||||
'resumo',
|
||||
'ملخص',
|
||||
'সারাংশ',
|
||||
'सारांश',
|
||||
'ringkasan',
|
||||
'概要',
|
||||
'摘要',
|
||||
'резюме',
|
||||
};
|
||||
if (etiquetasResumen.contains(etiqueta)) {
|
||||
return limpia.substring(limpia.indexOf(':') + 1).trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
String _versionCompleta(PackageInfo info) =>
|
||||
'${info.version}+${info.buildNumber}';
|
||||
|
||||
int _compararVersiones(String a, String b) {
|
||||
final pa = a.split('.').map((e) => int.tryParse(e) ?? 0).toList();
|
||||
final pb = b.split('.').map((e) => int.tryParse(e) ?? 0).toList();
|
||||
for (var i = 0; i < 3; i++) {
|
||||
final va = i < pa.length ? pa[i] : 0;
|
||||
final vb = i < pb.length ? pb[i] : 0;
|
||||
if (va != vb) return va.compareTo(vb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user