kasy-cli 1.9.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/kasy.js +30 -7
- package/lib/utils/i18n.js +69 -69
- package/package.json +1 -1
- package/templates/firebase/android/app/src/main/kotlin/com/aicrus/firebase/kit/MyWidget.kt +5 -4
- package/templates/firebase/ios/HomeWidgetExtension/MyWidget.swift +21 -9
- package/templates/firebase/ios/Runner/Runner.entitlements +3 -1
- package/templates/firebase/lib/core/home_widgets/home_widget_background_task.dart +13 -0
- package/templates/firebase/lib/core/home_widgets/home_widget_mywidget_service.dart +60 -44
- package/templates/firebase/lib/i18n/en.i18n.json +9 -0
- package/templates/firebase/lib/i18n/es.i18n.json +9 -0
- package/templates/firebase/lib/i18n/pt.i18n.json +9 -0
package/bin/kasy.js
CHANGED
|
@@ -44,13 +44,15 @@ function createLocalizedHelpConfig(t) {
|
|
|
44
44
|
const helpWidth = helper.helpWidth || 80;
|
|
45
45
|
const itemIndentWidth = 2;
|
|
46
46
|
const itemSeparatorWidth = 2;
|
|
47
|
+
const bulletIndentWidth = 4; // " • "
|
|
47
48
|
|
|
48
|
-
function formatItem(term, description) {
|
|
49
|
+
function formatItem(term, description, indentWidth) {
|
|
50
|
+
const indent = indentWidth ?? itemIndentWidth;
|
|
49
51
|
if (description) {
|
|
50
52
|
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
|
|
51
53
|
return helper.wrap(
|
|
52
54
|
fullText,
|
|
53
|
-
helpWidth -
|
|
55
|
+
helpWidth - indent,
|
|
54
56
|
termWidth + itemSeparatorWidth
|
|
55
57
|
);
|
|
56
58
|
}
|
|
@@ -62,6 +64,17 @@ function createLocalizedHelpConfig(t) {
|
|
|
62
64
|
return textArray.join('\n').replace(/^/gm, ' '.repeat(itemIndentWidth));
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
function formatBulletList(textArray) {
|
|
68
|
+
return textArray
|
|
69
|
+
.map((text) => {
|
|
70
|
+
const lines = text.split('\n');
|
|
71
|
+
return lines
|
|
72
|
+
.map((line, i) => (i === 0 ? ` ${kleur.dim('•')} ${line}` : ` ${line}`))
|
|
73
|
+
.join('\n');
|
|
74
|
+
})
|
|
75
|
+
.join('\n');
|
|
76
|
+
}
|
|
77
|
+
|
|
65
78
|
function localizeSubcommandTerm(term) {
|
|
66
79
|
return term.replace(/ \[options\]/g, ` ${t('cli.help.inline.options')}`);
|
|
67
80
|
}
|
|
@@ -128,24 +141,34 @@ function createLocalizedHelpConfig(t) {
|
|
|
128
141
|
.map((sub) =>
|
|
129
142
|
formatItem(
|
|
130
143
|
localizeSubcommandTerm(helper.subcommandTerm(sub)),
|
|
131
|
-
helper.subcommandDescription(sub)
|
|
144
|
+
helper.subcommandDescription(sub),
|
|
145
|
+
bulletIndentWidth
|
|
132
146
|
)
|
|
133
147
|
);
|
|
134
148
|
if (items.length === 0) continue;
|
|
135
|
-
output = output.concat([
|
|
149
|
+
output = output.concat([
|
|
150
|
+
kleur.cyan().bold(t(`cli.help.group.${group.id}`)),
|
|
151
|
+
formatBulletList(items),
|
|
152
|
+
''
|
|
153
|
+
]);
|
|
136
154
|
}
|
|
137
155
|
const otherItems = visibleCommands
|
|
138
156
|
.filter((c) => !knownIds.has(c.name()))
|
|
139
157
|
.map((sub) =>
|
|
140
158
|
formatItem(
|
|
141
159
|
localizeSubcommandTerm(helper.subcommandTerm(sub)),
|
|
142
|
-
helper.subcommandDescription(sub)
|
|
160
|
+
helper.subcommandDescription(sub),
|
|
161
|
+
bulletIndentWidth
|
|
143
162
|
)
|
|
144
163
|
);
|
|
145
164
|
if (otherItems.length > 0) {
|
|
146
|
-
output = output.concat([
|
|
165
|
+
output = output.concat([
|
|
166
|
+
kleur.cyan().bold(t('cli.help.group.other')),
|
|
167
|
+
formatBulletList(otherItems),
|
|
168
|
+
''
|
|
169
|
+
]);
|
|
147
170
|
}
|
|
148
|
-
output = output.concat([helper.wrap(t('cli.help.tip'), helpWidth, 0), '']);
|
|
171
|
+
output = output.concat([kleur.dim(helper.wrap(t('cli.help.tip'), helpWidth, 0)), '']);
|
|
149
172
|
} else {
|
|
150
173
|
// Subcommand help — keep the flat list (no grouping).
|
|
151
174
|
const commandList = visibleCommands.map((subcommand) =>
|
package/lib/utils/i18n.js
CHANGED
|
@@ -22,15 +22,15 @@ const MESSAGES = {
|
|
|
22
22
|
'cli.help.heading.options': 'Options',
|
|
23
23
|
'cli.help.heading.globalOptions': 'Global Options',
|
|
24
24
|
'cli.help.heading.commands': 'Commands',
|
|
25
|
-
'cli.help.group.start': '
|
|
26
|
-
'cli.help.group.work': '
|
|
27
|
-
'cli.help.group.publish': '
|
|
28
|
-
'cli.help.group.maintenance': '
|
|
29
|
-
'cli.help.group.advanced': '
|
|
25
|
+
'cli.help.group.start': 'Get started',
|
|
26
|
+
'cli.help.group.work': 'Work on your app',
|
|
27
|
+
'cli.help.group.publish': 'Publish & test',
|
|
28
|
+
'cli.help.group.maintenance': 'Kasy CLI maintenance',
|
|
29
|
+
'cli.help.group.advanced': 'Advanced',
|
|
30
30
|
'cli.help.group.other': 'Other',
|
|
31
31
|
'cli.help.tip': 'Tip: run `kasy <command> --help` for details. Use --lang pt|en|es to switch language.',
|
|
32
|
-
'cli.command.setup.description': '
|
|
33
|
-
'cli.command.new.description': '
|
|
32
|
+
'cli.command.setup.description': '(advanced) Set up an existing Flutter project',
|
|
33
|
+
'cli.command.new.description': 'Create a new app (e.g.: kasy new my-app)',
|
|
34
34
|
'cli.command.new.projectName': 'project name',
|
|
35
35
|
'cli.command.new.projectNameArg': 'Project folder name',
|
|
36
36
|
'prompt.projectName.enter': "What's your project name?",
|
|
@@ -43,13 +43,13 @@ const MESSAGES = {
|
|
|
43
43
|
'cli.command.setup.backendOption': 'Backend adapter (firebase, supabase, api)',
|
|
44
44
|
'cli.command.setup.featuresOption': 'Comma separated optional features (web,widget,llm_chat,revenuecat,ci)',
|
|
45
45
|
'cli.command.help.paramName': 'command',
|
|
46
|
-
'cli.command.doctor.description': '
|
|
47
|
-
'cli.command.modules.description': '
|
|
48
|
-
'cli.command.validate.description': '
|
|
46
|
+
'cli.command.doctor.description': 'Check if your computer is ready to run Kasy',
|
|
47
|
+
'cli.command.modules.description': 'Show what comes included and what you can add',
|
|
48
|
+
'cli.command.validate.description': '(advanced) Validate backend + feature combinations',
|
|
49
49
|
'cli.command.validate.analyzeOnlyOption': 'Run flutter analyze only (skip builds)',
|
|
50
|
-
'cli.command.version.description': '
|
|
51
|
-
'cli.command.upgrade.description': '
|
|
52
|
-
'cli.command.uninstall.description': '
|
|
50
|
+
'cli.command.version.description': 'Show the installed Kasy version',
|
|
51
|
+
'cli.command.upgrade.description': 'Update the Kasy CLI to the latest version',
|
|
52
|
+
'cli.command.uninstall.description': 'Uninstall Kasy from this computer',
|
|
53
53
|
'cli.command.upgrade.running': 'Updating kasy CLI...',
|
|
54
54
|
'cli.command.upgrade.done': 'kasy updated successfully!',
|
|
55
55
|
'cli.command.uninstall.running': 'Uninstalling kasy CLI...',
|
|
@@ -271,20 +271,20 @@ const MESSAGES = {
|
|
|
271
271
|
|
|
272
272
|
'new.firebase.success.deployStep': '• Deploy backend (from inside the project folder):',
|
|
273
273
|
|
|
274
|
-
'cli.command.deploy.description': '
|
|
275
|
-
'cli.command.check.description': '
|
|
274
|
+
'cli.command.deploy.description': 'Publish the server to Firebase or Supabase',
|
|
275
|
+
'cli.command.check.description': 'Check push notifications setup (use --fix to fix it)',
|
|
276
276
|
'deploy.q.project': 'Firebase Project ID:',
|
|
277
277
|
'deploy.q.serviceAccount': 'Path to service account JSON:',
|
|
278
278
|
'deploy.detected.project': '✓ Firebase project detected:',
|
|
279
279
|
'deploy.detected.serviceAccount': '✓ Service account detected:',
|
|
280
280
|
'deploy.error.notProject': 'No firebase.json found in this directory. Run kasy deploy from inside the project folder.',
|
|
281
281
|
|
|
282
|
-
'cli.command.ios.description': '
|
|
282
|
+
'cli.command.ios.description': 'Publish the app to the App Store (Mac needed)',
|
|
283
283
|
'cli.command.ios.configure.description': 'Configure Apple API credentials for local IPA upload',
|
|
284
284
|
'cli.command.ios.release.description': 'Bump build, create IPA, and upload to App Store Connect',
|
|
285
285
|
'cli.command.ios.build.description': 'Build IPA only (no upload)',
|
|
286
286
|
'cli.command.ios.clean.description': 'Clean Flutter/Xcode caches before a failed iOS build',
|
|
287
|
-
'cli.command.codemagic.description': '
|
|
287
|
+
'cli.command.codemagic.description': 'Build the app in the cloud (no Mac needed)',
|
|
288
288
|
'cli.command.codemagic.configure.description': 'Configure Codemagic API credentials',
|
|
289
289
|
'cli.command.codemagic.release.description': 'Start a Codemagic iOS workflow build',
|
|
290
290
|
'cli.command.codemagic.status.description': 'Show Codemagic build status by ID',
|
|
@@ -601,7 +601,7 @@ const MESSAGES = {
|
|
|
601
601
|
'new.internet.warning': '📶 Make sure you have a stable internet connection — this step requires network access.',
|
|
602
602
|
|
|
603
603
|
// run command
|
|
604
|
-
'cli.command.run.description': '
|
|
604
|
+
'cli.command.run.description': 'Run your app on phone, simulator, or browser',
|
|
605
605
|
'run.launching': 'Launching Flutter app...',
|
|
606
606
|
'run.updateHint.prefix': 'Project improvements available —',
|
|
607
607
|
'run.updateHint.suffix': 'to see what\'s new',
|
|
@@ -619,13 +619,13 @@ const MESSAGES = {
|
|
|
619
619
|
'doctor.project.noModules': 'No optional features active',
|
|
620
620
|
|
|
621
621
|
// add command
|
|
622
|
-
'cli.command.add.description': '
|
|
622
|
+
'cli.command.add.description': 'Add a new feature to your app (e.g.: kasy add ai_chat)',
|
|
623
623
|
|
|
624
624
|
// docs command
|
|
625
|
-
'cli.command.docs.description': '
|
|
625
|
+
'cli.command.docs.description': 'Open the full documentation',
|
|
626
626
|
|
|
627
627
|
// notifications command
|
|
628
|
-
'cli.command.notifications.description': '
|
|
628
|
+
'cli.command.notifications.description': 'Edit the text of local notifications and reminders',
|
|
629
629
|
'cli.command.notifications.text.description': 'Set titles and bodies shown in local notifications',
|
|
630
630
|
'notifications.error.notKasyProject': 'No kit_setup.json found. Run this command from inside a Kasy project.',
|
|
631
631
|
'notifications.error.noI18n': 'lib/i18n/*.i18n.json not found in this project.',
|
|
@@ -689,7 +689,7 @@ const MESSAGES = {
|
|
|
689
689
|
'add.llm_chat.nextSteps.supabase': '\n Next steps:\n 1. The LLM_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 2. Run the app: kasy run\n',
|
|
690
690
|
'add.llm_chat.nextSteps.supabase.deployFailed': '\n Next steps:\n 1. Deploy manually: supabase functions deploy llm-chat --no-verify-jwt\n 2. The LLM_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 3. Run the app: kasy run\n',
|
|
691
691
|
'add.llm_chat.nextSteps.api': '\n Next steps:\n 1. Create an endpoint on your server that accepts {message, history} and calls your LLM.\n 2. Update LLM_CHAT_ENDPOINT in .vscode/launch.json with your endpoint URL.\n 3. Run the app: kasy run\n',
|
|
692
|
-
'cli.command.remove.description': '
|
|
692
|
+
'cli.command.remove.description': 'Remove a feature you no longer use (e.g.: kasy remove sentry)',
|
|
693
693
|
'remove.error.noModule': 'Provide a feature name. Usage: kasy remove <feature>',
|
|
694
694
|
'remove.error.notKasyProject': 'No kit_setup.json found. Run this command from inside a Kasy project.',
|
|
695
695
|
'remove.error.unknownModule': 'Unknown feature: {module}\nAvailable: {list}',
|
|
@@ -706,7 +706,7 @@ const MESSAGES = {
|
|
|
706
706
|
'remove.success': 'Feature "{module}" removed successfully.',
|
|
707
707
|
'remove.warn.ci': 'CI files removed. If you had custom workflow files, restore them from git.',
|
|
708
708
|
'remove.warn.sentry.shared': 'sentry_flutter kept — still required by active features (revenuecat/facebook).',
|
|
709
|
-
'cli.command.update.description': '
|
|
709
|
+
'cli.command.update.description': 'Update parts of your app to the latest (e.g.: kasy update components)',
|
|
710
710
|
'cli.command.update.targetArg': 'Target to update (e.g. revenuecat, sentry, components)',
|
|
711
711
|
'update.error.noProject': 'No kit_setup.json found. Run this command from inside a Kasy project.',
|
|
712
712
|
'update.error.unknownModule': 'Unknown feature: {module}\nAvailable: {list}',
|
|
@@ -762,15 +762,15 @@ const MESSAGES = {
|
|
|
762
762
|
'cli.help.heading.options': 'Opções',
|
|
763
763
|
'cli.help.heading.globalOptions': 'Opções globais',
|
|
764
764
|
'cli.help.heading.commands': 'Comandos',
|
|
765
|
-
'cli.help.group.start': '
|
|
766
|
-
'cli.help.group.work': '
|
|
767
|
-
'cli.help.group.publish': '
|
|
768
|
-
'cli.help.group.maintenance': '
|
|
769
|
-
'cli.help.group.advanced': '
|
|
765
|
+
'cli.help.group.start': 'Para começar',
|
|
766
|
+
'cli.help.group.work': 'Trabalhar no app',
|
|
767
|
+
'cli.help.group.publish': 'Publicar e testar',
|
|
768
|
+
'cli.help.group.maintenance': 'Manutenção da Kasy CLI',
|
|
769
|
+
'cli.help.group.advanced': 'Avançado',
|
|
770
770
|
'cli.help.group.other': 'Outros',
|
|
771
771
|
'cli.help.tip': 'Dica: rode `kasy <comando> --help` para detalhes. Use --lang pt|en|es para mudar o idioma.',
|
|
772
|
-
'cli.command.setup.description': '
|
|
773
|
-
'cli.command.new.description': '
|
|
772
|
+
'cli.command.setup.description': '(avançado) Configura um projeto Flutter existente',
|
|
773
|
+
'cli.command.new.description': 'Cria um app novo (ex: kasy new meu-app)',
|
|
774
774
|
'cli.command.new.projectName': 'nome do projeto',
|
|
775
775
|
'cli.command.new.projectNameArg': 'Nome da pasta do projeto',
|
|
776
776
|
'prompt.projectName.enter': 'Qual o nome do seu projeto?',
|
|
@@ -783,13 +783,13 @@ const MESSAGES = {
|
|
|
783
783
|
'cli.command.setup.backendOption': 'Adapter de backend (firebase, supabase, api)',
|
|
784
784
|
'cli.command.setup.featuresOption': 'Features opcionais separadas por virgula (web,widget,llm_chat,revenuecat,ci)',
|
|
785
785
|
'cli.command.help.paramName': 'comando',
|
|
786
|
-
'cli.command.doctor.description': '
|
|
787
|
-
'cli.command.modules.description': '
|
|
788
|
-
'cli.command.validate.description': '
|
|
786
|
+
'cli.command.doctor.description': 'Verifica se o seu computador está pronto para rodar a Kasy',
|
|
787
|
+
'cli.command.modules.description': 'Mostra o que já vem incluso e o que você pode adicionar',
|
|
788
|
+
'cli.command.validate.description': '(avançado) Valida combinações de backend e features',
|
|
789
789
|
'cli.command.validate.analyzeOnlyOption': 'Executa apenas flutter analyze (sem build)',
|
|
790
|
-
'cli.command.version.description': '
|
|
791
|
-
'cli.command.upgrade.description': '
|
|
792
|
-
'cli.command.uninstall.description': '
|
|
790
|
+
'cli.command.version.description': 'Mostra a versão instalada da Kasy',
|
|
791
|
+
'cli.command.upgrade.description': 'Atualiza a Kasy CLI para a versão mais recente',
|
|
792
|
+
'cli.command.uninstall.description': 'Desinstala a Kasy deste computador',
|
|
793
793
|
'cli.command.upgrade.running': 'Atualizando a CLI kasy...',
|
|
794
794
|
'cli.command.upgrade.done': 'kasy atualizado com sucesso!',
|
|
795
795
|
'cli.command.uninstall.running': 'Desinstalando a CLI kasy...',
|
|
@@ -1011,20 +1011,20 @@ const MESSAGES = {
|
|
|
1011
1011
|
|
|
1012
1012
|
'new.firebase.success.deployStep': '• Deploy do backend (de dentro da pasta do projeto):',
|
|
1013
1013
|
|
|
1014
|
-
'cli.command.deploy.description': '
|
|
1015
|
-
'cli.command.check.description': '
|
|
1014
|
+
'cli.command.deploy.description': 'Publica o servidor no Firebase ou Supabase',
|
|
1015
|
+
'cli.command.check.description': 'Confere se as notificações push estão configuradas (use --fix para corrigir)',
|
|
1016
1016
|
'deploy.q.project': 'Firebase Project ID:',
|
|
1017
1017
|
'deploy.q.serviceAccount': 'Caminho para o service account JSON:',
|
|
1018
1018
|
'deploy.detected.project': '✓ Projeto Firebase detectado:',
|
|
1019
1019
|
'deploy.detected.serviceAccount': '✓ Service account detectado:',
|
|
1020
1020
|
'deploy.error.notProject': 'Nenhum firebase.json encontrado. Execute kasy deploy de dentro da pasta do projeto.',
|
|
1021
1021
|
|
|
1022
|
-
'cli.command.ios.description': '
|
|
1022
|
+
'cli.command.ios.description': 'Publica o app na App Store (precisa de Mac)',
|
|
1023
1023
|
'cli.command.ios.configure.description': 'Configurar credenciais Apple para envio local do IPA',
|
|
1024
1024
|
'cli.command.ios.release.description': 'Incrementa build, gera IPA e envia para App Store Connect',
|
|
1025
1025
|
'cli.command.ios.build.description': 'Só gera o IPA (sem enviar)',
|
|
1026
1026
|
'cli.command.ios.clean.description': 'Limpa caches Flutter/Xcode após falha no build iOS',
|
|
1027
|
-
'cli.command.codemagic.description': '
|
|
1027
|
+
'cli.command.codemagic.description': 'Compila o app na nuvem (sem precisar de Mac)',
|
|
1028
1028
|
'cli.command.codemagic.configure.description': 'Configurar credenciais da API Codemagic',
|
|
1029
1029
|
'cli.command.codemagic.release.description': 'Iniciar build do workflow iOS no Codemagic',
|
|
1030
1030
|
'cli.command.codemagic.status.description': 'Status do build Codemagic por ID',
|
|
@@ -1341,7 +1341,7 @@ const MESSAGES = {
|
|
|
1341
1341
|
'new.internet.warning': '📶 Verifique se voce esta com uma internet estavel — esta etapa precisa de conexao.',
|
|
1342
1342
|
|
|
1343
1343
|
// run command
|
|
1344
|
-
'cli.command.run.description': '
|
|
1344
|
+
'cli.command.run.description': 'Roda o app no celular, simulador ou navegador',
|
|
1345
1345
|
'run.launching': 'Iniciando app Flutter...',
|
|
1346
1346
|
'run.updateHint.prefix': 'Melhorias disponíveis para o projeto —',
|
|
1347
1347
|
'run.updateHint.suffix': 'para ver o que há de novo',
|
|
@@ -1359,13 +1359,13 @@ const MESSAGES = {
|
|
|
1359
1359
|
'doctor.project.noModules': 'Nenhuma feature opcional ativa',
|
|
1360
1360
|
|
|
1361
1361
|
// add command
|
|
1362
|
-
'cli.command.add.description': '
|
|
1362
|
+
'cli.command.add.description': 'Adiciona algo novo ao app (ex: kasy add ai_chat)',
|
|
1363
1363
|
|
|
1364
1364
|
// docs command
|
|
1365
|
-
'cli.command.docs.description': '
|
|
1365
|
+
'cli.command.docs.description': 'Abre a documentação completa',
|
|
1366
1366
|
|
|
1367
1367
|
// notifications command
|
|
1368
|
-
'cli.command.notifications.description': '
|
|
1368
|
+
'cli.command.notifications.description': 'Edita os textos das notificações locais e lembretes',
|
|
1369
1369
|
'cli.command.notifications.text.description': 'Define titulos e mensagens das notificacoes locais',
|
|
1370
1370
|
'notifications.error.notKasyProject': 'kit_setup.json nao encontrado. Execute dentro de um projeto Kasy.',
|
|
1371
1371
|
'notifications.error.noI18n': 'lib/i18n/*.i18n.json nao encontrado neste projeto.',
|
|
@@ -1429,7 +1429,7 @@ const MESSAGES = {
|
|
|
1429
1429
|
'add.llm_chat.nextSteps.supabase': '\n Proximos passos:\n 1. O LLM_CHAT_ENDPOINT no .vscode/launch.json ja foi preenchido.\n 2. Rode o app: kasy run\n',
|
|
1430
1430
|
'add.llm_chat.nextSteps.supabase.deployFailed': '\n Proximos passos:\n 1. Deploy manual: supabase functions deploy llm-chat --no-verify-jwt\n 2. O LLM_CHAT_ENDPOINT no .vscode/launch.json ja foi preenchido.\n 3. Rode o app: kasy run\n',
|
|
1431
1431
|
'add.llm_chat.nextSteps.api': '\n Proximos passos:\n 1. Crie um endpoint no seu servidor que aceite {message, history} e chame sua LLM.\n 2. Atualize LLM_CHAT_ENDPOINT no .vscode/launch.json com a URL do seu endpoint.\n 3. Rode o app: kasy run\n',
|
|
1432
|
-
'cli.command.remove.description': '
|
|
1432
|
+
'cli.command.remove.description': 'Remove algo que você não usa mais (ex: kasy remove sentry)',
|
|
1433
1433
|
'remove.error.noModule': 'Informe o nome da feature. Uso: kasy remove <feature>',
|
|
1434
1434
|
'remove.error.notKasyProject': 'kit_setup.json nao encontrado. Execute este comando dentro de um projeto Kasy.',
|
|
1435
1435
|
'remove.error.unknownModule': 'Feature desconhecida: {module}\nDisponiveis: {list}',
|
|
@@ -1446,7 +1446,7 @@ const MESSAGES = {
|
|
|
1446
1446
|
'remove.success': 'Feature "{module}" removida com sucesso.',
|
|
1447
1447
|
'remove.warn.ci': 'Arquivos de CI removidos. Se tinha workflows customizados, restaure-os pelo git.',
|
|
1448
1448
|
'remove.warn.sentry.shared': 'sentry_flutter mantido — ainda necessario para features ativas (revenuecat/facebook).',
|
|
1449
|
-
'cli.command.update.description': '
|
|
1449
|
+
'cli.command.update.description': 'Atualiza partes do app para a última versão (ex: kasy update components)',
|
|
1450
1450
|
'cli.command.update.targetArg': 'Alvo para atualizar (ex.: revenuecat, sentry, components)',
|
|
1451
1451
|
'update.error.noProject': 'kit_setup.json nao encontrado. Execute dentro de um projeto Kasy.',
|
|
1452
1452
|
'update.error.unknownModule': 'Modulo desconhecido: {module}\nDisponiveis: {list}',
|
|
@@ -1502,15 +1502,15 @@ const MESSAGES = {
|
|
|
1502
1502
|
'cli.help.heading.options': 'Opciones',
|
|
1503
1503
|
'cli.help.heading.globalOptions': 'Opciones globales',
|
|
1504
1504
|
'cli.help.heading.commands': 'Comandos',
|
|
1505
|
-
'cli.help.group.start': '
|
|
1506
|
-
'cli.help.group.work': '
|
|
1507
|
-
'cli.help.group.publish': '
|
|
1508
|
-
'cli.help.group.maintenance': '
|
|
1509
|
-
'cli.help.group.advanced': '
|
|
1505
|
+
'cli.help.group.start': 'Para empezar',
|
|
1506
|
+
'cli.help.group.work': 'Trabajar en tu app',
|
|
1507
|
+
'cli.help.group.publish': 'Publicar y probar',
|
|
1508
|
+
'cli.help.group.maintenance': 'Mantenimiento de Kasy CLI',
|
|
1509
|
+
'cli.help.group.advanced': 'Avanzado',
|
|
1510
1510
|
'cli.help.group.other': 'Otros',
|
|
1511
1511
|
'cli.help.tip': 'Tip: ejecuta `kasy <comando> --help` para más detalles. Usa --lang pt|en|es para cambiar idioma.',
|
|
1512
|
-
'cli.command.setup.description': '
|
|
1513
|
-
'cli.command.new.description': '
|
|
1512
|
+
'cli.command.setup.description': '(avanzado) Configura un proyecto Flutter existente',
|
|
1513
|
+
'cli.command.new.description': 'Crea una app nueva (ej: kasy new mi-app)',
|
|
1514
1514
|
'cli.command.new.projectName': 'nombre del proyecto',
|
|
1515
1515
|
'cli.command.new.projectNameArg': 'Nombre de la carpeta del proyecto',
|
|
1516
1516
|
'prompt.projectName.enter': '¿Cuál es el nombre de tu proyecto?',
|
|
@@ -1523,13 +1523,13 @@ const MESSAGES = {
|
|
|
1523
1523
|
'cli.command.setup.backendOption': 'Adapter de backend (firebase, supabase, api)',
|
|
1524
1524
|
'cli.command.setup.featuresOption': 'Features opcionales separadas por coma (web,widget,llm_chat,revenuecat,ci)',
|
|
1525
1525
|
'cli.command.help.paramName': 'comando',
|
|
1526
|
-
'cli.command.doctor.description': '
|
|
1527
|
-
'cli.command.modules.description': '
|
|
1528
|
-
'cli.command.validate.description': '
|
|
1526
|
+
'cli.command.doctor.description': 'Verifica si tu computadora está lista para correr Kasy',
|
|
1527
|
+
'cli.command.modules.description': 'Muestra lo que viene incluido y lo que puedes añadir',
|
|
1528
|
+
'cli.command.validate.description': '(avanzado) Valida combinaciones de backend y features',
|
|
1529
1529
|
'cli.command.validate.analyzeOnlyOption': 'Ejecuta solo flutter analyze (sin build)',
|
|
1530
|
-
'cli.command.version.description': '
|
|
1531
|
-
'cli.command.upgrade.description': '
|
|
1532
|
-
'cli.command.uninstall.description': '
|
|
1530
|
+
'cli.command.version.description': 'Muestra la versión instalada de Kasy',
|
|
1531
|
+
'cli.command.upgrade.description': 'Actualiza la Kasy CLI a la última versión',
|
|
1532
|
+
'cli.command.uninstall.description': 'Desinstala Kasy de esta computadora',
|
|
1533
1533
|
'cli.command.upgrade.running': 'Actualizando la CLI kasy...',
|
|
1534
1534
|
'cli.command.upgrade.done': 'kasy actualizado correctamente!',
|
|
1535
1535
|
'cli.command.uninstall.running': 'Desinstalando la CLI kasy...',
|
|
@@ -1753,20 +1753,20 @@ const MESSAGES = {
|
|
|
1753
1753
|
|
|
1754
1754
|
'new.firebase.success.deployStep': '• Desplegar backend (desde dentro de la carpeta del proyecto):',
|
|
1755
1755
|
|
|
1756
|
-
'cli.command.deploy.description': '
|
|
1757
|
-
'cli.command.check.description': '
|
|
1756
|
+
'cli.command.deploy.description': 'Publica el servidor en Firebase o Supabase',
|
|
1757
|
+
'cli.command.check.description': 'Verifica si las notificaciones push están configuradas (usa --fix para arreglar)',
|
|
1758
1758
|
'deploy.q.project': 'Firebase Project ID:',
|
|
1759
1759
|
'deploy.q.serviceAccount': 'Ruta al service account JSON:',
|
|
1760
1760
|
'deploy.detected.project': '✓ Proyecto Firebase detectado:',
|
|
1761
1761
|
'deploy.detected.serviceAccount': '✓ Service account detectado:',
|
|
1762
1762
|
'deploy.error.notProject': 'No se encontro firebase.json. Ejecute kasy deploy desde dentro de la carpeta del proyecto.',
|
|
1763
1763
|
|
|
1764
|
-
'cli.command.ios.description': '
|
|
1764
|
+
'cli.command.ios.description': 'Publica la app en la App Store (necesita Mac)',
|
|
1765
1765
|
'cli.command.ios.configure.description': 'Configurar credenciales Apple para subida local del IPA',
|
|
1766
1766
|
'cli.command.ios.release.description': 'Incrementa build, genera IPA y sube a App Store Connect',
|
|
1767
1767
|
'cli.command.ios.build.description': 'Solo genera el IPA (sin subir)',
|
|
1768
1768
|
'cli.command.ios.clean.description': 'Limpia cachés Flutter/Xcode tras fallo en build iOS',
|
|
1769
|
-
'cli.command.codemagic.description': '
|
|
1769
|
+
'cli.command.codemagic.description': 'Compila la app en la nube (sin necesitar Mac)',
|
|
1770
1770
|
'cli.command.codemagic.configure.description': 'Configurar credenciales API de Codemagic',
|
|
1771
1771
|
'cli.command.codemagic.release.description': 'Iniciar build del workflow iOS en Codemagic',
|
|
1772
1772
|
'cli.command.codemagic.status.description': 'Estado del build Codemagic por ID',
|
|
@@ -2081,7 +2081,7 @@ const MESSAGES = {
|
|
|
2081
2081
|
'new.internet.warning': '📶 Asegurate de tener una conexion a internet estable — este paso requiere red.',
|
|
2082
2082
|
|
|
2083
2083
|
// run command
|
|
2084
|
-
'cli.command.run.description': '
|
|
2084
|
+
'cli.command.run.description': 'Corre la app en celular, simulador o navegador',
|
|
2085
2085
|
'run.launching': 'Iniciando app Flutter...',
|
|
2086
2086
|
'run.updateHint.prefix': 'Mejoras disponibles para el proyecto —',
|
|
2087
2087
|
'run.updateHint.suffix': 'para ver las novedades',
|
|
@@ -2099,13 +2099,13 @@ const MESSAGES = {
|
|
|
2099
2099
|
'doctor.project.noModules': 'Ninguna feature opcional activa',
|
|
2100
2100
|
|
|
2101
2101
|
// add command
|
|
2102
|
-
'cli.command.add.description': '
|
|
2102
|
+
'cli.command.add.description': 'Añade algo nuevo a tu app (ej: kasy add ai_chat)',
|
|
2103
2103
|
|
|
2104
2104
|
// docs command
|
|
2105
|
-
'cli.command.docs.description': '
|
|
2105
|
+
'cli.command.docs.description': 'Abre la documentación completa',
|
|
2106
2106
|
|
|
2107
2107
|
// notifications command
|
|
2108
|
-
'cli.command.notifications.description': '
|
|
2108
|
+
'cli.command.notifications.description': 'Edita los textos de las notificaciones locales y recordatorios',
|
|
2109
2109
|
'cli.command.notifications.text.description': 'Define titulos y mensajes de notificaciones locales',
|
|
2110
2110
|
'notifications.error.notKasyProject': 'No se encontro kit_setup.json. Ejecuta dentro de un proyecto Kasy.',
|
|
2111
2111
|
'notifications.error.noI18n': 'lib/i18n/*.i18n.json no encontrado en este proyecto.',
|
|
@@ -2169,7 +2169,7 @@ const MESSAGES = {
|
|
|
2169
2169
|
'add.llm_chat.nextSteps.supabase': '\n Proximos pasos:\n 1. El LLM_CHAT_ENDPOINT en .vscode/launch.json ya fue pre-llenado.\n 2. Corre el app: kasy run\n',
|
|
2170
2170
|
'add.llm_chat.nextSteps.supabase.deployFailed': '\n Proximos pasos:\n 1. Deploy manual: supabase functions deploy llm-chat --no-verify-jwt\n 2. El LLM_CHAT_ENDPOINT en .vscode/launch.json ya fue pre-llenado.\n 3. Corre el app: kasy run\n',
|
|
2171
2171
|
'add.llm_chat.nextSteps.api': '\n Proximos pasos:\n 1. Crea un endpoint en tu servidor que acepte {message, history} y llame tu LLM.\n 2. Actualiza LLM_CHAT_ENDPOINT en .vscode/launch.json con la URL de tu endpoint.\n 3. Corre el app: kasy run\n',
|
|
2172
|
-
'cli.command.remove.description': '
|
|
2172
|
+
'cli.command.remove.description': 'Elimina algo que ya no usas (ej: kasy remove sentry)',
|
|
2173
2173
|
'remove.error.noModule': 'Ingresa el nombre de la feature. Uso: kasy remove <feature>',
|
|
2174
2174
|
'remove.error.notKasyProject': 'kit_setup.json no encontrado. Ejecuta este comando dentro de un proyecto Kasy.',
|
|
2175
2175
|
'remove.error.unknownModule': 'Modulo desconocido: {module}\nDisponibles: {list}',
|
|
@@ -2186,7 +2186,7 @@ const MESSAGES = {
|
|
|
2186
2186
|
'remove.success': 'Feature "{module}" eliminada exitosamente.',
|
|
2187
2187
|
'remove.warn.ci': 'Archivos de CI eliminados. Si tenias workflows personalizados, restauralos desde git.',
|
|
2188
2188
|
'remove.warn.sentry.shared': 'sentry_flutter conservado — todavia requerido por features activas (revenuecat/facebook).',
|
|
2189
|
-
'cli.command.update.description': '
|
|
2189
|
+
'cli.command.update.description': 'Actualiza partes de tu app a la última versión (ej: kasy update components)',
|
|
2190
2190
|
'cli.command.update.targetArg': 'Objetivo a actualizar (ej.: revenuecat, sentry, components)',
|
|
2191
2191
|
'update.error.noProject': 'kit_setup.json no encontrado. Ejecuta dentro de un proyecto Kasy.',
|
|
2192
2192
|
'update.error.unknownModule': 'Modulo desconocido: {module}\nDisponibles: {list}',
|
package/package.json
CHANGED
|
@@ -39,8 +39,9 @@ class MyWidgetWidget : GlanceAppWidget() {
|
|
|
39
39
|
@Composable
|
|
40
40
|
private fun GlanceContent(context: Context, currentState: HomeWidgetGlanceState) {
|
|
41
41
|
val prefs = currentState.preferences
|
|
42
|
-
val greeting = prefs.getString("greeting", "
|
|
43
|
-
val
|
|
42
|
+
val greeting = prefs.getString("greeting", "") ?: ""
|
|
43
|
+
val title = prefs.getString("title", "") ?: ""
|
|
44
|
+
val planText = prefs.getString("planText", "") ?: ""
|
|
44
45
|
val isPro = prefs.getString("isPro", "false") == "true"
|
|
45
46
|
|
|
46
47
|
val bgColor = Color(red = 0.08f, green = 0.03f, blue = 0.16f)
|
|
@@ -63,7 +64,7 @@ class MyWidgetWidget : GlanceAppWidget() {
|
|
|
63
64
|
),
|
|
64
65
|
)
|
|
65
66
|
Text(
|
|
66
|
-
text =
|
|
67
|
+
text = title,
|
|
67
68
|
style = TextStyle(
|
|
68
69
|
color = ColorProvider(white),
|
|
69
70
|
fontSize = 22.sp,
|
|
@@ -73,7 +74,7 @@ class MyWidgetWidget : GlanceAppWidget() {
|
|
|
73
74
|
)
|
|
74
75
|
Spacer(modifier = GlanceModifier.defaultWeight())
|
|
75
76
|
Text(
|
|
76
|
-
text = if (isPro) "⭐
|
|
77
|
+
text = if (isPro) "⭐ $planText" else planText,
|
|
77
78
|
style = TextStyle(
|
|
78
79
|
color = ColorProvider(if (isPro) gold else whiteVerySubtle),
|
|
79
80
|
fontSize = 11.sp,
|
|
@@ -3,15 +3,16 @@ import SwiftUI
|
|
|
3
3
|
|
|
4
4
|
struct MyWidgetProvider: TimelineProvider {
|
|
5
5
|
func placeholder(in context: Context) -> MyWidgetEntry {
|
|
6
|
-
MyWidgetEntry(date: Date(), greeting: "
|
|
6
|
+
MyWidgetEntry(date: Date(), greeting: "", title: "", planText: "", isPro: false)
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
func getSnapshot(in context: Context, completion: @escaping (MyWidgetEntry) -> Void) {
|
|
10
10
|
let prefs = UserDefaults(suiteName: "group.com.aicrus.firebase.kit")
|
|
11
11
|
completion(MyWidgetEntry(
|
|
12
12
|
date: Date(),
|
|
13
|
-
greeting: prefs?.string(forKey: "greeting") ?? "
|
|
14
|
-
|
|
13
|
+
greeting: prefs?.string(forKey: "greeting") ?? "",
|
|
14
|
+
title: prefs?.string(forKey: "title") ?? "",
|
|
15
|
+
planText: prefs?.string(forKey: "planText") ?? "",
|
|
15
16
|
isPro: prefs?.string(forKey: "isPro") == "true"
|
|
16
17
|
))
|
|
17
18
|
}
|
|
@@ -26,13 +27,15 @@ struct MyWidgetProvider: TimelineProvider {
|
|
|
26
27
|
struct MyWidgetEntry: TimelineEntry {
|
|
27
28
|
let date: Date
|
|
28
29
|
let greeting: String
|
|
29
|
-
let
|
|
30
|
+
let title: String
|
|
31
|
+
let planText: String
|
|
30
32
|
let isPro: Bool
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
struct MyWidgetWidgetView: View {
|
|
34
36
|
var entry: MyWidgetProvider.Entry
|
|
35
37
|
@Environment(\.widgetFamily) var family
|
|
38
|
+
@Environment(\.colorScheme) var colorScheme
|
|
36
39
|
|
|
37
40
|
private var titleSize: CGFloat {
|
|
38
41
|
switch family {
|
|
@@ -42,6 +45,15 @@ struct MyWidgetWidgetView: View {
|
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
|
|
48
|
+
private var gradientColors: [Color] {
|
|
49
|
+
// Dark theme stays the same in both light/dark modes for brand consistency;
|
|
50
|
+
// tweak here if you want true light-mode variant.
|
|
51
|
+
return [
|
|
52
|
+
Color(red: 0.08, green: 0.03, blue: 0.16),
|
|
53
|
+
Color(red: 0.20, green: 0.09, blue: 0.42),
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
|
|
45
57
|
var body: some View {
|
|
46
58
|
VStack(alignment: .leading, spacing: 0) {
|
|
47
59
|
Text(entry.greeting)
|
|
@@ -51,7 +63,7 @@ struct MyWidgetWidgetView: View {
|
|
|
51
63
|
|
|
52
64
|
Spacer().frame(height: 6)
|
|
53
65
|
|
|
54
|
-
Text(
|
|
66
|
+
Text(entry.title)
|
|
55
67
|
.font(.system(size: titleSize, weight: .bold, design: .rounded))
|
|
56
68
|
.foregroundStyle(.white)
|
|
57
69
|
.lineLimit(2)
|
|
@@ -60,7 +72,7 @@ struct MyWidgetWidgetView: View {
|
|
|
60
72
|
Spacer()
|
|
61
73
|
|
|
62
74
|
if entry.isPro {
|
|
63
|
-
Label(
|
|
75
|
+
Label(entry.planText, systemImage: "star.fill")
|
|
64
76
|
.font(.system(size: 10, weight: .bold, design: .rounded))
|
|
65
77
|
.foregroundStyle(Color(red: 1.0, green: 0.84, blue: 0.0))
|
|
66
78
|
.padding(.horizontal, 8)
|
|
@@ -68,7 +80,7 @@ struct MyWidgetWidgetView: View {
|
|
|
68
80
|
.background(Color(red: 1.0, green: 0.84, blue: 0.0).opacity(0.18))
|
|
69
81
|
.clipShape(Capsule())
|
|
70
82
|
} else {
|
|
71
|
-
Text(
|
|
83
|
+
Text(entry.planText)
|
|
72
84
|
.font(.system(size: 10, weight: .medium, design: .rounded))
|
|
73
85
|
.foregroundStyle(.white.opacity(0.4))
|
|
74
86
|
}
|
|
@@ -104,11 +116,11 @@ struct MyWidgetWidget: Widget {
|
|
|
104
116
|
#Preview("Small", as: .systemSmall) {
|
|
105
117
|
MyWidgetWidget()
|
|
106
118
|
} timeline: {
|
|
107
|
-
MyWidgetEntry(date: .now, greeting: "
|
|
119
|
+
MyWidgetEntry(date: .now, greeting: "Bom dia", title: "Olá, Paulo!", planText: "PRO", isPro: true)
|
|
108
120
|
}
|
|
109
121
|
|
|
110
122
|
#Preview("Medium", as: .systemMedium) {
|
|
111
123
|
MyWidgetWidget()
|
|
112
124
|
} timeline: {
|
|
113
|
-
MyWidgetEntry(date: .now, greeting: "
|
|
125
|
+
MyWidgetEntry(date: .now, greeting: "Boa tarde", title: "Olá, Paulo!", planText: "Plano grátis", isPro: false)
|
|
114
126
|
}
|
|
@@ -4,6 +4,7 @@ import 'package:kasy_kit/core/shared_preferences/shared_preferences.dart';
|
|
|
4
4
|
import 'package:kasy_kit/core/states/user_state_notifier.dart';
|
|
5
5
|
import 'package:kasy_kit/features/authentication/api/authentication_api.dart';
|
|
6
6
|
import 'package:kasy_kit/features/subscription/repositories/subscription_repository.dart';
|
|
7
|
+
import 'package:kasy_kit/i18n/translations.g.dart';
|
|
7
8
|
import 'package:logger/logger.dart';
|
|
8
9
|
|
|
9
10
|
/// Generated by Kasy CLI
|
|
@@ -17,6 +18,18 @@ Future<void> homeWidgetCallbackDispatcher() async {
|
|
|
17
18
|
final globalContainer = ProviderContainer();
|
|
18
19
|
final sharedPreferences = globalContainer.read(sharedPreferencesProvider);
|
|
19
20
|
await sharedPreferences.init();
|
|
21
|
+
// Restore the user's saved app locale so the widget renders text in the
|
|
22
|
+
// same language as the app (not the device locale).
|
|
23
|
+
final savedLocale = sharedPreferences.prefs.getString('app_locale');
|
|
24
|
+
if (savedLocale != null) {
|
|
25
|
+
final appLocale = AppLocale.values.firstWhere(
|
|
26
|
+
(l) => l.languageCode == savedLocale,
|
|
27
|
+
orElse: () => AppLocale.en,
|
|
28
|
+
);
|
|
29
|
+
LocaleSettings.setLocale(appLocale);
|
|
30
|
+
} else {
|
|
31
|
+
LocaleSettings.useDeviceLocale();
|
|
32
|
+
}
|
|
20
33
|
await globalContainer.read(authenticationApiProvider).init();
|
|
21
34
|
await globalContainer.read(subscriptionRepositoryProvider).init();
|
|
22
35
|
await globalContainer.read(userStateNotifierProvider.notifier).init();
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import 'dart:io';
|
|
2
|
-
|
|
3
1
|
import 'package:home_widget/home_widget.dart';
|
|
4
2
|
import 'package:kasy_kit/core/data/models/user.dart';
|
|
5
3
|
import 'package:kasy_kit/core/home_widgets/home_widget_service.dart';
|
|
4
|
+
import 'package:kasy_kit/core/states/translations.dart';
|
|
6
5
|
import 'package:kasy_kit/core/states/user_state_notifier.dart';
|
|
6
|
+
import 'package:kasy_kit/features/subscription/repositories/subscription_repository.dart';
|
|
7
|
+
import 'package:kasy_kit/i18n/translations.g.dart';
|
|
7
8
|
import 'package:logger/logger.dart';
|
|
8
9
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
9
10
|
|
|
@@ -19,37 +20,70 @@ class MyWidgetHomeWidget extends _$MyWidgetHomeWidget
|
|
|
19
20
|
void build() {}
|
|
20
21
|
|
|
21
22
|
@override
|
|
22
|
-
Future<void> update() {
|
|
23
|
-
|
|
23
|
+
Future<void> update() async {
|
|
24
|
+
final logger = Logger();
|
|
25
|
+
logger.i('🔄 Updating MyWidget Home Widget');
|
|
24
26
|
final user = ref.read(userStateNotifierProvider).user;
|
|
27
|
+
final t = ref.read(translationsProvider);
|
|
25
28
|
|
|
26
29
|
final name = switch (user) {
|
|
27
30
|
AuthenticatedUserData(:final name)
|
|
28
31
|
when name != null && name.isNotEmpty =>
|
|
29
32
|
name.split(' ').first,
|
|
30
|
-
_ =>
|
|
33
|
+
_ => null,
|
|
31
34
|
};
|
|
32
35
|
|
|
33
|
-
final isPro =
|
|
36
|
+
final isPro = await _resolveIsPro(user);
|
|
37
|
+
|
|
38
|
+
final greeting = _greeting(t);
|
|
39
|
+
final title = name == null
|
|
40
|
+
? t.home_widget.title_default
|
|
41
|
+
: t.home_widget.title_with_name(name: name);
|
|
42
|
+
final planText = isPro ? t.home_widget.plan_pro : t.home_widget.plan_free;
|
|
43
|
+
|
|
44
|
+
logger.d(
|
|
45
|
+
'Widget payload → greeting: "$greeting", title: "$title", '
|
|
46
|
+
'planText: "$planText", isPro: $isPro',
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return updateWidget({
|
|
50
|
+
'greeting': greeting,
|
|
51
|
+
'title': title,
|
|
52
|
+
'planText': planText,
|
|
53
|
+
'isPro': isPro.toString(),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// Returns true if the user has an active subscription.
|
|
58
|
+
/// Queries the SubscriptionRepository directly so the widget reflects the
|
|
59
|
+
/// most recent state — including the RevenueCat fallback when the backend
|
|
60
|
+
/// webhook is delayed. Falls back to the in-memory user.subscription if the
|
|
61
|
+
/// fresh fetch fails (no network, RC not initialised, etc.).
|
|
62
|
+
Future<bool> _resolveIsPro(User user) async {
|
|
63
|
+
final cached = switch (user) {
|
|
34
64
|
AuthenticatedUserData(:final subscription) ||
|
|
35
65
|
AnonymousUserData(:final subscription) =>
|
|
36
66
|
subscription?.isActive ?? false,
|
|
37
67
|
_ => false,
|
|
38
68
|
};
|
|
39
|
-
|
|
40
|
-
return
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
69
|
+
final userId = user.idOrNull;
|
|
70
|
+
if (userId == null) return cached;
|
|
71
|
+
try {
|
|
72
|
+
final repo = ref.read(subscriptionRepositoryProvider);
|
|
73
|
+
await repo.initUser(userId);
|
|
74
|
+
final fresh = await repo.get(userId);
|
|
75
|
+
return fresh.isActive;
|
|
76
|
+
} catch (e) {
|
|
77
|
+
Logger().w('Widget could not refresh subscription: $e (using cached)');
|
|
78
|
+
return cached;
|
|
79
|
+
}
|
|
45
80
|
}
|
|
46
81
|
|
|
47
82
|
Future<void> updateWidget(Map<String, String> data) async {
|
|
48
|
-
await HomeWidget.saveWidgetData<String>(
|
|
49
|
-
|
|
50
|
-
await HomeWidget.saveWidgetData<String>('
|
|
51
|
-
await HomeWidget.saveWidgetData<String>(
|
|
52
|
-
'isPro', data['isPro'] ?? 'false');
|
|
83
|
+
await HomeWidget.saveWidgetData<String>('greeting', data['greeting'] ?? '');
|
|
84
|
+
await HomeWidget.saveWidgetData<String>('title', data['title'] ?? '');
|
|
85
|
+
await HomeWidget.saveWidgetData<String>('planText', data['planText'] ?? '');
|
|
86
|
+
await HomeWidget.saveWidgetData<String>('isPro', data['isPro'] ?? 'false');
|
|
53
87
|
|
|
54
88
|
await HomeWidget.updateWidget(
|
|
55
89
|
name: _androidWidgetName,
|
|
@@ -59,14 +93,9 @@ class MyWidgetHomeWidget extends _$MyWidgetHomeWidget
|
|
|
59
93
|
|
|
60
94
|
Future<Map<String, dynamic>> getWidgetData() async {
|
|
61
95
|
return {
|
|
62
|
-
'greeting': await HomeWidget.getWidgetData<String>(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
),
|
|
66
|
-
'name': await HomeWidget.getWidgetData<String>(
|
|
67
|
-
'name',
|
|
68
|
-
defaultValue: 'there',
|
|
69
|
-
),
|
|
96
|
+
'greeting': await HomeWidget.getWidgetData<String>('greeting'),
|
|
97
|
+
'title': await HomeWidget.getWidgetData<String>('title'),
|
|
98
|
+
'planText': await HomeWidget.getWidgetData<String>('planText'),
|
|
70
99
|
'isPro': await HomeWidget.getWidgetData<String>(
|
|
71
100
|
'isPro',
|
|
72
101
|
defaultValue: 'false',
|
|
@@ -74,25 +103,12 @@ class MyWidgetHomeWidget extends _$MyWidgetHomeWidget
|
|
|
74
103
|
};
|
|
75
104
|
}
|
|
76
105
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
static String _greeting() {
|
|
81
|
-
final lang = Platform.localeName.split(RegExp(r'[_\-]')).first.toLowerCase();
|
|
106
|
+
/// Time-of-day greeting in the app language (matches what the user sees
|
|
107
|
+
/// inside the app, not the device language).
|
|
108
|
+
static String _greeting(Translations t) {
|
|
82
109
|
final hour = DateTime.now().hour;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
'es' => hour < 12
|
|
87
|
-
? 'Buenos días'
|
|
88
|
-
: hour < 18
|
|
89
|
-
? 'Buenas tardes'
|
|
90
|
-
: 'Buenas noches',
|
|
91
|
-
_ => hour < 12
|
|
92
|
-
? 'Good morning'
|
|
93
|
-
: hour < 18
|
|
94
|
-
? 'Good afternoon'
|
|
95
|
-
: 'Good evening',
|
|
96
|
-
};
|
|
110
|
+
if (hour < 12) return t.home_widget.greeting_morning;
|
|
111
|
+
if (hour < 18) return t.home_widget.greeting_afternoon;
|
|
112
|
+
return t.home_widget.greeting_evening;
|
|
97
113
|
}
|
|
98
114
|
}
|
|
@@ -516,6 +516,15 @@
|
|
|
516
516
|
"message_android_mixed": "A quick check when you open—you stay signed in.",
|
|
517
517
|
"not_now": "Not now",
|
|
518
518
|
"enable": "Turn on"
|
|
519
|
+
},
|
|
520
|
+
"home_widget": {
|
|
521
|
+
"greeting_morning": "Good morning",
|
|
522
|
+
"greeting_afternoon": "Good afternoon",
|
|
523
|
+
"greeting_evening": "Good evening",
|
|
524
|
+
"title_with_name": "Hi, $name!",
|
|
525
|
+
"title_default": "Hi there!",
|
|
526
|
+
"plan_free": "Free plan",
|
|
527
|
+
"plan_pro": "PRO"
|
|
519
528
|
}
|
|
520
529
|
}
|
|
521
530
|
|
|
@@ -516,6 +516,15 @@
|
|
|
516
516
|
"message_android_mixed": "Una confirmación rápida al abrir—sigues con la sesión.",
|
|
517
517
|
"not_now": "Ahora no",
|
|
518
518
|
"enable": "Activar"
|
|
519
|
+
},
|
|
520
|
+
"home_widget": {
|
|
521
|
+
"greeting_morning": "Buenos días",
|
|
522
|
+
"greeting_afternoon": "Buenas tardes",
|
|
523
|
+
"greeting_evening": "Buenas noches",
|
|
524
|
+
"title_with_name": "¡Hola, $name!",
|
|
525
|
+
"title_default": "¡Hola!",
|
|
526
|
+
"plan_free": "Plan gratuito",
|
|
527
|
+
"plan_pro": "PRO"
|
|
519
528
|
}
|
|
520
529
|
}
|
|
521
530
|
|
|
@@ -516,6 +516,15 @@
|
|
|
516
516
|
"message_android_mixed": "Confirmação rápida ao abrir — continua na conta.",
|
|
517
517
|
"not_now": "Agora não",
|
|
518
518
|
"enable": "Ativar"
|
|
519
|
+
},
|
|
520
|
+
"home_widget": {
|
|
521
|
+
"greeting_morning": "Bom dia",
|
|
522
|
+
"greeting_afternoon": "Boa tarde",
|
|
523
|
+
"greeting_evening": "Boa noite",
|
|
524
|
+
"title_with_name": "Olá, $name!",
|
|
525
|
+
"title_default": "Olá!",
|
|
526
|
+
"plan_free": "Plano grátis",
|
|
527
|
+
"plan_pro": "PRO"
|
|
519
528
|
}
|
|
520
529
|
}
|
|
521
530
|
|