@agentprojectcontext/apx 1.80.2 → 1.89.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/package.json +9 -8
- package/skills/apc-context/SKILL.md +14 -7
- package/skills/apx/SKILL.md +62 -2
- package/skills/apx-mcp/SKILL.md +42 -15
- package/src/core/agent/a2a/peers.js +161 -0
- package/src/core/agent/a2a/reply.js +379 -27
- package/src/core/agent/abort.js +25 -0
- package/src/core/agent/agent-model.js +58 -0
- package/src/core/agent/agent-tools.js +101 -0
- package/src/core/agent/author-line.js +110 -0
- package/src/core/agent/build-agent-system.js +52 -18
- package/src/core/agent/channels/voice-context.js +17 -2
- package/src/core/agent/closing-floor.js +117 -0
- package/src/core/agent/constants.js +119 -11
- package/src/core/agent/engine-call.js +56 -0
- package/src/core/agent/group/run-group-turn.js +218 -0
- package/src/core/agent/group/turn-resolver.js +165 -0
- package/src/core/agent/judge.js +138 -11
- package/src/core/agent/loop/side-effects.js +106 -3
- package/src/core/agent/memory.js +31 -18
- package/src/core/agent/model-capabilities.js +47 -0
- package/src/core/agent/model-router.js +11 -40
- package/src/core/agent/prompt-builder.js +47 -0
- package/src/core/agent/prompts/channels/a2a.md +12 -0
- package/src/core/agent/prompts/channels/code.md +3 -1
- package/src/core/agent/prompts/channels/telegram.md +2 -0
- package/src/core/agent/prompts/channels/web_code.md +1 -1
- package/src/core/agent/prompts/channels/whatsapp.md +37 -0
- package/src/core/agent/prompts/core/agent-base.md +2 -0
- package/src/core/agent/prompts/discipline/action.md +1 -0
- package/src/core/agent/prompts/discipline/two-segment.md +2 -1
- package/src/core/agent/prompts/modes/mobility.md +36 -0
- package/src/core/agent/retry.js +42 -0
- package/src/core/agent/run-agent.js +322 -25
- package/src/core/agent/run-turn.js +253 -0
- package/src/core/agent/self-memory.js +18 -52
- package/src/core/agent/skills/agent-skills.js +118 -0
- package/src/core/agent/skills/catalog.js +1 -1
- package/src/core/agent/skills/declared.js +13 -0
- package/src/core/agent/skills/index-store.js +8 -1
- package/src/core/agent/skills/inspector.js +20 -3
- package/src/core/agent/skills/loader.js +18 -3
- package/src/core/agent/skills/media.js +121 -0
- package/src/core/agent/skills/origin.js +61 -0
- package/src/core/agent/skills/sections.js +136 -0
- package/src/core/agent/super-agent.js +54 -14
- package/src/core/agent/tools/handlers/_calendar.js +50 -0
- package/src/core/agent/tools/handlers/add-mcp.js +103 -0
- package/src/core/agent/tools/handlers/asana-create-task.js +3 -1
- package/src/core/agent/tools/handlers/attach-media.js +56 -0
- package/src/core/agent/tools/handlers/calendar-create-event.js +38 -0
- package/src/core/agent/tools/handlers/calendar-find-slot.js +39 -0
- package/src/core/agent/tools/handlers/calendar-list-events.js +39 -0
- package/src/core/agent/tools/handlers/calendar-update-event.js +35 -0
- package/src/core/agent/tools/handlers/call-agent.js +14 -6
- package/src/core/agent/tools/handlers/call-runtime.js +27 -49
- package/src/core/agent/tools/handlers/comment-task.js +78 -0
- package/src/core/agent/tools/handlers/complete-task.js +60 -0
- package/src/core/agent/tools/handlers/configure-agent.js +70 -0
- package/src/core/agent/tools/handlers/create-agent.js +68 -0
- package/src/core/agent/tools/handlers/create-task.js +41 -3
- package/src/core/agent/tools/handlers/import-agent.js +5 -5
- package/src/core/agent/tools/handlers/list-mcp-tools.js +83 -0
- package/src/core/agent/tools/handlers/list-routines.js +46 -0
- package/src/core/agent/tools/handlers/list-tasks.js +8 -1
- package/src/core/agent/tools/handlers/mark-commitment.js +57 -0
- package/src/core/agent/tools/handlers/read-skill.js +64 -0
- package/src/core/agent/tools/handlers/remember-routine.js +2 -8
- package/src/core/agent/tools/handlers/remember.js +82 -6
- package/src/core/agent/tools/handlers/remove-agent.js +42 -0
- package/src/core/agent/tools/handlers/run-routine.js +94 -0
- package/src/core/agent/tools/handlers/run-shell.js +44 -2
- package/src/core/agent/tools/handlers/send-telegram.js +41 -19
- package/src/core/agent/tools/handlers/set-agent-prompt.js +44 -0
- package/src/core/agent/tools/handlers/view-media.js +69 -0
- package/src/core/agent/tools/handlers/write-agent-memory.js +52 -0
- package/src/core/agent/tools/helpers.js +36 -4
- package/src/core/agent/tools/names.js +64 -0
- package/src/core/agent/tools/registry-bridge.js +24 -1
- package/src/core/agent/tools/registry.js +79 -0
- package/src/core/agent/tools/tool-call-parser.js +136 -13
- package/src/core/agent/vision-bridge.js +69 -0
- package/src/core/apc/agent-identity.js +74 -0
- package/src/core/apc/agent-rename-refs.js +187 -0
- package/src/core/apc/agent-write.js +312 -0
- package/src/core/apc/agents-vault.js +1 -1
- package/src/core/apc/blob-keys.js +42 -0
- package/src/core/apc/frontmatter.js +166 -10
- package/src/core/apc/parser.js +33 -83
- package/src/core/apc/paths.js +4 -6
- package/src/core/apc/project-memory.js +44 -0
- package/src/core/apc/projects-helpers.js +33 -0
- package/src/core/apc/scaffold.js +36 -16
- package/src/core/channels/telegram/ask-callbacks.js +103 -0
- package/src/core/channels/telegram/dispatch.js +154 -30
- package/src/core/channels/telegram/helpers.js +59 -7
- package/src/core/channels/telegram/inbound/audio.js +26 -30
- package/src/core/channels/telegram/inbound/file.js +22 -32
- package/src/core/channels/telegram/inbound/photo.js +24 -28
- package/src/core/channels/telegram/progress-gate.js +76 -0
- package/src/core/channels/telegram/reply.js +151 -43
- package/src/core/channels/telegram/voice-note.js +150 -0
- package/src/core/config/index.js +53 -54
- package/src/core/config/paths.js +117 -31
- package/src/core/config/redact.js +89 -4
- package/src/core/config/secret-values.js +2 -4
- package/src/core/constants/actors.js +5 -0
- package/src/core/constants/channels.js +3 -1
- package/src/core/constants/task-categories.js +73 -0
- package/src/core/constants/task-fields.js +28 -0
- package/src/core/engines/_globs.js +33 -0
- package/src/core/engines/anthropic.js +19 -1
- package/src/core/engines/catalog.js +20 -0
- package/src/core/engines/gemini.js +84 -16
- package/src/core/engines/index.js +19 -3
- package/src/core/engines/mock.js +145 -1
- package/src/core/engines/openai-compatible.js +150 -15
- package/src/core/engines/presets.js +36 -9
- package/src/core/engines/zen.js +131 -0
- package/src/core/events/bus.js +140 -0
- package/src/core/events/mascot-notify.js +156 -0
- package/src/core/http-tools/browser.js +366 -36
- package/src/core/http-tools/catalog.js +206 -22
- package/src/core/http-tools/grep.js +62 -7
- package/src/core/http-tools/registry.js +3 -1
- package/src/core/i18n/en.js +34 -3
- package/src/core/i18n/es.js +36 -4
- package/src/core/i18n/index.js +5 -5
- package/src/core/i18n/pt.js +32 -3
- package/src/core/identity/self.js +14 -1
- package/src/core/images/engines/a1111.js +219 -0
- package/src/core/images/engines/index.js +187 -0
- package/src/core/images/engines/mock.js +74 -0
- package/src/core/images/engines/openai.js +130 -0
- package/src/core/images/engines/sdcpp.js +204 -0
- package/src/core/images/engines/shared.js +218 -0
- package/src/core/images/generate.js +260 -0
- package/src/core/integrations/catalog.js +8 -3
- package/src/core/integrations/plugins/_google-oauth.js +179 -0
- package/src/core/integrations/plugins/asana.js +7 -3
- package/src/core/integrations/plugins/calendar.js +404 -0
- package/src/core/integrations/store.js +2 -0
- package/src/core/memory/broker.js +16 -1
- package/src/core/memory/compactor.js +19 -3
- package/src/core/memory/consolidate.js +2 -2
- package/src/core/memory/dated-log.js +66 -0
- package/src/core/memory/embed-engines/custom.js +59 -0
- package/src/core/memory/embed-engines/gemini.js +9 -3
- package/src/core/memory/embed-engines/index.js +87 -15
- package/src/core/memory/embeddings.js +52 -24
- package/src/core/memory/index.js +13 -3
- package/src/core/memory/indexer.js +83 -27
- package/src/core/memory/prune.js +182 -0
- package/src/core/memory/store.js +22 -0
- package/src/core/memory/summarizer.js +72 -8
- package/src/core/mobility/answer.js +80 -0
- package/src/core/mobility/geofence.js +667 -0
- package/src/core/mobility/osm-route.js +282 -0
- package/src/core/mobility/preferences.js +91 -0
- package/src/core/mobility/state.js +245 -0
- package/src/core/mobility/trip-event.js +384 -0
- package/src/core/net/tailscale.js +168 -0
- package/src/core/profiles/bundled/secretary/PROFILE.md +32 -42
- package/src/core/profiles/bundled/secretary/config.schema.es.json +68 -0
- package/src/core/profiles/bundled/secretary/config.schema.json +30 -2
- package/src/core/profiles/bundled/secretary/profile.json +3 -1
- package/src/core/profiles/bundled/secretary/routines/a2a-sweep.json +20 -0
- package/src/core/profiles/bundled/secretary/routines/day-close.json +4 -1
- package/src/core/profiles/bundled/secretary/routines/day-open.json +7 -1
- package/src/core/profiles/bundled/secretary/routines/watch.json +13 -2
- package/src/core/profiles/lifecycle.js +243 -19
- package/src/core/profiles/paths.js +12 -0
- package/src/core/profiles/store.js +47 -0
- package/src/core/routines/active-runs.js +213 -0
- package/src/core/routines/delivery.js +612 -0
- package/src/core/routines/header.js +88 -0
- package/src/core/routines/index.js +26 -0
- package/src/core/routines/run-log.js +78 -0
- package/src/core/routines/runner.js +629 -66
- package/src/core/routines/signals.js +75 -0
- package/src/core/runtime-skills/apc-context/SKILL.md +14 -7
- package/src/core/runtime-skills/apx/SKILL.md +93 -1
- package/src/core/runtime-skills/apx-agency-agents/SKILL.md +2 -2
- package/src/core/runtime-skills/apx-agent/SKILL.md +134 -19
- package/src/core/runtime-skills/apx-commitment/SKILL.md +134 -0
- package/src/core/runtime-skills/apx-image/SKILL.md +60 -0
- package/src/core/runtime-skills/apx-integrations/SKILL.md +82 -0
- package/src/core/runtime-skills/apx-mcp/SKILL.md +45 -14
- package/src/core/runtime-skills/apx-mcp-builder/SKILL.md +4 -4
- package/src/core/runtime-skills/apx-profile/SKILL.md +27 -2
- package/src/core/runtime-skills/apx-project/SKILL.md +23 -2
- package/src/core/runtime-skills/apx-routine/SKILL.md +40 -17
- package/src/core/runtime-skills/apx-runtime/SKILL.md +124 -14
- package/src/core/runtime-skills/apx-sessions/SKILL.md +7 -6
- package/src/core/runtime-skills/apx-skill-builder/SKILL.md +15 -13
- package/src/core/runtime-skills/apx-task/SKILL.md +79 -26
- package/src/core/runtime-skills/apx-telegram/SKILL.md +12 -12
- package/src/core/runtime-skills/apx-transcribe/SKILL.md +56 -0
- package/src/core/runtime-skills/apx-voice/SKILL.md +27 -8
- package/src/core/runtime-skills/claude-code/SKILL.md +8 -0
- package/src/core/runtime-skills/openrouter/SKILL.md +8 -2
- package/src/core/runtimes/_spawn.js +9 -1
- package/src/core/runtimes/claude-code.js +11 -2
- package/src/core/runtimes/codex.js +44 -10
- package/src/core/runtimes/index.js +17 -2
- package/src/core/runtimes/opencode.js +88 -9
- package/src/core/runtimes/outcome.js +119 -0
- package/src/core/sessions/index.js +193 -1
- package/src/core/stores/agent-inbox.js +109 -23
- package/src/core/stores/code-sessions.js +21 -0
- package/src/core/stores/commitments.js +27 -3
- package/src/core/stores/conversations.js +220 -20
- package/src/core/stores/deliveries.js +177 -0
- package/src/core/stores/media-archive.js +228 -0
- package/src/core/stores/messages.js +1096 -112
- package/src/core/stores/organization.js +34 -0
- package/src/core/stores/project-memory.js +71 -0
- package/src/core/stores/routine-memory.js +16 -8
- package/src/core/stores/routines.js +27 -49
- package/src/core/stores/sessions.js +4 -8
- package/src/core/stores/tasks.js +212 -18
- package/src/core/stores/turn-record.js +209 -0
- package/src/core/tasks/columns.js +136 -0
- package/src/core/tasks/comment-turn.js +258 -0
- package/src/core/util/time.js +13 -0
- package/src/core/voice/engines/index.js +54 -1
- package/src/core/voice/engines/openai.js +50 -4
- package/src/core/voice/opus.js +67 -0
- package/src/core/voice/pronounceable.js +43 -0
- package/src/core/voice/transcription.js +4 -0
- package/src/core/voice/tts.js +114 -24
- package/src/host/daemon/active-turns.js +188 -0
- package/src/host/daemon/api/admin-config.js +9 -0
- package/src/host/daemon/api/agents.js +99 -90
- package/src/host/daemon/api/artifact-preview.js +7 -6
- package/src/host/daemon/api/artifacts.js +3 -2
- package/src/host/daemon/api/code.js +55 -9
- package/src/host/daemon/api/commitments.js +11 -0
- package/src/host/daemon/api/confirm.js +3 -2
- package/src/host/daemon/api/conversations.js +543 -35
- package/src/host/daemon/api/deck.js +9 -8
- package/src/host/daemon/api/deliveries.js +33 -0
- package/src/host/daemon/api/desktop.js +5 -4
- package/src/host/daemon/api/embeddings.js +15 -6
- package/src/host/daemon/api/engines.js +59 -8
- package/src/host/daemon/api/exec.js +437 -121
- package/src/host/daemon/api/groups.js +215 -0
- package/src/host/daemon/api/images.js +107 -0
- package/src/host/daemon/api/inbox.js +123 -2
- package/src/host/daemon/api/integrations.js +64 -2
- package/src/host/daemon/api/mcps.js +7 -6
- package/src/host/daemon/api/media.js +283 -0
- package/src/host/daemon/api/mobility.js +177 -0
- package/src/host/daemon/api/net.js +182 -0
- package/src/host/daemon/api/pairing.js +38 -5
- package/src/host/daemon/api/profiles.js +30 -2
- package/src/host/daemon/api/routines.js +36 -4
- package/src/host/daemon/api/runtimes.js +74 -39
- package/src/host/daemon/api/sessions-search.js +7 -2
- package/src/host/daemon/api/sessions.js +44 -2
- package/src/host/daemon/api/shared.js +127 -20
- package/src/host/daemon/api/skills.js +11 -4
- package/src/host/daemon/api/super-agent.js +384 -53
- package/src/host/daemon/api/tasks.js +180 -10
- package/src/host/daemon/api/telegram.js +11 -10
- package/src/host/daemon/api/thread-faces.js +159 -0
- package/src/host/daemon/api/top-level.js +3 -3
- package/src/host/daemon/api/transcribe.js +11 -10
- package/src/host/daemon/api/tts.js +97 -4
- package/src/host/daemon/api/turn-abort.js +23 -0
- package/src/host/daemon/api/turns.js +49 -0
- package/src/host/daemon/api/voice.js +5 -4
- package/src/host/daemon/api/web.js +98 -0
- package/src/host/daemon/api.js +39 -0
- package/src/host/daemon/delivery-sweep.js +58 -0
- package/src/host/daemon/desktop-ws.js +5 -23
- package/src/host/daemon/events-ws.js +273 -0
- package/src/host/daemon/index.js +59 -15
- package/src/host/daemon/plugins/desktop/index.js +17 -4
- package/src/host/daemon/plugins/telegram/index.js +78 -40
- package/src/host/daemon/pty-bridge.py +99 -0
- package/src/host/daemon/routines-scheduler.js +1 -0
- package/src/host/daemon/smoke.js +1 -2
- package/src/host/daemon/terminal-ws.js +132 -0
- package/src/host/daemon/tts-keepwarm.js +87 -0
- package/src/host/daemon/wakeup.js +11 -6
- package/src/host/daemon/whisper-server.js +44 -0
- package/src/host/daemon/whisper-server.py +70 -13
- package/src/host/daemon/ws-auth.js +28 -0
- package/src/interfaces/android/app/build.gradle +42 -0
- package/src/interfaces/android/app/proguard-rules.pro +4 -0
- package/src/interfaces/android/app/src/main/AndroidManifest.xml +139 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/AlertScreen.java +139 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/AndroidAutoDetector.java +106 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ApxCarAppService.java +57 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ApxPreferences.java +165 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarAlertStore.java +84 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarMessageActionReceiver.java +47 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarMessageNotification.java +152 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DaemonAddress.java +35 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DaemonClient.java +339 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DeviceLocation.java +38 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ErrandScreen.java +127 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MainActivity.java +872 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsNavigationDetector.java +63 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsNavigationListenerService.java +453 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsShareIntentParser.java +93 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotBlobCatalog.java +66 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotOverlayService.java +448 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotView.java +249 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MessageFrameParser.java +240 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/NotifyChannels.java +69 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ProximityActionReceiver.java +78 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ProximityNotification.java +161 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/StartupReceiver.java +57 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TravelEventGate.java +62 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TravelStatusBanner.java +116 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripLocationService.java +272 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripPlacesSheet.java +203 -0
- package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripScreen.java +182 -0
- package/src/interfaces/android/app/src/main/res/drawable/app_background.xml +12 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_apx_app.xml +10 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_apx_launcher_foreground.xml +12 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_apx_notification.xml +22 -0
- package/src/interfaces/android/app/src/main/res/drawable/ic_trip_car.xml +37 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/apx_logo.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_amatista.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_aqua.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_brasa.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_campana.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_caracol.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_carbon.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cobalto.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cometa.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_coral.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cubi.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_eclipse.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_faro.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_gajo.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_iris.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_kiwi.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_laguna.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_lila.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_menta.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_nimbo.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_noche.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_onyx.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_orbita.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_ovni.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_papa.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_parche.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_peon.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_perla.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_pino.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_quad.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_rubi.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_saturno.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_trebol.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_trino.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_volcan.png +0 -0
- package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_zafiro.png +0 -0
- package/src/interfaces/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
- package/src/interfaces/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
- package/src/interfaces/android/app/src/main/res/raw/apx_notification.mp3 +0 -0
- package/src/interfaces/android/app/src/main/res/values/colors.xml +4 -0
- package/src/interfaces/android/app/src/main/res/values/strings.xml +25 -0
- package/src/interfaces/android/app/src/main/res/values/styles.xml +10 -0
- package/src/interfaces/android/app/src/main/res/values-v31/styles.xml +14 -0
- package/src/interfaces/android/app/src/main/res/xml/automotive_app_desc.xml +9 -0
- package/src/interfaces/android/app/src/main/res/xml/network_security_config.xml +10 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/AndroidAutoDetectorTest.java +85 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/CarAlertStoreTest.java +104 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/DaemonAddressTest.java +23 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MapsNavigationDetectorTest.java +69 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MapsShareIntentParserTest.java +31 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MessageFrameParserTest.java +180 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/TravelEventGateTest.java +64 -0
- package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/TripPlacesSheetTest.java +66 -0
- package/src/interfaces/android/build.gradle +3 -0
- package/src/interfaces/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/src/interfaces/android/gradle/wrapper/gradle-wrapper.properties +9 -0
- package/src/interfaces/android/gradle.properties +3 -0
- package/src/interfaces/android/gradlew +248 -0
- package/src/interfaces/android/gradlew.bat +82 -0
- package/src/interfaces/android/settings.gradle +18 -0
- package/src/interfaces/cli/commands/a2a.js +145 -4
- package/src/interfaces/cli/commands/agent.js +247 -22
- package/src/interfaces/cli/commands/code.js +1 -1
- package/src/interfaces/cli/commands/commitment.js +5 -0
- package/src/interfaces/cli/commands/config.js +85 -6
- package/src/interfaces/cli/commands/exec.js +90 -1
- package/src/interfaces/cli/commands/image.js +314 -0
- package/src/interfaces/cli/commands/mcp.js +87 -23
- package/src/interfaces/cli/commands/memory.js +35 -22
- package/src/interfaces/cli/commands/panel.js +94 -0
- package/src/interfaces/cli/commands/profile.js +14 -0
- package/src/interfaces/cli/commands/project.js +29 -0
- package/src/interfaces/cli/commands/routine.js +45 -10
- package/src/interfaces/cli/commands/runtime.js +30 -7
- package/src/interfaces/cli/commands/session.js +90 -38
- package/src/interfaces/cli/commands/sessions.js +35 -2
- package/src/interfaces/cli/commands/skills.js +15 -9
- package/src/interfaces/cli/commands/status.js +2 -3
- package/src/interfaces/cli/commands/task.js +54 -5
- package/src/interfaces/cli/commands/telegram.js +12 -4
- package/src/interfaces/cli/commands/transcribe.js +177 -0
- package/src/interfaces/cli/help/index.js +311 -72
- package/src/interfaces/cli/http.js +61 -13
- package/src/interfaces/cli/index.js +1 -1
- package/src/interfaces/cli/routes/agent.js +5 -4
- package/src/interfaces/cli/routes/commitment.js +3 -2
- package/src/interfaces/cli/routes/config.js +7 -2
- package/src/interfaces/cli/routes/image.js +11 -0
- package/src/interfaces/cli/routes/index.js +2 -0
- package/src/interfaces/cli/routes/log.js +1 -1
- package/src/interfaces/cli/routes/memory.js +3 -2
- package/src/interfaces/cli/routes/panel.js +15 -2
- package/src/interfaces/cli/routes/profile.js +3 -2
- package/src/interfaces/cli/routes/transcribe.js +10 -0
- package/src/interfaces/cli/stdin.js +29 -0
- package/src/interfaces/desktop/assets/blobs/amatista.png +0 -0
- package/src/interfaces/desktop/assets/blobs/aqua.png +0 -0
- package/src/interfaces/desktop/assets/blobs/brasa.png +0 -0
- package/src/interfaces/desktop/assets/blobs/campana.png +0 -0
- package/src/interfaces/desktop/assets/blobs/caracol.png +0 -0
- package/src/interfaces/desktop/assets/blobs/carbon.png +0 -0
- package/src/interfaces/desktop/assets/blobs/cobalto.png +0 -0
- package/src/interfaces/desktop/assets/blobs/cometa.png +0 -0
- package/src/interfaces/desktop/assets/blobs/coral.png +0 -0
- package/src/interfaces/desktop/assets/blobs/cubi.png +0 -0
- package/src/interfaces/desktop/assets/blobs/eclipse.png +0 -0
- package/src/interfaces/desktop/assets/blobs/faro.png +0 -0
- package/src/interfaces/desktop/assets/blobs/gajo.png +0 -0
- package/src/interfaces/desktop/assets/blobs/iris.png +0 -0
- package/src/interfaces/desktop/assets/blobs/kiwi.png +0 -0
- package/src/interfaces/desktop/assets/blobs/laguna.png +0 -0
- package/src/interfaces/desktop/assets/blobs/lila.png +0 -0
- package/src/interfaces/desktop/assets/blobs/menta.png +0 -0
- package/src/interfaces/desktop/assets/blobs/nimbo.png +0 -0
- package/src/interfaces/desktop/assets/blobs/noche.png +0 -0
- package/src/interfaces/desktop/assets/blobs/onyx.png +0 -0
- package/src/interfaces/desktop/assets/blobs/orbita.png +0 -0
- package/src/interfaces/desktop/assets/blobs/ovni.png +0 -0
- package/src/interfaces/desktop/assets/blobs/papa.png +0 -0
- package/src/interfaces/desktop/assets/blobs/parche.png +0 -0
- package/src/interfaces/desktop/assets/blobs/peon.png +0 -0
- package/src/interfaces/desktop/assets/blobs/perla.png +0 -0
- package/src/interfaces/desktop/assets/blobs/pino.png +0 -0
- package/src/interfaces/desktop/assets/blobs/quad.png +0 -0
- package/src/interfaces/desktop/assets/blobs/rubi.png +0 -0
- package/src/interfaces/desktop/assets/blobs/saturno.png +0 -0
- package/src/interfaces/desktop/assets/blobs/trebol.png +0 -0
- package/src/interfaces/desktop/assets/blobs/trino.png +0 -0
- package/src/interfaces/desktop/assets/blobs/volcan.png +0 -0
- package/src/interfaces/desktop/assets/blobs/zafiro.png +0 -0
- package/src/interfaces/desktop/assets/notification.mp3 +0 -0
- package/src/interfaces/desktop/main.js +473 -29
- package/src/interfaces/desktop/mascot-blobs.js +41 -0
- package/src/interfaces/desktop/mascot-preload.js +32 -0
- package/src/interfaces/desktop/mascot.css +186 -0
- package/src/interfaces/desktop/mascot.html +40 -0
- package/src/interfaces/desktop/mascot.js +163 -0
- package/src/interfaces/desktop/preload.js +10 -0
- package/src/interfaces/desktop/renderer.js +308 -48
- package/src/interfaces/desktop/style.css +34 -0
- package/src/interfaces/mcp-server/index.js +87 -0
- package/src/interfaces/tui/_shims/util-locale.ts +0 -2
- package/src/interfaces/tui/app.tsx +0 -6
- package/src/interfaces/tui/attach.ts +0 -1
- package/src/interfaces/tui/context/sdk-apx.tsx +0 -4
- package/src/interfaces/tui/plugin/api.tsx +0 -3
- package/src/interfaces/tui/plugin/runtime.ts +0 -3
- package/src/interfaces/tui/thread.ts +0 -16
- package/src/interfaces/web/README.md +22 -14
- package/src/interfaces/web/dist/assets/claude-XtpLmGtF.webp +0 -0
- package/src/interfaces/web/dist/assets/codex-DExPUgvh.webp +0 -0
- package/src/interfaces/web/dist/assets/index-BEoRgIqd.css +32 -0
- package/src/interfaces/web/dist/assets/index-BEoRgIqd.css.br +0 -0
- package/src/interfaces/web/dist/assets/index-BEoRgIqd.css.gz +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js +1074 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.br +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.gz +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map +1 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map.br +0 -0
- package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map.gz +0 -0
- package/src/interfaces/web/dist/favicon/dark/site.webmanifest +12 -6
- package/src/interfaces/web/dist/favicon/white/site.webmanifest +12 -6
- package/src/interfaces/web/dist/index.html +22 -6
- package/src/interfaces/web/dist/index.html.br +0 -0
- package/src/interfaces/web/dist/index.html.gz +0 -0
- package/src/interfaces/web/dist/manifest.webmanifest +25 -0
- package/src/interfaces/web/dist/modules/blobs/amatista.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/aqua.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/brasa.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/campana.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/caracol.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/carbon.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/cobalto.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/cometa.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/coral.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/cubi.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/eclipse.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/faro.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/gajo.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/iris.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/kiwi.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/laguna.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/lila.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/menta.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/nimbo.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/noche.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/onyx.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/orbita.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/ovni.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/papa.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/parche.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/peon.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/perla.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/pino.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/quad.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/rubi.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/saturno.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/trebol.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/trino.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/volcan.png +0 -0
- package/src/interfaces/web/dist/modules/blobs/zafiro.png +0 -0
- package/src/interfaces/web/dist/sw.js +106 -0
- package/src/interfaces/web/dist/sw.js.br +0 -0
- package/src/interfaces/web/dist/sw.js.gz +0 -0
- package/src/interfaces/web/eslint.config.js +83 -0
- package/src/interfaces/web/index.html +20 -4
- package/src/interfaces/web/package-lock.json +1651 -1280
- package/src/interfaces/web/package.json +9 -10
- package/src/interfaces/web/pnpm-lock.yaml +867 -869
- package/src/interfaces/web/public/favicon/dark/site.webmanifest +12 -6
- package/src/interfaces/web/public/favicon/white/site.webmanifest +12 -6
- package/src/interfaces/web/public/manifest.webmanifest +25 -0
- package/src/interfaces/web/public/modules/blobs/amatista.png +0 -0
- package/src/interfaces/web/public/modules/blobs/aqua.png +0 -0
- package/src/interfaces/web/public/modules/blobs/brasa.png +0 -0
- package/src/interfaces/web/public/modules/blobs/campana.png +0 -0
- package/src/interfaces/web/public/modules/blobs/caracol.png +0 -0
- package/src/interfaces/web/public/modules/blobs/carbon.png +0 -0
- package/src/interfaces/web/public/modules/blobs/cobalto.png +0 -0
- package/src/interfaces/web/public/modules/blobs/cometa.png +0 -0
- package/src/interfaces/web/public/modules/blobs/coral.png +0 -0
- package/src/interfaces/web/public/modules/blobs/cubi.png +0 -0
- package/src/interfaces/web/public/modules/blobs/eclipse.png +0 -0
- package/src/interfaces/web/public/modules/blobs/faro.png +0 -0
- package/src/interfaces/web/public/modules/blobs/gajo.png +0 -0
- package/src/interfaces/web/public/modules/blobs/iris.png +0 -0
- package/src/interfaces/web/public/modules/blobs/kiwi.png +0 -0
- package/src/interfaces/web/public/modules/blobs/laguna.png +0 -0
- package/src/interfaces/web/public/modules/blobs/lila.png +0 -0
- package/src/interfaces/web/public/modules/blobs/menta.png +0 -0
- package/src/interfaces/web/public/modules/blobs/nimbo.png +0 -0
- package/src/interfaces/web/public/modules/blobs/noche.png +0 -0
- package/src/interfaces/web/public/modules/blobs/onyx.png +0 -0
- package/src/interfaces/web/public/modules/blobs/orbita.png +0 -0
- package/src/interfaces/web/public/modules/blobs/ovni.png +0 -0
- package/src/interfaces/web/public/modules/blobs/papa.png +0 -0
- package/src/interfaces/web/public/modules/blobs/parche.png +0 -0
- package/src/interfaces/web/public/modules/blobs/peon.png +0 -0
- package/src/interfaces/web/public/modules/blobs/perla.png +0 -0
- package/src/interfaces/web/public/modules/blobs/pino.png +0 -0
- package/src/interfaces/web/public/modules/blobs/quad.png +0 -0
- package/src/interfaces/web/public/modules/blobs/rubi.png +0 -0
- package/src/interfaces/web/public/modules/blobs/saturno.png +0 -0
- package/src/interfaces/web/public/modules/blobs/trebol.png +0 -0
- package/src/interfaces/web/public/modules/blobs/trino.png +0 -0
- package/src/interfaces/web/public/modules/blobs/volcan.png +0 -0
- package/src/interfaces/web/public/modules/blobs/zafiro.png +0 -0
- package/src/interfaces/web/public/sw.js +106 -0
- package/src/interfaces/web/src/App.tsx +106 -10
- package/src/interfaces/web/src/assets/cli/claude.webp +0 -0
- package/src/interfaces/web/src/assets/cli/codex.webp +0 -0
- package/src/interfaces/web/src/assets/cli/cursor.svg +1 -0
- package/src/interfaces/web/src/assets/cli/opencode.png +0 -0
- package/src/interfaces/web/src/components/Combobox.tsx +201 -0
- package/src/interfaces/web/src/components/MobileHint.tsx +95 -0
- package/src/interfaces/web/src/components/MobileLinkDialog.tsx +156 -0
- package/src/interfaces/web/src/components/ModelCombobox.tsx +21 -113
- package/src/interfaces/web/src/components/{routines/ReadOnlyBlock.tsx → ReadOnlyBlock.tsx} +13 -4
- package/src/interfaces/web/src/components/Roby.tsx +5 -3
- package/src/interfaces/web/src/components/RobyBubble.tsx +23 -5
- package/src/interfaces/web/src/components/RowMenu.tsx +46 -0
- package/src/interfaces/web/src/components/TimezoneSelect.tsx +4 -1
- package/src/interfaces/web/src/components/Toast.tsx +50 -14
- package/src/interfaces/web/src/components/UiSelect.tsx +12 -5
- package/src/interfaces/web/src/components/agents/AgentAvatar.tsx +171 -0
- package/src/interfaces/web/src/components/agents/AgentFormFields.tsx +42 -11
- package/src/interfaces/web/src/components/agents/AgentModelBadge.tsx +157 -0
- package/src/interfaces/web/src/components/agents/AgentModelSelect.tsx +57 -0
- package/src/interfaces/web/src/components/agents/AgentSkillsPicker.tsx +115 -0
- package/src/interfaces/web/src/components/agents/BlobAvatar.tsx +50 -0
- package/src/interfaces/web/src/components/agents/blobPresets.ts +50 -0
- package/src/interfaces/web/src/components/agents/modelCatalog.ts +66 -0
- package/src/interfaces/web/src/components/chat/ActionGroup.tsx +162 -0
- package/src/interfaces/web/src/components/chat/AskAnswersCard.tsx +4 -3
- package/src/interfaces/web/src/components/chat/AskQuestionsCard.tsx +1 -1
- package/src/interfaces/web/src/components/chat/Attachment.tsx +220 -0
- package/src/interfaces/web/src/components/chat/ChatList.tsx +226 -51
- package/src/interfaces/web/src/components/chat/ChatRowActivity.tsx +45 -0
- package/src/interfaces/web/src/components/chat/Composer.tsx +672 -23
- package/src/interfaces/web/src/components/chat/ComposerCommands.tsx +175 -0
- package/src/interfaces/web/src/components/chat/ComposerSuggest.tsx +215 -0
- package/src/interfaces/web/src/components/chat/ContextBar.tsx +133 -65
- package/src/interfaces/web/src/components/chat/InlineAskPanel.tsx +107 -47
- package/src/interfaces/web/src/components/chat/MessageBubble.tsx +460 -119
- package/src/interfaces/web/src/components/chat/MessageList.tsx +165 -18
- package/src/interfaces/web/src/components/chat/ReasoningBlock.tsx +58 -0
- package/src/interfaces/web/src/components/chat/SessionPicker.tsx +182 -0
- package/src/interfaces/web/src/components/chat/SkillTrace.tsx +183 -0
- package/src/interfaces/web/src/components/chat/ToolCall.tsx +11 -11
- package/src/interfaces/web/src/components/code/CodeContextTab.tsx +87 -53
- package/src/interfaces/web/src/components/code/CodeFileTree.tsx +11 -52
- package/src/interfaces/web/src/components/code/CodeFileViewer.tsx +5 -4
- package/src/interfaces/web/src/components/code/CodeProjectPicker.tsx +31 -7
- package/src/interfaces/web/src/components/code/CodeSessionList.tsx +32 -11
- package/src/interfaces/web/src/components/code/CodeSidePanel.tsx +33 -3
- package/src/interfaces/web/src/components/code/CodeTerminal.tsx +5 -4
- package/src/interfaces/web/src/components/code/NewCodeSessionDialog.tsx +164 -0
- package/src/interfaces/web/src/components/commitments/CommitmentDetail.tsx +162 -0
- package/src/interfaces/web/src/components/commitments/CommitmentFormDialog.tsx +158 -0
- package/src/interfaces/web/src/components/commitments/CommitmentList.tsx +194 -0
- package/src/interfaces/web/src/components/commitments/commitmentState.tsx +46 -0
- package/src/interfaces/web/src/components/common/BulkActionBar.tsx +60 -0
- package/src/interfaces/web/src/components/common/ConfirmDialog.tsx +4 -1
- package/src/interfaces/web/src/components/common/SelectCheckbox.tsx +40 -0
- package/src/interfaces/web/src/components/common/TabNav.tsx +1 -1
- package/src/interfaces/web/src/components/cron/CronPicker.tsx +1 -1
- package/src/interfaces/web/src/components/files/FileBrowser.tsx +1 -1
- package/src/interfaces/web/src/components/files/FileTree.tsx +6 -4
- package/src/interfaces/web/src/components/files/FileViewer.tsx +9 -5
- package/src/interfaces/web/src/components/files/MarkdownPreview.tsx +45 -9
- package/src/interfaces/web/src/components/images/ImageDefaultsCard.tsx +93 -0
- package/src/interfaces/web/src/components/images/ImageProviderList.tsx +142 -0
- package/src/interfaces/web/src/components/images/ImageProviderModal.tsx +263 -0
- package/src/interfaces/web/src/components/images/ImageTestCard.tsx +142 -0
- package/src/interfaces/web/src/components/inbox/ChannelFilter.tsx +178 -0
- package/src/interfaces/web/src/components/inbox/InboxList.tsx +77 -81
- package/src/interfaces/web/src/components/inbox/InboxRowItem.tsx +140 -0
- package/src/interfaces/web/src/components/integrations/ComingSoonPlugin.tsx +2 -2
- package/src/interfaces/web/src/components/integrations/PluginConnect.tsx +208 -30
- package/src/interfaces/web/src/components/integrations/PluginToolsSection.tsx +1 -1
- package/src/interfaces/web/src/components/layout/ProjectAvatar.tsx +39 -24
- package/src/interfaces/web/src/components/layout/ProjectSidebar.tsx +253 -58
- package/src/interfaces/web/src/components/memory/MemoryBrowser.tsx +94 -47
- package/src/interfaces/web/src/components/routines/ExecutionsList.tsx +202 -90
- package/src/interfaces/web/src/components/routines/RoutineDetail.tsx +28 -6
- package/src/interfaces/web/src/components/routines/RoutineEditor.tsx +16 -5
- package/src/interfaces/web/src/components/routines/RoutineList.tsx +49 -9
- package/src/interfaces/web/src/components/routines/VarTextarea.tsx +1 -1
- package/src/interfaces/web/src/components/routines/runChat.ts +121 -0
- package/src/interfaces/web/src/components/sessions/SessionDetail.tsx +148 -0
- package/src/interfaces/web/src/components/sessions/SessionTerminal.tsx +98 -0
- package/src/interfaces/web/src/components/settings/AccessPanel.tsx +205 -0
- package/src/interfaces/web/src/components/settings/DefaultRouterCard.tsx +246 -101
- package/src/interfaces/web/src/components/settings/DesktopSettingsPanel.tsx +36 -2
- package/src/interfaces/web/src/components/settings/DevicesPanel.tsx +19 -6
- package/src/interfaces/web/src/components/settings/EmbedProviderList.tsx +274 -0
- package/src/interfaces/web/src/components/settings/EnginesPanel.tsx +26 -6
- package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +118 -119
- package/src/interfaces/web/src/components/settings/NudgePanel.tsx +4 -3
- package/src/interfaces/web/src/components/settings/PairDeviceDialog.tsx +15 -4
- package/src/interfaces/web/src/components/settings/PanelPrefs.tsx +374 -0
- package/src/interfaces/web/src/components/settings/ProfilePanel.tsx +70 -2
- package/src/interfaces/web/src/components/settings/RoutingPanel.tsx +2 -1
- package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +102 -43
- package/src/interfaces/web/src/components/settings/SkillsManager.tsx +76 -21
- package/src/interfaces/web/src/components/settings/SkillsSettings.tsx +10 -3
- package/src/interfaces/web/src/components/settings/SuperAgentPanel.tsx +8 -0
- package/src/interfaces/web/src/components/settings/TelegramChannelsPanel.tsx +11 -2
- package/src/interfaces/web/src/components/settings/TelegramContactsPanel.tsx +19 -8
- package/src/interfaces/web/src/components/settings/TelegramRolesPanel.tsx +12 -2
- package/src/interfaces/web/src/components/settings/WebPanel.tsx +22 -31
- package/src/interfaces/web/src/components/settings/providers/ProviderCard.tsx +15 -3
- package/src/interfaces/web/src/components/settings/providers/ProviderModal.tsx +97 -66
- package/src/interfaces/web/src/components/settings/providers/ProviderTestDialog.tsx +150 -0
- package/src/interfaces/web/src/components/settings/providers/typeStyles.ts +67 -25
- package/src/interfaces/web/src/components/settings/providers/types.ts +3 -0
- package/src/interfaces/web/src/components/tasks/TaskBoard.tsx +201 -0
- package/src/interfaces/web/src/components/tasks/TaskColumnsDialog.tsx +243 -0
- package/src/interfaces/web/src/components/tasks/TaskComments.tsx +167 -0
- package/src/interfaces/web/src/components/tasks/TaskDetail.tsx +335 -0
- package/src/interfaces/web/src/components/tasks/TaskFormDialog.tsx +406 -0
- package/src/interfaces/web/src/components/tasks/TaskList.tsx +258 -0
- package/src/interfaces/web/src/components/tasks/TaskSubtasks.tsx +126 -0
- package/src/interfaces/web/src/components/tasks/columns.ts +51 -0
- package/src/interfaces/web/src/components/tasks/taskStatus.tsx +159 -34
- package/src/interfaces/web/src/components/tasks/taskViewPrefs.ts +73 -0
- package/src/interfaces/web/src/components/tasks/useTaskColumns.ts +31 -0
- package/src/interfaces/web/src/components/ui/chat-input.tsx +136 -12
- package/src/interfaces/web/src/components/ui/context-menu.tsx +15 -198
- package/src/interfaces/web/src/components/ui/dialog.tsx +3 -2
- package/src/interfaces/web/src/components/ui/filter-chips.tsx +4 -0
- package/src/interfaces/web/src/components/ui/popover.tsx +14 -49
- package/src/interfaces/web/src/components/ui/sheet.tsx +2 -1
- package/src/interfaces/web/src/components/ui/spinner.tsx +2 -1
- package/src/interfaces/web/src/components/ui.tsx +62 -23
- package/src/interfaces/web/src/components/voice/VoiceProviderList.tsx +2 -1
- package/src/interfaces/web/src/components/voice/VoiceProviderModal.tsx +66 -8
- package/src/interfaces/web/src/components/voice/VoiceQvoxInstallCard.tsx +63 -0
- package/src/interfaces/web/src/components/voice/VoiceQvoxStatusCard.tsx +51 -0
- package/src/interfaces/web/src/components/voice/VoiceSttCard.tsx +4 -3
- package/src/interfaces/web/src/components/voice/VoiceTestCard.tsx +38 -4
- package/src/interfaces/web/src/constants/index.ts +1 -0
- package/src/interfaces/web/src/hooks/useChannelPrefs.ts +39 -0
- package/src/interfaces/web/src/hooks/useChat.ts +1092 -85
- package/src/interfaces/web/src/hooks/useChatActivity.ts +24 -0
- package/src/interfaces/web/src/hooks/useInbox.ts +26 -4
- package/src/interfaces/web/src/hooks/useLiveMessages.ts +16 -0
- package/src/interfaces/web/src/hooks/useOllamaModels.ts +79 -0
- package/src/interfaces/web/src/hooks/useRecorder.ts +198 -0
- package/src/interfaces/web/src/hooks/useTokenBootstrap.ts +23 -6
- package/src/interfaces/web/src/i18n/en.ts +832 -175
- package/src/interfaces/web/src/i18n/es.ts +841 -188
- package/src/interfaces/web/src/lib/api/agents.ts +23 -4
- package/src/interfaces/web/src/lib/api/code.ts +17 -0
- package/src/interfaces/web/src/lib/api/commitments.ts +7 -1
- package/src/interfaces/web/src/lib/api/conversations.ts +38 -11
- package/src/interfaces/web/src/lib/api/embeddings.ts +3 -0
- package/src/interfaces/web/src/lib/api/engines.ts +14 -0
- package/src/interfaces/web/src/lib/api/groups.ts +93 -0
- package/src/interfaces/web/src/lib/api/images.ts +193 -0
- package/src/interfaces/web/src/lib/api/inbox.ts +29 -5
- package/src/interfaces/web/src/lib/api/integrations.ts +9 -0
- package/src/interfaces/web/src/lib/api/media.ts +126 -0
- package/src/interfaces/web/src/lib/api/net.ts +44 -0
- package/src/interfaces/web/src/lib/api/profiles.ts +12 -0
- package/src/interfaces/web/src/lib/api/projects.ts +9 -1
- package/src/interfaces/web/src/lib/api/routines.ts +9 -1
- package/src/interfaces/web/src/lib/api/sessions.ts +18 -0
- package/src/interfaces/web/src/lib/api/skills.ts +8 -0
- package/src/interfaces/web/src/lib/api/super_agent.ts +3 -0
- package/src/interfaces/web/src/lib/api/tasks.ts +46 -6
- package/src/interfaces/web/src/lib/api/tools.ts +2 -0
- package/src/interfaces/web/src/lib/api/transcribe.ts +31 -0
- package/src/interfaces/web/src/lib/api/turns.ts +20 -0
- package/src/interfaces/web/src/lib/api/voice.ts +72 -2
- package/src/interfaces/web/src/lib/api.ts +3 -0
- package/src/interfaces/web/src/lib/channels.ts +214 -0
- package/src/interfaces/web/src/lib/chat-activity.ts +175 -0
- package/src/interfaces/web/src/lib/chat-prefs.ts +48 -0
- package/src/interfaces/web/src/lib/code-context.ts +0 -2
- package/src/interfaces/web/src/lib/http.ts +51 -17
- package/src/interfaces/web/src/lib/inbox-selection.ts +29 -0
- package/src/interfaces/web/src/lib/live.ts +252 -0
- package/src/interfaces/web/src/lib/net.ts +211 -0
- package/src/interfaces/web/src/lib/notify.ts +331 -0
- package/src/interfaces/web/src/lib/projectNav.ts +40 -0
- package/src/interfaces/web/src/lib/pwa.ts +115 -0
- package/src/interfaces/web/src/lib/qvox.ts +24 -0
- package/src/interfaces/web/src/lib/slug.ts +3 -0
- package/src/interfaces/web/src/lib/tone.ts +150 -0
- package/src/interfaces/web/src/main.tsx +15 -4
- package/src/interfaces/web/src/screens/ApxAdminScreen.tsx +33 -11
- package/src/interfaces/web/src/screens/InboxScreen.tsx +126 -71
- package/src/interfaces/web/src/screens/ProjectScreen.tsx +8 -4
- package/src/interfaces/web/src/screens/SettingsScreen.tsx +7 -4
- package/src/interfaces/web/src/screens/base/AgentDefaultsTab.tsx +30 -9
- package/src/interfaces/web/src/screens/base/CommitmentsTab.tsx +150 -168
- package/src/interfaces/web/src/screens/base/LogsTab.tsx +8 -7
- package/src/interfaces/web/src/screens/base/SessionsTab.tsx +99 -37
- package/src/interfaces/web/src/screens/base/WorkspacesTab.tsx +1 -1
- package/src/interfaces/web/src/screens/mobile/MobileChat.tsx +85 -0
- package/src/interfaces/web/src/screens/mobile/MobileChatList.tsx +244 -0
- package/src/interfaces/web/src/screens/mobile/MobileCommitments.tsx +350 -0
- package/src/interfaces/web/src/screens/mobile/MobileScreen.tsx +138 -0
- package/src/interfaces/web/src/screens/mobile/MobileTabBar.tsx +105 -0
- package/src/interfaces/web/src/screens/mobile/MobileTasks.tsx +407 -0
- package/src/interfaces/web/src/screens/mobile/NewChatSheet.tsx +313 -0
- package/src/interfaces/web/src/screens/mobile/mobileList.tsx +194 -0
- package/src/interfaces/web/src/screens/mobile/routes.ts +239 -0
- package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +135 -64
- package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +0 -1
- package/src/interfaces/web/src/screens/modules/ImagesScreen.tsx +172 -0
- package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +36 -4
- package/src/interfaces/web/src/screens/project/AgentBrainGraph.tsx +117 -30
- package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +537 -92
- package/src/interfaces/web/src/screens/project/AgentsTab.tsx +344 -93
- package/src/interfaces/web/src/screens/project/ArtifactsTab.tsx +1 -1
- package/src/interfaces/web/src/screens/project/ChatTab.tsx +1160 -94
- package/src/interfaces/web/src/screens/project/IntegrationsTab.tsx +3 -2
- package/src/interfaces/web/src/screens/project/McpsTab.tsx +62 -14
- package/src/interfaces/web/src/screens/project/Overview.tsx +36 -15
- package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +93 -8
- package/src/interfaces/web/src/screens/project/SkillsTab.tsx +4 -1
- package/src/interfaces/web/src/screens/project/StructureTab.tsx +5 -4
- package/src/interfaces/web/src/screens/project/TasksTab.tsx +351 -129
- package/src/interfaces/web/src/screens/project/VarsTab.tsx +17 -5
- package/src/interfaces/web/src/styles.css +106 -31
- package/src/interfaces/web/src/types/daemon.ts +246 -2
- package/src/interfaces/web/src/vite-env.d.ts +20 -0
- package/src/interfaces/tui/plugin/command-shim.ts +0 -109
- package/src/interfaces/web/components.json +0 -25
- package/src/interfaces/web/dist/assets/index-CvEoGtTf.js +0 -849
- package/src/interfaces/web/dist/assets/index-CvEoGtTf.js.map +0 -1
- package/src/interfaces/web/dist/assets/index-DzBBXFaO.css +0 -1
- package/src/interfaces/web/src/components/tasks/TaskDetailPanel.tsx +0 -142
- package/src/interfaces/web/src/components/ui/accordion.tsx +0 -72
- package/src/interfaces/web/src/components/ui/alert-dialog.tsx +0 -187
- package/src/interfaces/web/src/components/ui/alert.tsx +0 -76
- package/src/interfaces/web/src/components/ui/aspect-ratio.tsx +0 -22
- package/src/interfaces/web/src/components/ui/avatar.tsx +0 -107
- package/src/interfaces/web/src/components/ui/breadcrumb.tsx +0 -125
- package/src/interfaces/web/src/components/ui/button-group.tsx +0 -87
- package/src/interfaces/web/src/components/ui/calendar.tsx +0 -221
- package/src/interfaces/web/src/components/ui/card.tsx +0 -103
- package/src/interfaces/web/src/components/ui/carousel.tsx +0 -242
- package/src/interfaces/web/src/components/ui/chart.tsx +0 -371
- package/src/interfaces/web/src/components/ui/checkbox.tsx +0 -29
- package/src/interfaces/web/src/components/ui/collapsible.tsx +0 -19
- package/src/interfaces/web/src/components/ui/combobox.tsx +0 -295
- package/src/interfaces/web/src/components/ui/command.tsx +0 -196
- package/src/interfaces/web/src/components/ui/direction.tsx +0 -4
- package/src/interfaces/web/src/components/ui/drawer.tsx +0 -134
- package/src/interfaces/web/src/components/ui/empty.tsx +0 -104
- package/src/interfaces/web/src/components/ui/field.tsx +0 -236
- package/src/interfaces/web/src/components/ui/hover-card.tsx +0 -51
- package/src/interfaces/web/src/components/ui/input-otp.tsx +0 -85
- package/src/interfaces/web/src/components/ui/item.tsx +0 -201
- package/src/interfaces/web/src/components/ui/menubar.tsx +0 -280
- package/src/interfaces/web/src/components/ui/native-select.tsx +0 -61
- package/src/interfaces/web/src/components/ui/navigation-menu.tsx +0 -168
- package/src/interfaces/web/src/components/ui/pagination.tsx +0 -130
- package/src/interfaces/web/src/components/ui/progress.tsx +0 -83
- package/src/interfaces/web/src/components/ui/radio-group.tsx +0 -36
- package/src/interfaces/web/src/components/ui/resizable.tsx +0 -50
- package/src/interfaces/web/src/components/ui/scroll-area.tsx +0 -53
- package/src/interfaces/web/src/components/ui/sidebar.tsx +0 -726
- package/src/interfaces/web/src/components/ui/slider.tsx +0 -52
- package/src/interfaces/web/src/components/ui/sonner.tsx +0 -49
- package/src/interfaces/web/src/components/ui/table.tsx +0 -116
- package/src/interfaces/web/src/components/ui/toggle-group.tsx +0 -87
- package/src/interfaces/web/src/components/ui/toggle.tsx +0 -45
- package/src/interfaces/web/src/hooks/use-mobile.ts +0 -19
- package/src/interfaces/web/src/screens/base/GlobalTasksTab.tsx +0 -161
package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MainActivity.java
ADDED
|
@@ -0,0 +1,872 @@
|
|
|
1
|
+
package dev.agentprojectcontext.apx;
|
|
2
|
+
|
|
3
|
+
import android.Manifest;
|
|
4
|
+
import android.app.Activity;
|
|
5
|
+
import android.app.AlertDialog;
|
|
6
|
+
import android.app.NotificationManager;
|
|
7
|
+
import android.service.notification.NotificationListenerService;
|
|
8
|
+
import android.content.Intent;
|
|
9
|
+
import android.content.ComponentName;
|
|
10
|
+
import android.content.BroadcastReceiver;
|
|
11
|
+
import android.content.Context;
|
|
12
|
+
import android.content.IntentFilter;
|
|
13
|
+
import android.content.pm.PackageManager;
|
|
14
|
+
import android.graphics.Color;
|
|
15
|
+
import android.net.Uri;
|
|
16
|
+
import android.os.Build;
|
|
17
|
+
import android.os.Bundle;
|
|
18
|
+
import android.os.PowerManager;
|
|
19
|
+
import android.provider.Settings;
|
|
20
|
+
import android.util.Log;
|
|
21
|
+
import android.view.Gravity;
|
|
22
|
+
import android.view.View;
|
|
23
|
+
import android.view.ViewGroup;
|
|
24
|
+
import android.webkit.WebChromeClient;
|
|
25
|
+
import android.webkit.JavascriptInterface;
|
|
26
|
+
import android.webkit.WebResourceRequest;
|
|
27
|
+
import android.webkit.WebSettings;
|
|
28
|
+
import android.webkit.WebView;
|
|
29
|
+
import android.webkit.WebViewClient;
|
|
30
|
+
import android.widget.Button;
|
|
31
|
+
import android.widget.EditText;
|
|
32
|
+
import android.widget.FrameLayout;
|
|
33
|
+
import android.widget.ImageView;
|
|
34
|
+
import android.widget.LinearLayout;
|
|
35
|
+
import android.widget.ProgressBar;
|
|
36
|
+
import android.widget.TextView;
|
|
37
|
+
import android.widget.Toast;
|
|
38
|
+
|
|
39
|
+
import org.json.JSONObject;
|
|
40
|
+
|
|
41
|
+
import java.net.URI;
|
|
42
|
+
import java.util.List;
|
|
43
|
+
import java.util.UUID;
|
|
44
|
+
|
|
45
|
+
public final class MainActivity extends Activity {
|
|
46
|
+
static final String EXTRA_PATH = "open_path";
|
|
47
|
+
static final String EXTRA_SETTINGS = "show_settings";
|
|
48
|
+
private static final int OVERLAY_REQUEST = 401;
|
|
49
|
+
private static final int NOTIFICATION_REQUEST = 402;
|
|
50
|
+
private static final int LOCATION_REQUEST = 403;
|
|
51
|
+
private static final int GREEN = Color.rgb(58, 231, 176);
|
|
52
|
+
private static final int PANEL = Color.rgb(20, 27, 25);
|
|
53
|
+
|
|
54
|
+
private ApxPreferences preferences;
|
|
55
|
+
private WebView webView;
|
|
56
|
+
private TravelStatusBanner travelBanner;
|
|
57
|
+
// -1 = not asked yet. The banner must not print "0 pendientes" before the
|
|
58
|
+
// daemon has answered.
|
|
59
|
+
private int tripPlaceCount = -1;
|
|
60
|
+
private boolean travelReceiverRegistered;
|
|
61
|
+
private boolean waitingForOverlay;
|
|
62
|
+
private String pendingPath = "/mobile";
|
|
63
|
+
private final BroadcastReceiver travelReceiver = new BroadcastReceiver() {
|
|
64
|
+
@Override public void onReceive(Context context, Intent intent) {
|
|
65
|
+
updateTravelBanner();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
private final Runnable tripPlaceRecheck = () -> {
|
|
69
|
+
if (preferences.travelActive()) refreshTripPlaceCount();
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
@Override
|
|
73
|
+
protected void onCreate(Bundle state) {
|
|
74
|
+
super.onCreate(state);
|
|
75
|
+
preferences = new ApxPreferences(this);
|
|
76
|
+
getWindow().setStatusBarColor(Color.rgb(13, 17, 16));
|
|
77
|
+
getWindow().setNavigationBarColor(Color.rgb(13, 17, 16));
|
|
78
|
+
handleIntent(getIntent());
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@Override
|
|
82
|
+
protected void onNewIntent(Intent intent) {
|
|
83
|
+
super.onNewIntent(intent);
|
|
84
|
+
setIntent(intent);
|
|
85
|
+
handleIntent(intent);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private void handleIntent(Intent intent) {
|
|
89
|
+
if (handleMapsShare(intent)) return;
|
|
90
|
+
String requestedPath = intent.getStringExtra(EXTRA_PATH);
|
|
91
|
+
if (requestedPath != null && requestedPath.startsWith("/mobile")) pendingPath = requestedPath;
|
|
92
|
+
Uri data = intent.getData();
|
|
93
|
+
if (data != null && "apx".equals(data.getScheme()) && "pair".equals(data.getHost())) {
|
|
94
|
+
showPairing(data.getQueryParameter("url"), data.getQueryParameter("pid"), true);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (intent.getBooleanExtra(EXTRA_SETTINGS, false)) {
|
|
98
|
+
showNativeMenu();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (preferences.paired()) {
|
|
102
|
+
requestLocationPermission();
|
|
103
|
+
openMobile(pendingPath);
|
|
104
|
+
ensureMascotRunning();
|
|
105
|
+
} else {
|
|
106
|
+
showPairing(null, null, false);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private boolean handleMapsShare(Intent intent) {
|
|
111
|
+
if (!Intent.ACTION_SEND.equals(intent.getAction()) || !"text/plain".equals(intent.getType())) return false;
|
|
112
|
+
CharSequence shared = intent.getCharSequenceExtra(Intent.EXTRA_TEXT);
|
|
113
|
+
if (!MapsShareIntentParser.isGoogleMapsShare(shared)) {
|
|
114
|
+
Toast.makeText(this, "APX necesita un viaje compartido desde Maps", Toast.LENGTH_LONG).show();
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
if (!preferences.paired()) {
|
|
118
|
+
Toast.makeText(this, "Vinculá APX antes de compartir el viaje", Toast.LENGTH_LONG).show();
|
|
119
|
+
showPairing(null, null, false);
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
String destination = MapsShareIntentParser.destinationFrom(shared);
|
|
124
|
+
String tripId = preferences.travelActive() && !preferences.travelTripId().isBlank()
|
|
125
|
+
? preferences.travelTripId()
|
|
126
|
+
: UUID.randomUUID().toString();
|
|
127
|
+
boolean suppressed = TravelEventGate.coolingDown(
|
|
128
|
+
System.currentTimeMillis(),
|
|
129
|
+
destination,
|
|
130
|
+
preferences.travelLastSentAt(),
|
|
131
|
+
preferences.travelLastSentDestination()
|
|
132
|
+
);
|
|
133
|
+
preferences.setTravelState(true, destination, tripId);
|
|
134
|
+
if (suppressed) {
|
|
135
|
+
preferences.setTravelEventSent(true);
|
|
136
|
+
} else {
|
|
137
|
+
preferences.recordTravelEventSent(destination);
|
|
138
|
+
DaemonClient.notifyTripStarted(
|
|
139
|
+
preferences.daemonUrl(),
|
|
140
|
+
preferences.token(),
|
|
141
|
+
tripId,
|
|
142
|
+
destination,
|
|
143
|
+
DeviceLocation.latest(this)
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
sendBroadcast(new Intent(MapsNavigationListenerService.ACTION_TRAVEL_STATE_CHANGED).setPackage(getPackageName()));
|
|
147
|
+
Toast.makeText(
|
|
148
|
+
this,
|
|
149
|
+
suppressed ? "Viaje actualizado; Roby no repetirá el aviso" : "Viaje compartido con APX",
|
|
150
|
+
Toast.LENGTH_LONG
|
|
151
|
+
).show();
|
|
152
|
+
intent.setAction(Intent.ACTION_MAIN);
|
|
153
|
+
intent.removeExtra(Intent.EXTRA_TEXT);
|
|
154
|
+
requestLocationPermission();
|
|
155
|
+
openMobile(pendingPath);
|
|
156
|
+
ensureMascotRunning();
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private void showPairing(String suggestedUrl, String suggestedCode, boolean autoSubmit) {
|
|
161
|
+
webView = null;
|
|
162
|
+
LinearLayout root = new LinearLayout(this);
|
|
163
|
+
root.setOrientation(LinearLayout.VERTICAL);
|
|
164
|
+
root.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
165
|
+
root.setPadding(dp(28), dp(56), dp(28), dp(24));
|
|
166
|
+
root.setBackgroundColor(Color.rgb(13, 17, 16));
|
|
167
|
+
|
|
168
|
+
ImageView logo = new ImageView(this);
|
|
169
|
+
logo.setImageResource(R.drawable.apx_logo);
|
|
170
|
+
logo.setContentDescription("APX");
|
|
171
|
+
logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
|
172
|
+
LinearLayout.LayoutParams logoParams = new LinearLayout.LayoutParams(
|
|
173
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
174
|
+
dp(112)
|
|
175
|
+
);
|
|
176
|
+
logoParams.bottomMargin = dp(16);
|
|
177
|
+
root.addView(logo, logoParams);
|
|
178
|
+
|
|
179
|
+
TextView title = text("APX Android", 28, Color.WHITE);
|
|
180
|
+
title.setTypeface(null, android.graphics.Typeface.BOLD);
|
|
181
|
+
root.addView(title, matchWrap());
|
|
182
|
+
|
|
183
|
+
TextView info = text("Conectá esta app al daemon. Ejecutá “apx pair web” y pegá código mostrado.", 15, Color.LTGRAY);
|
|
184
|
+
info.setPadding(0, dp(12), 0, dp(24));
|
|
185
|
+
root.addView(info, matchWrap());
|
|
186
|
+
|
|
187
|
+
EditText url = input("http://IP:7430");
|
|
188
|
+
url.setInputType(android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_URI);
|
|
189
|
+
String currentUrl = suggestedUrl != null ? suggestedUrl : preferences.daemonUrl();
|
|
190
|
+
url.setText(currentUrl);
|
|
191
|
+
root.addView(url, matchWrap());
|
|
192
|
+
|
|
193
|
+
EditText code = input("Código pairing");
|
|
194
|
+
code.setText(suggestedCode == null ? "" : suggestedCode);
|
|
195
|
+
LinearLayout.LayoutParams codeParams = matchWrap();
|
|
196
|
+
codeParams.topMargin = dp(12);
|
|
197
|
+
root.addView(code, codeParams);
|
|
198
|
+
|
|
199
|
+
TextView status = text("", 14, Color.LTGRAY);
|
|
200
|
+
status.setPadding(0, dp(14), 0, dp(8));
|
|
201
|
+
root.addView(status, matchWrap());
|
|
202
|
+
|
|
203
|
+
ProgressBar progress = new ProgressBar(this);
|
|
204
|
+
progress.setVisibility(View.GONE);
|
|
205
|
+
root.addView(progress, new LinearLayout.LayoutParams(dp(38), dp(38)));
|
|
206
|
+
|
|
207
|
+
Button pair = button("Vincular y abrir");
|
|
208
|
+
root.addView(pair, matchWrap());
|
|
209
|
+
setContentView(root);
|
|
210
|
+
|
|
211
|
+
View.OnClickListener submit = ignored -> {
|
|
212
|
+
String base;
|
|
213
|
+
try {
|
|
214
|
+
base = DaemonAddress.normalize(url.getText().toString());
|
|
215
|
+
} catch (IllegalArgumentException error) {
|
|
216
|
+
status.setText(error.getMessage());
|
|
217
|
+
status.setTextColor(Color.rgb(255, 130, 130));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
String pairingId = code.getText().toString().trim();
|
|
221
|
+
if (pairingId.isBlank()) {
|
|
222
|
+
status.setText("Ingresá código pairing.");
|
|
223
|
+
status.setTextColor(Color.rgb(255, 130, 130));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
pair.setEnabled(false);
|
|
227
|
+
progress.setVisibility(View.VISIBLE);
|
|
228
|
+
status.setText("Vinculando…");
|
|
229
|
+
status.setTextColor(Color.LTGRAY);
|
|
230
|
+
String label = "APX Android · " + Build.MANUFACTURER + " " + Build.MODEL;
|
|
231
|
+
DaemonClient.pair(base, pairingId, label, new DaemonClient.PairCallback() {
|
|
232
|
+
@Override public void onSuccess(String token) {
|
|
233
|
+
runOnUiThread(() -> {
|
|
234
|
+
preferences.savePairing(base, token);
|
|
235
|
+
status.setText("Vinculado.");
|
|
236
|
+
status.setTextColor(GREEN);
|
|
237
|
+
requestNativePermissionsAndOpen();
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
@Override public void onError(String message) {
|
|
242
|
+
runOnUiThread(() -> {
|
|
243
|
+
pair.setEnabled(true);
|
|
244
|
+
progress.setVisibility(View.GONE);
|
|
245
|
+
status.setText(message);
|
|
246
|
+
status.setTextColor(Color.rgb(255, 130, 130));
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
};
|
|
251
|
+
pair.setOnClickListener(submit);
|
|
252
|
+
if (autoSubmit && suggestedUrl != null && suggestedCode != null) pair.post(pair::performClick);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private void requestNativePermissionsAndOpen() {
|
|
256
|
+
if (Build.VERSION.SDK_INT >= 33 && checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
|
257
|
+
requestPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS}, NOTIFICATION_REQUEST);
|
|
258
|
+
}
|
|
259
|
+
if (!Settings.canDrawOverlays(this)) {
|
|
260
|
+
waitingForOverlay = true;
|
|
261
|
+
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
|
|
262
|
+
startActivityForResult(intent, OVERLAY_REQUEST);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
requestLocationPermission();
|
|
266
|
+
ensureMascotRunning();
|
|
267
|
+
openMobile("/mobile");
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private void requestLocationPermission() {
|
|
271
|
+
if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) return;
|
|
272
|
+
requestPermissions(new String[]{
|
|
273
|
+
Manifest.permission.ACCESS_COARSE_LOCATION,
|
|
274
|
+
Manifest.permission.ACCESS_FINE_LOCATION,
|
|
275
|
+
}, LOCATION_REQUEST);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
@Override
|
|
279
|
+
protected void onResume() {
|
|
280
|
+
super.onResume();
|
|
281
|
+
NotificationListenerService.requestRebind(new ComponentName(
|
|
282
|
+
this,
|
|
283
|
+
MapsNavigationListenerService.class
|
|
284
|
+
));
|
|
285
|
+
// A foreground-service start is only guaranteed to be allowed while an
|
|
286
|
+
// activity is visible, and some OEM power managers refuse it outright
|
|
287
|
+
// from the notification listener. This is the one moment the trip's GPS
|
|
288
|
+
// service can always be (re)started, so take it: a trip flagged active
|
|
289
|
+
// with nothing tracking is a trip the daemon hears nothing from.
|
|
290
|
+
// Starting an already-running service is a no-op.
|
|
291
|
+
if (preferences.travelActive() && !preferences.travelTripId().isBlank()) {
|
|
292
|
+
TripLocationService.start(this, preferences.travelTripId());
|
|
293
|
+
}
|
|
294
|
+
if (waitingForOverlay) {
|
|
295
|
+
waitingForOverlay = false;
|
|
296
|
+
if (Settings.canDrawOverlays(this)) ensureMascotRunning();
|
|
297
|
+
openMobile("/mobile");
|
|
298
|
+
}
|
|
299
|
+
setMascotAppForeground(true);
|
|
300
|
+
// The embedded /mobile is a live React app: its own socket, its
|
|
301
|
+
// timers, its animations. Android does not stop any of that when the
|
|
302
|
+
// activity goes away, so leaving APX by the home button used to leave a
|
|
303
|
+
// full web app running behind the launcher for as long as the process
|
|
304
|
+
// survived. Resume it here, pause it in onPause, and off screen the
|
|
305
|
+
// WebView costs nothing.
|
|
306
|
+
if (webView != null) {
|
|
307
|
+
webView.onResume();
|
|
308
|
+
webView.resumeTimers();
|
|
309
|
+
}
|
|
310
|
+
updateTravelBanner();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
@Override
|
|
314
|
+
protected void onStart() {
|
|
315
|
+
super.onStart();
|
|
316
|
+
IntentFilter filter = new IntentFilter(MapsNavigationListenerService.ACTION_TRAVEL_STATE_CHANGED);
|
|
317
|
+
if (Build.VERSION.SDK_INT >= 33) registerReceiver(travelReceiver, filter, RECEIVER_NOT_EXPORTED);
|
|
318
|
+
else registerReceiver(travelReceiver, filter);
|
|
319
|
+
travelReceiverRegistered = true;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
@Override
|
|
323
|
+
protected void onStop() {
|
|
324
|
+
if (travelReceiverRegistered) {
|
|
325
|
+
unregisterReceiver(travelReceiver);
|
|
326
|
+
travelReceiverRegistered = false;
|
|
327
|
+
}
|
|
328
|
+
super.onStop();
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
@Override
|
|
332
|
+
protected void onPause() {
|
|
333
|
+
setMascotAppForeground(false);
|
|
334
|
+
if (webView != null) {
|
|
335
|
+
webView.onPause();
|
|
336
|
+
// pauseTimers() is process-wide and there is exactly one WebView
|
|
337
|
+
// here; it is what actually stops the JavaScript, where onPause()
|
|
338
|
+
// alone only stops drawing.
|
|
339
|
+
webView.pauseTimers();
|
|
340
|
+
}
|
|
341
|
+
super.onPause();
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private void ensureMascotRunning() {
|
|
345
|
+
if (!preferences.paired()) return;
|
|
346
|
+
Intent service = new Intent(this, MascotOverlayService.class);
|
|
347
|
+
if (Build.VERSION.SDK_INT >= 26) startForegroundService(service); else startService(service);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
private void setMascotAppForeground(boolean foreground) {
|
|
351
|
+
if (!preferences.paired()) return;
|
|
352
|
+
Intent service = new Intent(this, MascotOverlayService.class)
|
|
353
|
+
.setAction(foreground ? MascotOverlayService.ACTION_APP_FOREGROUND : MascotOverlayService.ACTION_APP_BACKGROUND);
|
|
354
|
+
if (Build.VERSION.SDK_INT >= 26) startForegroundService(service); else startService(service);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
private void openMobile(String path) {
|
|
358
|
+
if (!preferences.paired()) {
|
|
359
|
+
showPairing(null, null, false);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
LinearLayout frame = new LinearLayout(this);
|
|
363
|
+
frame.setOrientation(LinearLayout.VERTICAL);
|
|
364
|
+
frame.setBackgroundColor(Color.rgb(13, 17, 16));
|
|
365
|
+
frame.setOnApplyWindowInsetsListener((view, insets) -> {
|
|
366
|
+
view.setPadding(0, insets.getSystemWindowInsetTop(), 0, 0);
|
|
367
|
+
return insets;
|
|
368
|
+
});
|
|
369
|
+
travelBanner = new TravelStatusBanner(this);
|
|
370
|
+
travelBanner.setOnClickListener(ignored -> showTripPlaces());
|
|
371
|
+
LinearLayout.LayoutParams bannerParams = new LinearLayout.LayoutParams(
|
|
372
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
373
|
+
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
374
|
+
);
|
|
375
|
+
frame.addView(travelBanner, bannerParams);
|
|
376
|
+
webView = new WebView(this);
|
|
377
|
+
webView.setBackgroundColor(Color.rgb(13, 17, 16));
|
|
378
|
+
WebSettings settings = webView.getSettings();
|
|
379
|
+
settings.setJavaScriptEnabled(true);
|
|
380
|
+
settings.setDomStorageEnabled(true);
|
|
381
|
+
settings.setDatabaseEnabled(true);
|
|
382
|
+
settings.setMediaPlaybackRequiresUserGesture(false);
|
|
383
|
+
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
|
|
384
|
+
settings.setUserAgentString(settings.getUserAgentString() + " APXAndroid/0.1");
|
|
385
|
+
webView.addJavascriptInterface(new AndroidBridge(), "APXAndroid");
|
|
386
|
+
webView.setWebChromeClient(new WebChromeClient());
|
|
387
|
+
webView.setWebViewClient(new WebViewClient() {
|
|
388
|
+
@Override
|
|
389
|
+
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
|
390
|
+
Uri target = request.getUrl();
|
|
391
|
+
try {
|
|
392
|
+
URI base = URI.create(preferences.daemonUrl());
|
|
393
|
+
if (base.getHost().equalsIgnoreCase(target.getHost())) return false;
|
|
394
|
+
} catch (Exception ignored) {}
|
|
395
|
+
startActivity(new Intent(Intent.ACTION_VIEW, target));
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
frame.addView(webView, new LinearLayout.LayoutParams(
|
|
400
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
401
|
+
0,
|
|
402
|
+
1f
|
|
403
|
+
));
|
|
404
|
+
setContentView(frame);
|
|
405
|
+
updateTravelBanner();
|
|
406
|
+
|
|
407
|
+
String safePath = path != null && path.startsWith("/mobile") ? path : "/mobile";
|
|
408
|
+
String target = preferences.daemonUrl() + safePath + "#token=" + Uri.encode(preferences.token());
|
|
409
|
+
webView.loadUrl(target);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
private void updateTravelBanner() {
|
|
413
|
+
if (travelBanner == null) return;
|
|
414
|
+
travelBanner.update(
|
|
415
|
+
preferences.travelActive(),
|
|
416
|
+
preferences.travelDestination(),
|
|
417
|
+
preferences.travelSource(),
|
|
418
|
+
tripPlaceCount
|
|
419
|
+
);
|
|
420
|
+
if (preferences.travelActive()) {
|
|
421
|
+
refreshTripPlaceCount();
|
|
422
|
+
scheduleTripPlaceRecheck();
|
|
423
|
+
} else {
|
|
424
|
+
travelBanner.removeCallbacks(tripPlaceRecheck);
|
|
425
|
+
tripPlaceCount = -1;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Keep the banner's count honest without making the driver tap to find out.
|
|
431
|
+
* Best-effort and silent: a count that could not be fetched shows as
|
|
432
|
+
* "Ver pendientes", never as zero — claiming there is nothing to stop for
|
|
433
|
+
* because the network was down is the one wrong answer here.
|
|
434
|
+
*/
|
|
435
|
+
private void refreshTripPlaceCount() {
|
|
436
|
+
DaemonClient.fetchTripPlaces(preferences.daemonUrl(), preferences.token(), new DaemonClient.TripCallback() {
|
|
437
|
+
@Override
|
|
438
|
+
public void onTrip(java.util.List<DaemonClient.TripPlace> places) {
|
|
439
|
+
runOnUiThread(() -> {
|
|
440
|
+
tripPlaceCount = places.size();
|
|
441
|
+
if (travelBanner != null) {
|
|
442
|
+
travelBanner.update(
|
|
443
|
+
preferences.travelActive(),
|
|
444
|
+
preferences.travelDestination(),
|
|
445
|
+
preferences.travelSource(),
|
|
446
|
+
tripPlaceCount
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
@Override
|
|
453
|
+
public void onError(String message) {
|
|
454
|
+
Log.i("APXTravel", "Could not read trip places: " + message);
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* The daemon's list fills in asynchronously — it only knows what is nearby
|
|
461
|
+
* once a GPS sample has reached it and the place search has answered. Asking
|
|
462
|
+
* once, the instant a trip opens, reliably gets "nothing nearby" for a trip
|
|
463
|
+
* that is about to have plenty, so ask again shortly after. One retry: this
|
|
464
|
+
* is a label, not a poll.
|
|
465
|
+
*/
|
|
466
|
+
private void scheduleTripPlaceRecheck() {
|
|
467
|
+
if (travelBanner == null) return;
|
|
468
|
+
// Exactly one pending recheck. This runs on every banner update — every
|
|
469
|
+
// resume and every travel broadcast — and posting a fresh timer each
|
|
470
|
+
// time queued a stack of them that all fired at once.
|
|
471
|
+
travelBanner.removeCallbacks(tripPlaceRecheck);
|
|
472
|
+
travelBanner.postDelayed(tripPlaceRecheck, 20_000L);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* The list behind the banner: every errand APX is watching on this trip,
|
|
477
|
+
* nearest first, each openable in Maps. This replaced an "Abrir Maps"
|
|
478
|
+
* shortcut that led nowhere useful — Maps is already open, it is where the
|
|
479
|
+
* trip is being read from.
|
|
480
|
+
*/
|
|
481
|
+
private void showTripPlaces() {
|
|
482
|
+
Toast.makeText(this, "Buscando pendientes del viaje…", Toast.LENGTH_SHORT).show();
|
|
483
|
+
DaemonClient.fetchTripPlaces(preferences.daemonUrl(), preferences.token(), new DaemonClient.TripCallback() {
|
|
484
|
+
@Override
|
|
485
|
+
public void onTrip(java.util.List<DaemonClient.TripPlace> places) {
|
|
486
|
+
runOnUiThread(() -> renderTripPlaces(places));
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
@Override
|
|
490
|
+
public void onError(String message) {
|
|
491
|
+
runOnUiThread(() -> Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show());
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* The errands, as the thread of cards TripPlacesSheet builds — one card per
|
|
498
|
+
* errand carrying the same four chips the Telegram card offers.
|
|
499
|
+
*
|
|
500
|
+
* It was an AlertDialog.setItems() list before, where a tap could only mean
|
|
501
|
+
* "open in Maps". That made the phone strictly worse than the chat for the
|
|
502
|
+
* same information: no way to say "voy", no way to add a stop without
|
|
503
|
+
* losing the current route.
|
|
504
|
+
*/
|
|
505
|
+
private void renderTripPlaces(java.util.List<DaemonClient.TripPlace> places) {
|
|
506
|
+
tripPlaceCount = places.size();
|
|
507
|
+
updateTravelBanner();
|
|
508
|
+
if (places.isEmpty()) {
|
|
509
|
+
new AlertDialog.Builder(this)
|
|
510
|
+
.setTitle("Pendientes del viaje")
|
|
511
|
+
.setMessage("Por ahora no hay ningún mandado cerca de este viaje.\n\nAPX mira las tareas abiertas que nombran algo físico — farmacia, supermercado, ferretería, nafta — y busca lugares en el camino.")
|
|
512
|
+
.setPositiveButton("Cerrar", null)
|
|
513
|
+
.show();
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
AlertDialog[] open = new AlertDialog[1];
|
|
517
|
+
TripPlacesSheet.Actions actions = new TripPlacesSheet.Actions() {
|
|
518
|
+
@Override
|
|
519
|
+
public void navigate(DaemonClient.TripPlace place) {
|
|
520
|
+
openInMaps(place.mapsUrl());
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
@Override
|
|
524
|
+
public void addStop(DaemonClient.TripPlace place) {
|
|
525
|
+
// Falls back to plain navigation when the daemon had no
|
|
526
|
+
// destination to add a stop to — see addToRouteUrl.
|
|
527
|
+
String url = place.addStopUrl() == null || place.addStopUrl().isBlank()
|
|
528
|
+
? place.mapsUrl() : place.addStopUrl();
|
|
529
|
+
openInMaps(url);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
@Override
|
|
533
|
+
public void answer(DaemonClient.TripPlace place, String answer) {
|
|
534
|
+
answerErrand(place, answer);
|
|
535
|
+
// Closed on the answer: the sheet is a snapshot, and leaving it
|
|
536
|
+
// open would keep showing chips for a question just settled.
|
|
537
|
+
if (open[0] != null) open[0].dismiss();
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
open[0] = new AlertDialog.Builder(this)
|
|
541
|
+
.setTitle("Pendientes del viaje")
|
|
542
|
+
.setView(TripPlacesSheet.build(this, places, actions))
|
|
543
|
+
.setNegativeButton("Cerrar", null)
|
|
544
|
+
.create();
|
|
545
|
+
open[0].show();
|
|
546
|
+
// The dialog paints its own light frame behind the sheet, so the title
|
|
547
|
+
// and the button row read as a different surface from the cards between
|
|
548
|
+
// them. One colour, one surface.
|
|
549
|
+
if (open[0].getWindow() != null) {
|
|
550
|
+
open[0].getWindow().setBackgroundDrawable(
|
|
551
|
+
new android.graphics.drawable.ColorDrawable(TripPlacesSheet.GROUND));
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Send one "voy" / "hoy no" to the daemon, which records it exactly as the
|
|
557
|
+
* Telegram chip would. Confirmed with a toast because the sheet closes: a
|
|
558
|
+
* tap with no visible consequence reads as a tap that did not register.
|
|
559
|
+
*/
|
|
560
|
+
private void answerErrand(DaemonClient.TripPlace place, String answer) {
|
|
561
|
+
String said = "go".equals(answer) ? "Anotado: vas." : "Listo, hoy no.";
|
|
562
|
+
DaemonClient.answerErrand(
|
|
563
|
+
preferences.daemonUrl(), preferences.token(), place.taskId(), answer,
|
|
564
|
+
new DaemonClient.AnswerCallback() {
|
|
565
|
+
@Override
|
|
566
|
+
public void onAnswered() {
|
|
567
|
+
runOnUiThread(() -> {
|
|
568
|
+
Toast.makeText(MainActivity.this, said, Toast.LENGTH_SHORT).show();
|
|
569
|
+
refreshTripPlaceCount();
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
@Override
|
|
574
|
+
public void onAnswerFailed(String message) {
|
|
575
|
+
runOnUiThread(() -> Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show());
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/** Hand one Maps URL to Maps. Falls back to any map app. */
|
|
581
|
+
private void openInMaps(String url) {
|
|
582
|
+
if (url == null || url.isBlank()) return;
|
|
583
|
+
Intent open = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
|
584
|
+
open.setPackage(MapsNavigationDetector.MAPS_PACKAGE);
|
|
585
|
+
if (open.resolveActivity(getPackageManager()) == null) open.setPackage(null);
|
|
586
|
+
try {
|
|
587
|
+
startActivity(open);
|
|
588
|
+
} catch (RuntimeException noHandler) {
|
|
589
|
+
Toast.makeText(this, "No hay ninguna app de mapas para abrirlo.", Toast.LENGTH_LONG).show();
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
private final class AndroidBridge {
|
|
594
|
+
@JavascriptInterface
|
|
595
|
+
public void openOptions() {
|
|
596
|
+
runOnUiThread(MainActivity.this::showNativeMenu);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
@JavascriptInterface
|
|
600
|
+
public boolean notificationsEnabled() {
|
|
601
|
+
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
|
602
|
+
boolean permissionGranted = Build.VERSION.SDK_INT < 33 ||
|
|
603
|
+
checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED;
|
|
604
|
+
return permissionGranted && manager.areNotificationsEnabled();
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
@JavascriptInterface
|
|
608
|
+
public void openNotificationSettings() {
|
|
609
|
+
runOnUiThread(() -> startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
|
|
610
|
+
.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName())));
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* The five channels and whether each may ring, as JSON.
|
|
615
|
+
*
|
|
616
|
+
* Resolved here, not raw storage: the panel gets the ANSWER for every
|
|
617
|
+
* channel, defaults filled in, so it never has to know that Telegram
|
|
618
|
+
* starts off on a phone. One rule, one place — NotifyChannels.
|
|
619
|
+
*
|
|
620
|
+
* A string and not an object because a WebView bridge only carries
|
|
621
|
+
* primitives across.
|
|
622
|
+
*/
|
|
623
|
+
@JavascriptInterface
|
|
624
|
+
public String notifyChannels() {
|
|
625
|
+
JSONObject out = new JSONObject();
|
|
626
|
+
try {
|
|
627
|
+
for (String channel : NotifyChannels.ALL) {
|
|
628
|
+
out.put(channel, preferences.notifyChannelEnabled(channel));
|
|
629
|
+
}
|
|
630
|
+
} catch (Exception ignored) {
|
|
631
|
+
// A JSONObject of five booleans does not throw; if it somehow
|
|
632
|
+
// did, an empty answer leaves the panel showing nothing rather
|
|
633
|
+
// than a wrong tick.
|
|
634
|
+
}
|
|
635
|
+
return out.toString();
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/** The panel's own tick, written to the same store the menu writes. */
|
|
639
|
+
@JavascriptInterface
|
|
640
|
+
public void setNotifyChannel(String channel, boolean on) {
|
|
641
|
+
preferences.setNotifyChannelEnabled(channel, on);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
private void showNativeMenu() {
|
|
646
|
+
if (!preferences.paired()) {
|
|
647
|
+
showPairing(null, null, false);
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
String mascotAction = preferences.mascotEnabled() ? "Desactivar mascota" : "Activar mascota";
|
|
651
|
+
String soundAction = preferences.soundEnabled() ? "✓ Sonido de mensajes" : "Sonido de mensajes";
|
|
652
|
+
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
|
653
|
+
String drivingAlertsAction = notificationManager.isNotificationPolicyAccessGranted()
|
|
654
|
+
? "✓ Avisos durante conducción"
|
|
655
|
+
: "Permitir avisos durante conducción";
|
|
656
|
+
String batteryAction = batteryUnrestricted()
|
|
657
|
+
? "✓ Batería sin restricciones"
|
|
658
|
+
: "Quitar restricción de batería";
|
|
659
|
+
boolean travelAccess = travelDetectionEnabled();
|
|
660
|
+
String travelAction = !travelAccess
|
|
661
|
+
? "Activar detección de viajes"
|
|
662
|
+
: !preferences.travelActive() ? "✓ Detección de viajes activa"
|
|
663
|
+
: ApxPreferences.SOURCE_ANDROID_AUTO.equals(preferences.travelSource())
|
|
664
|
+
? "✓ Android Auto conectado"
|
|
665
|
+
: "✓ Viaje de Maps detectado";
|
|
666
|
+
new AlertDialog.Builder(this)
|
|
667
|
+
.setTitle("APX Android")
|
|
668
|
+
.setItems(new String[]{mascotAction, soundAction, notifyChannelsAction(), drivingAlertsAction, batteryAction, travelAction, "Probar aviso Android Auto", "Recargar /mobile", "Vincular otro dispositivo"}, (dialog, which) -> {
|
|
669
|
+
if (which == 0) toggleMascot();
|
|
670
|
+
if (which == 1) toggleMessageSound();
|
|
671
|
+
if (which == 2) showNotifyChannels();
|
|
672
|
+
if (which == 3) startActivity(new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS));
|
|
673
|
+
if (which == 4) openBatterySettings();
|
|
674
|
+
if (which == 5) openTravelDetectionSettings();
|
|
675
|
+
if (which == 6) {
|
|
676
|
+
Intent test = new Intent(this, MascotOverlayService.class)
|
|
677
|
+
.setAction(MascotOverlayService.ACTION_TEST_MESSAGE)
|
|
678
|
+
.putExtra(MascotOverlayService.EXTRA_TEST_MESSAGE, "Prueba APX: aviso directo en Android Auto.");
|
|
679
|
+
if (Build.VERSION.SDK_INT >= 26) startForegroundService(test); else startService(test);
|
|
680
|
+
Toast.makeText(this, "Aviso APX enviado", Toast.LENGTH_SHORT).show();
|
|
681
|
+
}
|
|
682
|
+
if (which == 7) openMobile("/mobile");
|
|
683
|
+
if (which == 8) {
|
|
684
|
+
stopService(new Intent(this, MascotOverlayService.class));
|
|
685
|
+
preferences.clearPairing();
|
|
686
|
+
showPairing(null, null, false);
|
|
687
|
+
}
|
|
688
|
+
})
|
|
689
|
+
.setNegativeButton("Cerrar", null)
|
|
690
|
+
.show();
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/** Is APX exempt from Doze / App Standby right now? */
|
|
694
|
+
private boolean batteryUnrestricted() {
|
|
695
|
+
PowerManager power = (PowerManager) getSystemService(POWER_SERVICE);
|
|
696
|
+
return power != null && power.isIgnoringBatteryOptimizations(getPackageName());
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Hand the battery-optimisation decision to the owner, on the phone.
|
|
701
|
+
*
|
|
702
|
+
* It is theirs to make: the exemption is what stops Android deferring the
|
|
703
|
+
* trip's start and end while the phone is in a pocket, and it is also the
|
|
704
|
+
* one switch that lets APX cost battery when it is idle. So the app asks
|
|
705
|
+
* and never assumes — the direct dialog while APX is still restricted, and
|
|
706
|
+
* the system list once it is exempt, which is where the exemption can be
|
|
707
|
+
* taken back. Some OEM builds ship neither screen; fall back to the app's
|
|
708
|
+
* own details page rather than crashing on a missing activity.
|
|
709
|
+
*/
|
|
710
|
+
private void openBatterySettings() {
|
|
711
|
+
Intent request = batteryUnrestricted()
|
|
712
|
+
? new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)
|
|
713
|
+
: new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse("package:" + getPackageName()));
|
|
714
|
+
try {
|
|
715
|
+
startActivity(request);
|
|
716
|
+
return;
|
|
717
|
+
} catch (RuntimeException noScreen) {
|
|
718
|
+
Log.w("APX", "No battery optimisation screen: " + noScreen.getMessage());
|
|
719
|
+
}
|
|
720
|
+
try {
|
|
721
|
+
startActivity(new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName())));
|
|
722
|
+
} catch (RuntimeException noDetails) {
|
|
723
|
+
Toast.makeText(this, "Este Android no expone el ajuste de batería.", Toast.LENGTH_LONG).show();
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
private boolean travelDetectionEnabled() {
|
|
728
|
+
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
|
729
|
+
if (Build.VERSION.SDK_INT >= 27) {
|
|
730
|
+
return manager.isNotificationListenerAccessGranted(
|
|
731
|
+
new ComponentName(this, MapsNavigationListenerService.class)
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
String enabled = Settings.Secure.getString(getContentResolver(), "enabled_notification_listeners");
|
|
735
|
+
return enabled != null && enabled.contains(getPackageName());
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
private void openTravelDetectionSettings() {
|
|
739
|
+
startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS));
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/** How many of the five are on, said on the row itself: the menu answers
|
|
743
|
+
* "is something muted" without being opened. */
|
|
744
|
+
private String notifyChannelsAction() {
|
|
745
|
+
int on = 0;
|
|
746
|
+
for (String channel : NotifyChannels.ALL) {
|
|
747
|
+
if (preferences.notifyChannelEnabled(channel)) on++;
|
|
748
|
+
}
|
|
749
|
+
return on == NotifyChannels.ALL.size()
|
|
750
|
+
? "Avisarme de todo"
|
|
751
|
+
: "Avisarme de… (" + on + " de " + NotifyChannels.ALL.size() + ")";
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Which kinds of news may interrupt — as ticks, because that is the shape
|
|
756
|
+
* of the question: five independent yes/nos, all visible at once, no order
|
|
757
|
+
* and no priority between them.
|
|
758
|
+
*
|
|
759
|
+
* Applied on the spot rather than on a Save button. Each tick is complete
|
|
760
|
+
* on its own, and the next bubble either arrives or does not, which is the
|
|
761
|
+
* fastest way to find out whether the box you just ticked is the one you
|
|
762
|
+
* meant. The muted channels keep every message in /mobile — this only
|
|
763
|
+
* decides what jumps at you.
|
|
764
|
+
*/
|
|
765
|
+
private void showNotifyChannels() {
|
|
766
|
+
List<String> channels = NotifyChannels.ALL;
|
|
767
|
+
String[] labels = new String[channels.size()];
|
|
768
|
+
boolean[] checked = new boolean[channels.size()];
|
|
769
|
+
for (int i = 0; i < channels.size(); i++) {
|
|
770
|
+
labels[i] = NotifyChannels.label(channels.get(i));
|
|
771
|
+
checked[i] = preferences.notifyChannelEnabled(channels.get(i));
|
|
772
|
+
}
|
|
773
|
+
new AlertDialog.Builder(this)
|
|
774
|
+
.setTitle("Avisarme de")
|
|
775
|
+
.setMultiChoiceItems(labels, checked, (dialog, which, on) -> {
|
|
776
|
+
preferences.setNotifyChannelEnabled(channels.get(which), on);
|
|
777
|
+
pushNotifyChannelsToPanel();
|
|
778
|
+
})
|
|
779
|
+
.setPositiveButton("Listo", null)
|
|
780
|
+
.show();
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* Tell the page what the menu just changed.
|
|
785
|
+
*
|
|
786
|
+
* The panel shows the same five switches (PanelPrefs.tsx) and reads them
|
|
787
|
+
* through the bridge, so a WebView already on screen behind this dialog
|
|
788
|
+
* would otherwise keep painting the answer from before the tick. One event,
|
|
789
|
+
* same as the panel fires for its own writes.
|
|
790
|
+
*/
|
|
791
|
+
private void pushNotifyChannelsToPanel() {
|
|
792
|
+
if (webView == null) return;
|
|
793
|
+
webView.evaluateJavascript(
|
|
794
|
+
"window.dispatchEvent(new CustomEvent('apx:native-notify-channels'))",
|
|
795
|
+
null
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
private void toggleMessageSound() {
|
|
800
|
+
boolean enabled = !preferences.soundEnabled();
|
|
801
|
+
preferences.setSoundEnabled(enabled);
|
|
802
|
+
Toast.makeText(this, enabled ? "Sonido activado" : "Sonido silenciado", Toast.LENGTH_SHORT).show();
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
private void toggleMascot() {
|
|
806
|
+
boolean enabled = !preferences.mascotEnabled();
|
|
807
|
+
preferences.setMascotEnabled(enabled);
|
|
808
|
+
if (!enabled) {
|
|
809
|
+
ensureMascotRunning();
|
|
810
|
+
Toast.makeText(this, "Mascota desactivada", Toast.LENGTH_SHORT).show();
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
if (!Settings.canDrawOverlays(this)) {
|
|
814
|
+
waitingForOverlay = true;
|
|
815
|
+
startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), OVERLAY_REQUEST);
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
ensureMascotRunning();
|
|
819
|
+
Toast.makeText(this, "Mascota activada", Toast.LENGTH_SHORT).show();
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
@Override
|
|
823
|
+
public void onBackPressed() {
|
|
824
|
+
if (webView != null && webView.canGoBack()) webView.goBack(); else super.onBackPressed();
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
@Override
|
|
828
|
+
protected void onDestroy() {
|
|
829
|
+
travelBanner = null;
|
|
830
|
+
if (webView != null) {
|
|
831
|
+
webView.stopLoading();
|
|
832
|
+
webView.destroy();
|
|
833
|
+
}
|
|
834
|
+
super.onDestroy();
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
private EditText input(String hint) {
|
|
838
|
+
EditText input = new EditText(this);
|
|
839
|
+
input.setHint(hint);
|
|
840
|
+
input.setHintTextColor(Color.GRAY);
|
|
841
|
+
input.setTextColor(Color.WHITE);
|
|
842
|
+
input.setSingleLine(true);
|
|
843
|
+
input.setPadding(dp(14), dp(12), dp(14), dp(12));
|
|
844
|
+
input.setBackgroundColor(PANEL);
|
|
845
|
+
return input;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
private Button button(String label) {
|
|
849
|
+
Button button = new Button(this);
|
|
850
|
+
button.setText(label);
|
|
851
|
+
button.setTextColor(Color.rgb(10, 20, 17));
|
|
852
|
+
button.setBackgroundColor(GREEN);
|
|
853
|
+
button.setAllCaps(false);
|
|
854
|
+
return button;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
private TextView text(String value, int sp, int color) {
|
|
858
|
+
TextView view = new TextView(this);
|
|
859
|
+
view.setText(value);
|
|
860
|
+
view.setTextSize(sp);
|
|
861
|
+
view.setTextColor(color);
|
|
862
|
+
return view;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
private LinearLayout.LayoutParams matchWrap() {
|
|
866
|
+
return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
private int dp(int value) {
|
|
870
|
+
return Math.round(value * getResources().getDisplayMetrics().density);
|
|
871
|
+
}
|
|
872
|
+
}
|