From 53e612e2218ccf0cbff4bc9d54dafd2ec3cedc51 Mon Sep 17 00:00:00 2001 From: Wowieee4 Date: Thu, 7 May 2026 10:22:06 +0700 Subject: [PATCH] api update and flutter update --- assets/api-path-collection.json | 1701 +++++++++++++++++ .../walkguide_app/lib/app/app.dart | 0 .../lib/app/injection_container.dart | 38 + .../walkguide_app/lib/app/router.dart | 110 ++ .../lib/core/constants/app_constants.dart | 44 + .../lib/core/errors/failures.dart | 36 + .../lib/core/network/api_client.dart | 100 + .../lib/core/services/haptic_service.dart | 37 + .../lib/core/services/stt_service.dart | 54 + .../lib/core/services/tts_service.dart | 61 + .../core/services/voice_command_handler.dart | 75 + .../lib/core/storage/secure_storage.dart | 41 + .../lib/features/auth/login_screen.dart | 69 + .../lib/features/auth/register_screen.dart | 165 ++ .../lib/features/auth/splash_screen.dart | 69 + .../server_connect/server_connect_server.dart | 184 ++ .../walk_guide/walk_guide_screen.dart | 137 ++ walkguide-mobile/walkguide_app/lib/main.dart | 41 +- .../flutter/generated_plugin_registrant.cc | 8 + .../linux/flutter/generated_plugins.cmake | 3 + .../Flutter/GeneratedPluginRegistrant.swift | 36 +- walkguide-mobile/walkguide_app/pubspec.lock | 1353 ++++++++++++- walkguide-mobile/walkguide_app/pubspec.yaml | 162 +- .../flutter/generated_plugin_registrant.cc | 30 + .../windows/flutter/generated_plugins.cmake | 11 + 25 files changed, 4423 insertions(+), 142 deletions(-) create mode 100644 assets/api-path-collection.json create mode 100644 walkguide-mobile/walkguide_app/lib/app/app.dart create mode 100644 walkguide-mobile/walkguide_app/lib/app/injection_container.dart create mode 100644 walkguide-mobile/walkguide_app/lib/app/router.dart create mode 100644 walkguide-mobile/walkguide_app/lib/core/constants/app_constants.dart create mode 100644 walkguide-mobile/walkguide_app/lib/core/errors/failures.dart create mode 100644 walkguide-mobile/walkguide_app/lib/core/network/api_client.dart create mode 100644 walkguide-mobile/walkguide_app/lib/core/services/haptic_service.dart create mode 100644 walkguide-mobile/walkguide_app/lib/core/services/stt_service.dart create mode 100644 walkguide-mobile/walkguide_app/lib/core/services/tts_service.dart create mode 100644 walkguide-mobile/walkguide_app/lib/core/services/voice_command_handler.dart create mode 100644 walkguide-mobile/walkguide_app/lib/core/storage/secure_storage.dart create mode 100644 walkguide-mobile/walkguide_app/lib/features/auth/login_screen.dart create mode 100644 walkguide-mobile/walkguide_app/lib/features/auth/register_screen.dart create mode 100644 walkguide-mobile/walkguide_app/lib/features/auth/splash_screen.dart create mode 100644 walkguide-mobile/walkguide_app/lib/features/server_connect/server_connect_server.dart create mode 100644 walkguide-mobile/walkguide_app/lib/features/walk_guide/walk_guide_screen.dart diff --git a/assets/api-path-collection.json b/assets/api-path-collection.json new file mode 100644 index 0000000..be1aceb --- /dev/null +++ b/assets/api-path-collection.json @@ -0,0 +1,1701 @@ +{ + "meta": { + "format": "httpie", + "version": "1.0.0", + "contentType": "collection", + "schema": "https://schema.httpie.io/1.0.0.json", + "docs": "https://httpie.io/r/help/export-from-httpie", + "source": "HTTPie Desktop 2025.2.0" + }, + "entry": { + "name": "final-project-uas-v2", + "icon": { + "name": "default", + "color": "red" + }, + "auth": { + "type": "none" + }, + "requests": [ + { + "name": "Auth — /api/v1/auth", + "url": "", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "inherited" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Cek Server Hidup", + "url": "http://localhost:8080/api/v1/auth/ping", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "inherited" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Register Akun Baru (GUARDIAN)", + "url": "http://localhost:8080/api/v1/auth/login", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "inherited" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"email\": \"guardian@test.com\",\n \"password\": \"password123\",\n \"displayName\": \"Guardian Satu\",\n \"role\": \"GUARDIAN\"\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Register Akun Baru (USER)", + "url": "http://localhost:8080/api/v1/auth/register", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "inherited" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"email\": \"user@test.com\",\n \"password\": \"password123\",\n \"displayName\": \"User Satu\",\n \"role\": \"USER\"\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Login Get Token (USER)", + "url": "http://localhost:8080/api/v1/auth/login", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "inherited" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"email\": \"user@test.com\",\n \"password\": \"password123\",\n \"displayName\": \"User Satu\",\n \"role\": \"USER\"\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Login Get Token (GUARDIAN)", + "url": "http://localhost:8080/api/v1/auth/login", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "inherited" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"email\": \"guardian@test.com\",\n \"password\": \"password123\"\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Refresh Token (GUARDIAN)", + "url": "http://localhost:8080/api/v1/auth/refresh", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "inherited" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"refreshToken\": \"1a66db59-fd2d-496d-bd6e-057e1ededc18-cfe94ef3-c1e3-4cd0-b9b5-9ab4eaf91e18\"\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Logout (GUARDIAN)", + "url": "http://localhost:8080/api/v1/auth/logout", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjE3NDksImV4cCI6MTc3ODEyNTM0OX0.SCN8gudz9RnzfLIOtzwPESBsI4sHKmwYKEC8mlDDDP0" + }, + "target": "headers" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Update FCM Token (USER)", + "url": "http://localhost:8080/api/v1/auth/fcm-token", + "method": "PUT", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "inherited" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"fcmToken\": \"fcm_device_token_dari_firebase_sdk\"\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Pairing — /api/v1/shared/pairing", + "url": "", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "inherited" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Guardian Invite User", + "url": "http://localhost:8080/api/v1/shared/pairing/invite", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjE3NDksImV4cCI6MTc3ODEyNTM0OX0.SCN8gudz9RnzfLIOtzwPESBsI4sHKmwYKEC8mlDDDP0" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"uniqueUserId\": \"EO7JZKK19Z9A\"\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Accept or Deny Invite (USER)", + "url": "http://localhost:8080/api/v1/shared/pairing/respond", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"pairingId\": 1,\n \"accept\": true\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Unpair (GUARDIAN)", + "url": "http://localhost:8080/api/v1/shared/pairing/unpair", + "method": "DELETE", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjE3NDksImV4cCI6MTc3ODEyNTM0OX0.SCN8gudz9RnzfLIOtzwPESBsI4sHKmwYKEC8mlDDDP0" + }, + "target": "headers" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Check Pairing Status (GUARDIAN)", + "url": "http://localhost:8080/api/v1/shared/pairing/status", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjE3NDksImV4cCI6MTc3ODEyNTM0OX0.SCN8gudz9RnzfLIOtzwPESBsI4sHKmwYKEC8mlDDDP0" + }, + "target": "headers" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "User endpoints — /api/v1/user (ROLE_USER)", + "url": "", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "inherited" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "User Own Profile", + "url": "http://localhost:8080/api/v1/user/profile", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "User Location", + "url": "http://localhost:8080/api/v1/user/location", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"lat\": -7.2575,\n \"lng\": 112.7521,\n \"accuracy\": 5.0,\n \"speed\": 1.2,\n \"heading\": 270.0\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "YOLO Log Obstacle", + "url": "http://localhost:8080/api/v1/user/obstacle", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"label\": \"person\",\n \"confidence\": 0.87,\n \"direction\": \"CENTER\",\n \"estimatedDist\": \"Very Close\",\n \"lat\": -7.2575,\n \"lng\": 112.7521\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Trigger SOS Alert (USER)", + "url": "http://localhost:8080/api/v1/user/sos", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"triggerType\": \"MANUAL\",\n \"lat\": -7.2575,\n \"lng\": 112.7521\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "WalkGuide START Log", + "url": "http://localhost:8080/api/v1/user/walkguide/start", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "WalkGuide STOP Log", + "url": "http://localhost:8080/api/v1/user/walkguide/stop", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Log User Activity", + "url": "http://localhost:8080/api/v1/user/activity-logs?page=0&size=20", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "List User Notification", + "url": "http://localhost:8080/api/v1/user/notifications?page=0&size=20", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Unread Notif Count (USER)", + "url": "http://localhost:8080/api/v1/user/notifications/unread-count", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Read All Notif Function Mark (USER)", + "url": "http://localhost:8080/api/v1/user/notifications/mark-all-read", + "method": "PUT", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Only Mark 1 Notif Read (USER)", + "url": "http://localhost:8080/api/v1/user/notifications/5/read", + "method": "PUT", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Take User Setting", + "url": "http://localhost:8080/api/v1/user/settings", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Updates User Setting", + "url": "http://localhost:8080/api/v1/user/settings", + "method": "PUT", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"ttsLanguage\": \"id-ID\",\n \"warnNoGuardian\": true,\n \"hapticEnabled\": true\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "List Voice Commands (USER)", + "url": "http://localhost:8080/api/v1/user/voice-commands", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"ttsLanguage\": \"id-ID\",\n \"warnNoGuardian\": true,\n \"hapticEnabled\": true\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "List All Shortcut (USER)", + "url": "http://localhost:8080/api/v1/user/shortcuts", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"ttsLanguage\": \"id-ID\",\n \"warnNoGuardian\": true,\n \"hapticEnabled\": true\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Update Shortcut (USER)", + "url": "http://localhost:8080/api/v1/user/shortcuts", + "method": "PUT", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"shortcutKey\": \"CALL_GUARDIAN\",\n \"buttonName\": \"Volume Up\",\n \"buttonCode\": 24,\n \"enabled\": true\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Check AI Config (USER)", + "url": "http://localhost:8080/api/v1/user/ai-config", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9VU0VSIiwidXNlcklkIjo4LCJzdWIiOiJ1c2VyQHRlc3QuY29tIiwiaWF0IjoxNzc4MTIyNTAyLCJleHAiOjE3NzgxMjYxMDJ9.Wr1mVj0nk7M-OMEwoIZScDHabw4Y3Po3ToW4e10It3w" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Guardian endpoints — /api/v1/guardian (ROLE_GUARDIAN)", + "url": "", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "inherited" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Home Data (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/dashboard ", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Get User Location (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/user-location", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "See User History (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/location-history?page=0&size=50", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "User Activity Log (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/activity-logs?page=0&size=20", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Log User Obstacle (USER)", + "url": "http://localhost:8080/api/v1/guardian/obstacle-logs?page=0&size=20", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "none", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Send Notif to User (GUARDIAN)", + "url": " http://localhost:8080/api/v1/guardian/notifications/send", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"notifType\": \"TEXT\",\n \"content\": \"Hati-hati, ada jalan rusak di depanmu\"\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Send Notif to User AUDIO (GUARDIAN)", + "url": " http://localhost:8080/api/v1/guardian/notifications/send", + "method": "POST", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"notifType\": \"VOICE_NOTE\",\n \"voiceNoteUrl\": \"https://example.com/audio/note.m4a\",\n \"voiceNoteDuration\": 15\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Lihat SOS dari User (Guardian)", + "url": "http://localhost:8080/api/v1/guardian/sos-events?page=0&size=20", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Acknowledge SOS (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/sos/3/acknowledge", + "method": "PUT", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "See AI Config (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/ai-config", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Update AI Config YOLO (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/ai-config", + "method": "PUT", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"confidenceThreshold\": 0.6,\n \"alertDistanceClose\": 1.5,\n \"alertDistanceMedium\": 3.0,\n \"maxInferenceFps\": 5,\n \"enabledLabels\": \"ALL\"\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "List CMD Voice User (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/voice-commands", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Update Voice Trigger Phase (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/voice-commands", + "method": "PUT", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"commandKey\": \"START_WALKGUIDE\",\n \"triggerPhrase\": \"mulai walkguide\",\n \"enabled\": true\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "List USER Shortcut (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/shortcuts", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "See Geofence Config (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/geofence", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Set Geofence Area (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/geofence", + "method": "PUT", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"centerLat\": -7.2575,\n \"centerLng\": 112.7521,\n \"radiusMeters\": 200.0,\n \"enabled\": true\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "See USER TTS Settings (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/user-settings ", + "method": "GET", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + }, + { + "name": "Update USER TTS Settings (GUARDIAN)", + "url": "http://localhost:8080/api/v1/guardian/user-settings ", + "method": "PUT", + "headers": [], + "queryParams": [], + "pathParams": [], + "auth": { + "type": "bearer", + "credentials": { + "username": "", + "password": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiUk9MRV9HVUFSRElBTiIsInVzZXJJZCI6Nywic3ViIjoiZ3VhcmRpYW5AdGVzdC5jb20iLCJpYXQiOjE3NzgxMjIxNTAsImV4cCI6MTc3ODEyNTc1MH0.CxmnZ4m_5M9sdU2tpC8z1PY8W1dHtfWWMDWa1lrd9sk" + }, + "target": "headers" + }, + "body": { + "type": "text", + "file": { + "name": "" + }, + "text": { + "value": "{\n \"ttsLanguage\": \"id-ID\",\n \"ttsPitch\": 1.0,\n \"ttsSpeed\": 0.9,\n \"warnNoGuardian\": true,\n \"hapticEnabled\": true\n}", + "format": "application/json" + }, + "form": { + "isMultipart": false, + "fields": [] + }, + "graphql": { + "query": "", + "variables": "" + } + } + } + ] + } +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/app/app.dart b/walkguide-mobile/walkguide_app/lib/app/app.dart new file mode 100644 index 0000000..e69de29 diff --git a/walkguide-mobile/walkguide_app/lib/app/injection_container.dart b/walkguide-mobile/walkguide_app/lib/app/injection_container.dart new file mode 100644 index 0000000..c14477f --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/app/injection_container.dart @@ -0,0 +1,38 @@ +import 'package:get_it/get_it.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'core/constants/app_constants.dart'; +import 'core/network/api_client.dart'; +import 'core/storage/secure_storage.dart'; +import 'core/services/tts_service.dart'; +import 'core/services/stt_service.dart'; +import 'core/services/voice_command_handler.dart'; +import 'core/services/haptic_service.dart'; + +final sl = GetIt.instance; + +Future initDependencies() async { + // ── Core singletons ────────────────────────────────────────────────────── + sl.registerLazySingleton(() => SecureStorage()); + sl.registerLazySingleton(() => ApiClient(sl())); + + sl.registerLazySingleton(() => TtsService()); + sl.registerLazySingleton(() => SttService()); + sl.registerLazySingleton(() => HapticService()); + sl.registerLazySingleton( + () => VoiceCommandHandler(sl(), sl()), + ); + + // ── Init ApiClient if serverUrl already saved ───────────────────────────── + final serverUrl = await AppConstants.getServerUrl(); + if (serverUrl != null && serverUrl.isNotEmpty) { + await sl().init(serverUrl); + } + + // ── Init TTS ────────────────────────────────────────────────────────────── + await sl().init(); + + // ── Init STT ────────────────────────────────────────────────────────────── + await sl().init(); + sl().loadDefaultCommands(); +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/app/router.dart b/walkguide-mobile/walkguide_app/lib/app/router.dart new file mode 100644 index 0000000..cbc1aeb --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/app/router.dart @@ -0,0 +1,110 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +import 'core/storage/secure_storage.dart'; +import 'core/constants/app_constants.dart'; +import 'injection_container.dart'; + +// Auth +import 'features/server_connect/presentation/screens/server_connect_screen.dart'; +import 'features/auth/presentation/screens/splash_screen.dart'; +import 'features/auth/presentation/screens/login_screen.dart'; +import 'features/auth/presentation/screens/register_screen.dart'; + +// User shell + screens +import 'shared/widgets/user_shell.dart'; +import 'features/walk_guide/presentation/screens/walk_guide_screen.dart'; +import 'features/sos/presentation/screens/sos_screen.dart'; +import 'features/activity_log/presentation/screens/activity_log_screen.dart'; +import 'features/notifications/presentation/screens/notification_screen.dart'; +import 'features/navigation_mode/presentation/screens/navigation_mode_screen.dart'; +import 'features/settings/presentation/screens/user_settings_screen.dart'; + +// Guardian shell + screens +import 'shared/widgets/guardian_shell.dart'; +import 'features/guardian/presentation/screens/guardian_dashboard_screen.dart'; +import 'features/guardian/presentation/screens/guardian_map_screen.dart'; +import 'features/guardian/presentation/screens/guardian_activity_log_screen.dart'; +import 'features/guardian/presentation/screens/guardian_send_notif_screen.dart'; +import 'features/guardian/presentation/screens/guardian_ai_config_screen.dart'; +import 'features/guardian/presentation/screens/guardian_voice_cmd_screen.dart'; +import 'features/guardian/presentation/screens/guardian_shortcut_screen.dart'; +import 'features/guardian/presentation/screens/guardian_geofence_screen.dart'; +import 'features/pairing/presentation/screens/guardian_pairing_screen.dart'; +import 'features/pairing/presentation/screens/user_pairing_screen.dart'; + +// Call +import 'features/call/presentation/screens/call_screen.dart'; +import 'features/call/presentation/screens/incoming_call_screen.dart'; + +final GoRouter appRouter = GoRouter( + initialLocation: '/splash', + redirect: (context, state) async { + final serverUrl = await AppConstants.getServerUrl(); + final path = state.matchedLocation; + + // 1. No server URL → must go to server-connect + if (serverUrl == null || serverUrl.isEmpty) { + if (path != '/server-connect') return '/server-connect'; + return null; + } + + // 2. Already on server-connect but has URL → splash + if (path == '/server-connect') return '/splash'; + + return null; + }, + routes: [ + GoRoute( + path: '/server-connect', + builder: (context, state) => const ServerConnectScreen(), + ), + GoRoute( + path: '/splash', + builder: (context, state) => const SplashScreen(), + ), + GoRoute( + path: '/login', + builder: (context, state) => const LoginScreen(), + ), + GoRoute( + path: '/register', + builder: (context, state) => const RegisterScreen(), + ), + GoRoute( + path: '/incoming-call', + builder: (context, state) => const IncomingCallScreen(), + ), + + // ── USER SHELL ────────────────────────────────────────────────────────── + ShellRoute( + builder: (context, state, child) => UserShell(child: child), + routes: [ + GoRoute(path: '/user/walkguide', builder: (c, s) => const WalkGuideScreen()), + GoRoute(path: '/user/sos', builder: (c, s) => const SosScreen()), + GoRoute(path: '/user/activity', builder: (c, s) => const ActivityLogScreen()), + GoRoute(path: '/user/notifications',builder: (c, s) => const NotificationScreen()), + GoRoute(path: '/user/navigation', builder: (c, s) => const NavigationModeScreen()), + GoRoute(path: '/user/settings', builder: (c, s) => const UserSettingsScreen()), + GoRoute(path: '/user/pairing', builder: (c, s) => const UserPairingScreen()), + GoRoute(path: '/user/call', builder: (c, s) => const CallScreen()), + ], + ), + + // ── GUARDIAN SHELL ────────────────────────────────────────────────────── + ShellRoute( + builder: (context, state, child) => GuardianShell(child: child), + routes: [ + GoRoute(path: '/guardian/dashboard', builder: (c, s) => const GuardianDashboardScreen()), + GoRoute(path: '/guardian/map', builder: (c, s) => const GuardianMapScreen()), + GoRoute(path: '/guardian/logs', builder: (c, s) => const GuardianActivityLogScreen()), + GoRoute(path: '/guardian/send-notif', builder: (c, s) => const GuardianSendNotifScreen()), + GoRoute(path: '/guardian/ai-config', builder: (c, s) => const GuardianAiConfigScreen()), + GoRoute(path: '/guardian/voice-cmd', builder: (c, s) => const GuardianVoiceCmdScreen()), + GoRoute(path: '/guardian/shortcuts', builder: (c, s) => const GuardianShortcutScreen()), + GoRoute(path: '/guardian/geofence', builder: (c, s) => const GuardianGeofenceScreen()), + GoRoute(path: '/guardian/pairing', builder: (c, s) => const GuardianPairingScreen()), + ], + ), + ], +); \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/core/constants/app_constants.dart b/walkguide-mobile/walkguide_app/lib/core/constants/app_constants.dart new file mode 100644 index 0000000..00aa885 --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/core/constants/app_constants.dart @@ -0,0 +1,44 @@ +import 'package:shared_preferences/shared_preferences.dart'; + +class AppConstants { + static const String _serverUrlKey = 'server_base_url'; + + // Ambil base URL dari SharedPreferences + static Future getServerUrl() async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString(_serverUrlKey); + } + + // Simpan URL setelah berhasil connect + static Future setServerUrl(String url) async { + final prefs = await SharedPreferences.getInstance(); + // Trim trailing slash + final cleaned = url.endsWith('/') ? url.substring(0, url.length - 1) : url; + await prefs.setString(_serverUrlKey, cleaned); + } + + static Future clearServerUrl() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove(_serverUrlKey); + } + + static String buildApiUrl(String baseUrl) => '$baseUrl/api/v1'; + static String buildWsUrl(String baseUrl) => baseUrl.replaceFirst('http', 'ws') + '/ws'; + + // Timeouts + static const Duration connectTimeout = Duration(seconds: 10); + static const Duration receiveTimeout = Duration(seconds: 30); + static const Duration pingTimeout = Duration(seconds: 5); + + // Location intervals + static const int locationIntervalWalkMs = 5000; + static const int locationIntervalIdleMs = 30000; + + // YOLO + static const String yoloModelPath = 'assets/models/yolov8n.tflite'; + static const String yoloLabelsPath = 'assets/models/labels.txt'; + static const int yoloInputSize = 640; + + // Agora - ganti dengan App ID dari agora.io + static const String agoraAppId = 'YOUR_AGORA_APP_ID'; +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/core/errors/failures.dart b/walkguide-mobile/walkguide_app/lib/core/errors/failures.dart new file mode 100644 index 0000000..ac4c2bf --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/core/errors/failures.dart @@ -0,0 +1,36 @@ +abstract class Failure { + final String message; + const Failure(this.message); +} + +class ServerFailure extends Failure { + const ServerFailure(super.message); +} + +class NetworkFailure extends Failure { + const NetworkFailure(super.message); +} + +class AuthFailure extends Failure { + const AuthFailure(super.message); +} + +class NotFoundFailure extends Failure { + const NotFoundFailure(super.message); +} + +class PairingFailure extends Failure { + const PairingFailure(super.message); +} + +class ValidationFailure extends Failure { + const ValidationFailure(super.message); +} + +class CacheFailure extends Failure { + const CacheFailure(super.message); +} + +class ConnectionFailure extends Failure { + const ConnectionFailure(super.message); +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/core/network/api_client.dart b/walkguide-mobile/walkguide_app/lib/core/network/api_client.dart new file mode 100644 index 0000000..c94717e --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/core/network/api_client.dart @@ -0,0 +1,100 @@ +import 'package:dio/dio.dart'; +import '../constants/app_constants.dart'; +import '../storage/secure_storage.dart'; + +class ApiClient { + late Dio _dio; + final SecureStorage _secureStorage; + String? _baseUrl; + + ApiClient(this._secureStorage); + + Future init(String serverUrl) async { + _baseUrl = AppConstants.buildApiUrl(serverUrl); + _dio = Dio(BaseOptions( + baseUrl: _baseUrl!, + connectTimeout: AppConstants.connectTimeout, + receiveTimeout: AppConstants.receiveTimeout, + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + )); + _dio.interceptors.addAll([ + _AuthInterceptor(_secureStorage, _dio), + _ErrorInterceptor(), + LogInterceptor(requestBody: true, responseBody: true), + ]); + } + + Dio get dio => _dio; + + String? get baseUrl => _baseUrl; +} + +// ── Auth Interceptor: inject token & auto-refresh on 401 ────────────────────── +class _AuthInterceptor extends Interceptor { + final SecureStorage _storage; + final Dio _dio; + bool _refreshing = false; + + _AuthInterceptor(this._storage, this._dio); + + @override + void onRequest(RequestOptions options, RequestInterceptorHandler handler) async { + final token = await _storage.getAccessToken(); + if (token != null) { + options.headers['Authorization'] = 'Bearer $token'; + } + handler.next(options); + } + + @override + void onError(DioException err, ErrorInterceptorHandler handler) async { + if (err.response?.statusCode == 401 && !_refreshing) { + _refreshing = true; + try { + final refresh = await _storage.getRefreshToken(); + if (refresh == null) { + _refreshing = false; + handler.next(err); + return; + } + final res = await _dio.post('/auth/refresh', + data: {'refreshToken': refresh}, + options: Options(headers: {'Authorization': null})); + + if (res.statusCode == 200 && res.data['success'] == true) { + final data = res.data['data']; + await _storage.saveTokens( + accessToken: data['accessToken'], + refreshToken: data['refreshToken'] ?? refresh, + role: data['role'], + userId: data['userId'].toString(), + displayName: data['displayName'], + uniqueUserId: data['uniqueUserId'], + ); + // Retry original request + err.requestOptions.headers['Authorization'] = + 'Bearer ${data['accessToken']}'; + final retryRes = await _dio.fetch(err.requestOptions); + _refreshing = false; + handler.resolve(retryRes); + return; + } + } catch (_) {} + _refreshing = false; + await _storage.clearAll(); + } + handler.next(err); + } +} + +// ── Error Interceptor: normalize errors ─────────────────────────────────────── +class _ErrorInterceptor extends Interceptor { + @override + void onError(DioException err, ErrorInterceptorHandler handler) { + // Let the calling code handle it — just pass through + handler.next(err); + } +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/core/services/haptic_service.dart b/walkguide-mobile/walkguide_app/lib/core/services/haptic_service.dart new file mode 100644 index 0000000..58dc999 --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/core/services/haptic_service.dart @@ -0,0 +1,37 @@ +import 'package:vibration/vibration.dart'; + +class HapticService { + Future get _hasVibrator async => (await Vibration.hasVibrator()) ?? false; + + Future obstacleVeryClose() async { + if (!await _hasVibrator) return; + Vibration.vibrate(pattern: [0, 500, 100, 500, 100, 500]); + } + + Future obstacleClose() async { + if (!await _hasVibrator) return; + Vibration.vibrate(pattern: [0, 300, 100, 300]); + } + + Future obstacleMedium() async { + if (!await _hasVibrator) return; + Vibration.vibrate(duration: 150); + } + + Future sosTriggered() async { + if (!await _hasVibrator) return; + Vibration.vibrate(pattern: [0, 1000, 200, 1000, 200, 1000]); + } + + Future callIncoming() async { + if (!await _hasVibrator) return; + Vibration.vibrate(pattern: [0, 500, 500, 500, 500, 500, 500, 500]); + } + + Future success() async { + if (!await _hasVibrator) return; + Vibration.vibrate(duration: 80); + } + + Future stop() async => Vibration.cancel(); +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/core/services/stt_service.dart b/walkguide-mobile/walkguide_app/lib/core/services/stt_service.dart new file mode 100644 index 0000000..bb49674 --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/core/services/stt_service.dart @@ -0,0 +1,54 @@ +import 'package:speech_to_text/speech_to_text.dart'; + +class SttService { + final SpeechToText _stt = SpeechToText(); + bool _available = false; + bool _listening = false; + Function(String)? onResult; + + Future init() async { + _available = await _stt.initialize( + onError: (e) => _onError(e), + onStatus: (s) => _onStatus(s), + ); + return _available; + } + + Future startListening() async { + if (!_available || _listening) return; + _listening = true; + await _stt.listen( + onResult: (result) { + if (result.finalResult && result.recognizedWords.isNotEmpty) { + onResult?.call(result.recognizedWords.toLowerCase().trim()); + } + }, + listenFor: const Duration(seconds: 10), + pauseFor: const Duration(seconds: 3), + localeId: 'id_ID', + cancelOnError: false, + ); + } + + Future stopListening() async { + _listening = false; + await _stt.stop(); + } + + bool get isListening => _listening; + bool get isAvailable => _available; + + void _onError(dynamic error) { + _listening = false; + // Auto-restart setelah error + Future.delayed(const Duration(seconds: 1), startListening); + } + + void _onStatus(String status) { + if (status == 'done' || status == 'notListening') { + _listening = false; + // Auto-restart agar selalu mendengarkan + Future.delayed(const Duration(milliseconds: 500), startListening); + } + } +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/core/services/tts_service.dart b/walkguide-mobile/walkguide_app/lib/core/services/tts_service.dart new file mode 100644 index 0000000..13c04a7 --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/core/services/tts_service.dart @@ -0,0 +1,61 @@ +import 'package:flutter_tts/flutter_tts.dart'; + +class TtsService { + final FlutterTts _tts = FlutterTts(); + final List _queue = []; + bool _speaking = false; + String _lastSpoken = ''; + + Future init({String language = 'id-ID', double pitch = 1.0, double rate = 0.5}) async { + await _tts.setLanguage(language); + await _tts.setPitch(pitch); + await _tts.setSpeechRate(rate); + await _tts.setVolume(1.0); + _tts.setCompletionHandler(() { + _speaking = false; + _processQueue(); + }); + } + + /// Tambah ke antrian - tidak memotong yg sedang bicara + void speak(String text) { + if (text.isEmpty) return; + _queue.add(text); + if (!_speaking) _processQueue(); + } + + /// Potong TTS sekarang dan langsung ucapkan ini - untuk obstacle alert + Future speakImmediate(String text) async { + if (text.isEmpty) return; + _queue.clear(); + await _tts.stop(); + _speaking = true; + _lastSpoken = text; + await _tts.speak(text); + } + + Future stop() async { + _queue.clear(); + _speaking = false; + await _tts.stop(); + } + + String get lastSpoken => _lastSpoken; + bool get isSpeaking => _speaking; + + Future setLanguage(String lang) async => _tts.setLanguage(lang); + Future setPitch(double pitch) async => _tts.setPitch(pitch); + Future setRate(double rate) async => _tts.setSpeechRate(rate); + + void repeatLast() { + if (_lastSpoken.isNotEmpty) speak(_lastSpoken); + } + + void _processQueue() { + if (_queue.isEmpty || _speaking) return; + final text = _queue.removeAt(0); + _speaking = true; + _lastSpoken = text; + _tts.speak(text); + } +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/core/services/voice_command_handler.dart b/walkguide-mobile/walkguide_app/lib/core/services/voice_command_handler.dart new file mode 100644 index 0000000..884cc82 --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/core/services/voice_command_handler.dart @@ -0,0 +1,75 @@ +import 'package:get_it/get_it.dart'; +import 'tts_service.dart'; +import 'stt_service.dart'; + +enum VoiceCommandKey { + openWalkguide, startWalkguide, stopWalkguide, + callGuardian, openNotification, readAllNotif, + openSos, sendSos, whereAmI, + openActivity, openNavigation, openSettings, + repeatLast, stopTts, +} + +class VoiceCommand { + final VoiceCommandKey key; + final String phrase; + final bool enabled; + const VoiceCommand({required this.key, required this.phrase, required this.enabled}); +} + +/// Callback yang dipanggil saat command terdeteksi +/// Registered oleh router/screen yang relevan +typedef CommandCallback = void Function(VoiceCommandKey key); + +class VoiceCommandHandler { + final SttService _stt; + final TtsService _tts; + + List _commands = []; + CommandCallback? onCommand; + + VoiceCommandHandler(this._stt, this._tts); + + void loadCommands(List commands) { + _commands = commands; + _stt.onResult = _processText; + } + + void loadDefaultCommands() { + _commands = const [ + VoiceCommand(key: VoiceCommandKey.openWalkguide, phrase: 'open walkguide', enabled: true), + VoiceCommand(key: VoiceCommandKey.startWalkguide, phrase: 'start walkguide', enabled: true), + VoiceCommand(key: VoiceCommandKey.stopWalkguide, phrase: 'stop walkguide', enabled: true), + VoiceCommand(key: VoiceCommandKey.callGuardian, phrase: 'call guardian', enabled: true), + VoiceCommand(key: VoiceCommandKey.openNotification, phrase: 'open notifications', enabled: true), + VoiceCommand(key: VoiceCommandKey.readAllNotif, phrase: 'read all my notifications', enabled: true), + VoiceCommand(key: VoiceCommandKey.openSos, phrase: 'open sos', enabled: true), + VoiceCommand(key: VoiceCommandKey.sendSos, phrase: 'send sos', enabled: true), + VoiceCommand(key: VoiceCommandKey.whereAmI, phrase: 'where am i', enabled: true), + VoiceCommand(key: VoiceCommandKey.openActivity, phrase: 'open activity log', enabled: true), + VoiceCommand(key: VoiceCommandKey.openNavigation, phrase: 'open navigation', enabled: true), + VoiceCommand(key: VoiceCommandKey.openSettings, phrase: 'open settings', enabled: true), + VoiceCommand(key: VoiceCommandKey.repeatLast, phrase: 'repeat', enabled: true), + VoiceCommand(key: VoiceCommandKey.stopTts, phrase: 'stop', enabled: true), + ]; + _stt.onResult = _processText; + } + + void _processText(String text) { + final lower = text.toLowerCase().trim(); + for (final cmd in _commands) { + if (!cmd.enabled) continue; + if (lower.contains(cmd.phrase.toLowerCase())) { + _handleCommand(cmd.key); + return; + } + } + } + + void _handleCommand(VoiceCommandKey key) { + onCommand?.call(key); + // Built-in actions for TTS-only commands + if (key == VoiceCommandKey.repeatLast) _tts.repeatLast(); + if (key == VoiceCommandKey.stopTts) _tts.stop(); + } +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/core/storage/secure_storage.dart b/walkguide-mobile/walkguide_app/lib/core/storage/secure_storage.dart new file mode 100644 index 0000000..b13f5d1 --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/core/storage/secure_storage.dart @@ -0,0 +1,41 @@ +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +class SecureStorage { + static const _storage = FlutterSecureStorage( + aOptions: AndroidOptions(encryptedSharedPreferences: true), + ); + + static const _keyAccess = 'access_token'; + static const _keyRefresh = 'refresh_token'; + static const _keyRole = 'user_role'; + static const _keyUserId = 'user_id'; + static const _keyName = 'display_name'; + static const _keyUid = 'unique_user_id'; + + Future saveTokens({ + required String accessToken, + required String refreshToken, + required String role, + required String userId, + String? displayName, + String? uniqueUserId, + }) async { + await Future.wait([ + _storage.write(key: _keyAccess, value: accessToken), + _storage.write(key: _keyRefresh, value: refreshToken), + _storage.write(key: _keyRole, value: role), + _storage.write(key: _keyUserId, value: userId), + if (displayName != null) _storage.write(key: _keyName, value: displayName), + if (uniqueUserId != null) _storage.write(key: _keyUid, value: uniqueUserId), + ]); + } + + Future getAccessToken() async => _storage.read(key: _keyAccess); + Future getRefreshToken() async => _storage.read(key: _keyRefresh); + Future getUserRole() async => _storage.read(key: _keyRole); + Future getUserId() async => _storage.read(key: _keyUserId); + Future getDisplayName() async => _storage.read(key: _keyName); + Future getUniqueUserId() async => _storage.read(key: _keyUid); + + Future clearAll() async => _storage.deleteAll(); +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/features/auth/login_screen.dart b/walkguide-mobile/walkguide_app/lib/features/auth/login_screen.dart new file mode 100644 index 0000000..da5973e --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/features/auth/login_screen.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import '../../../../core/storage/secure_storage.dart'; +import '../../../../core/services/tts_service.dart'; +import '../../../../injection_container.dart'; + +class SplashScreen extends StatefulWidget { + const SplashScreen({super.key}); + + @override + State createState() => _SplashScreenState(); +} + +class _SplashScreenState extends State { + @override + void initState() { + super.initState(); + _checkAuth(); + } + + Future _checkAuth() async { + await Future.delayed(const Duration(milliseconds: 800)); + final storage = sl(); + final token = await storage.getAccessToken(); + final role = await storage.getUserRole(); + + if (!mounted) return; + + if (token == null || role == null) { + context.go('/login'); + return; + } + + final name = await storage.getDisplayName() ?? 'kembali'; + sl().speak('Selamat datang, $name'); + + if (role == 'ROLE_GUARDIAN') { + context.go('/guardian/dashboard'); + } else { + context.go('/user/walkguide'); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFF1A56DB), + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 80, height: 80, + decoration: BoxDecoration(color: Colors.white.withOpacity(0.15), borderRadius: BorderRadius.circular(20)), + child: const Icon(Icons.navigation_rounded, color: Colors.white, size: 44), + ), + const SizedBox(height: 20), + Text('WalkGuide', style: GoogleFonts.outfit(fontSize: 32, fontWeight: FontWeight.w700, color: Colors.white)), + const SizedBox(height: 8), + Text('AI Navigation Assistant', style: GoogleFonts.inter(fontSize: 14, color: Colors.white60)), + const SizedBox(height: 48), + const CircularProgressIndicator(color: Colors.white54, strokeWidth: 2), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/features/auth/register_screen.dart b/walkguide-mobile/walkguide_app/lib/features/auth/register_screen.dart new file mode 100644 index 0000000..4d2e82d --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/features/auth/register_screen.dart @@ -0,0 +1,165 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:dio/dio.dart'; + +import '../../../../core/network/api_client.dart'; +import '../../../../core/storage/secure_storage.dart'; +import '../../../../core/services/tts_service.dart'; +import '../../../../injection_container.dart'; + +class RegisterScreen extends StatefulWidget { + const RegisterScreen({super.key}); + @override + State createState() => _RegisterScreenState(); +} + +class _RegisterScreenState extends State { + final _nameCtrl = TextEditingController(); + final _emailCtrl = TextEditingController(); + final _passCtrl = TextEditingController(); + String _selectedRole = ''; + bool _loading = false; + + Future _register() async { + if (_selectedRole.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Pilih tipe akun dulu'))); + return; + } + setState(() => _loading = true); + try { + final res = await sl().dio.post('/auth/register', data: { + 'email': _emailCtrl.text.trim(), + 'password': _passCtrl.text.trim(), + 'displayName': _nameCtrl.text.trim(), + 'role': _selectedRole, + }); + if (res.statusCode == 200 && res.data['success'] == true) { + final data = res.data['data']; + await sl().saveTokens( + accessToken: data['accessToken'], + refreshToken: data['refreshToken'], + role: data['role'], + userId: data['userId'].toString(), + displayName: data['displayName'], + uniqueUserId: data['uniqueUserId'], + ); + if (!mounted) return; + final isUser = data['role'] == 'ROLE_USER'; + if (isUser) { + final uid = data['uniqueUserId'] ?? ''; + sl().speak('Registrasi berhasil. ID kamu adalah ${uid.split('').join(' ')}. Bagikan ID ini ke Guardian kamu.'); + } else { + sl().speak('Registrasi berhasil. Selamat datang, ${data['displayName']}'); + } + context.go(isUser ? '/user/walkguide' : '/guardian/dashboard'); + } + } on DioException catch (e) { + final msg = e.response?.data['message'] ?? 'Registrasi gagal'; + if (mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg), backgroundColor: Colors.redAccent)); + } finally { + if (mounted) setState(() => _loading = false); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFFF1F5F9), + body: Center( + child: SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: Container( + constraints: const BoxConstraints(maxWidth: 440), + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20), + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.08), blurRadius: 40, offset: const Offset(0, 16))]), + padding: const EdgeInsets.all(32), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text('Buat Akun', style: GoogleFonts.outfit(fontSize: 26, fontWeight: FontWeight.w700)), + const SizedBox(height: 6), + Text('Pilih tipe akun kamu', style: GoogleFonts.inter(fontSize: 13, color: const Color(0xFF64748B))), + const SizedBox(height: 24), + + // Role selector cards + Row(children: [ + _roleCard('GUARDIAN', Icons.shield_outlined, 'Guardian', 'Saya akan membimbing seseorang'), + const SizedBox(width: 12), + _roleCard('USER', Icons.accessibility_new_rounded, 'User', 'Saya butuh bantuan navigasi'), + ]), + const SizedBox(height: 24), + + _field('Nama Lengkap', _nameCtrl, false), + const SizedBox(height: 14), + _field('Email', _emailCtrl, false), + const SizedBox(height: 14), + _field('Password (min. 6 karakter)', _passCtrl, true), + const SizedBox(height: 24), + + SizedBox( + width: double.infinity, height: 44, + child: ElevatedButton( + onPressed: _loading ? null : _register, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A56DB), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + ), + child: _loading + ? const SizedBox(width: 18, height: 18, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2)) + : Text('Daftar Sekarang', style: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.w600, color: Colors.white)), + ), + ), + const SizedBox(height: 14), + Center(child: GestureDetector( + onTap: () => context.go('/login'), + child: Text('Sudah punya akun? Login', style: GoogleFonts.inter(fontSize: 12, color: const Color(0xFF1A56DB))), + )), + ]), + ), + ), + ), + ); + } + + Widget _roleCard(String role, IconData icon, String title, String subtitle) { + final selected = _selectedRole == role; + return Expanded( + child: GestureDetector( + onTap: () => setState(() => _selectedRole = role), + child: AnimatedContainer( + duration: const Duration(milliseconds: 200), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: selected ? const Color(0xFFEFF6FF) : const Color(0xFFF8FAFC), + border: Border.all(color: selected ? const Color(0xFF1A56DB) : const Color(0xFFE2E8F0), width: selected ? 2 : 1), + borderRadius: BorderRadius.circular(12), + ), + child: Column(children: [ + Icon(icon, color: selected ? const Color(0xFF1A56DB) : const Color(0xFF94A3B8), size: 28), + const SizedBox(height: 8), + Text(title, style: GoogleFonts.inter(fontSize: 13, fontWeight: FontWeight.w600, color: selected ? const Color(0xFF1A56DB) : const Color(0xFF0F172A))), + const SizedBox(height: 4), + Text(subtitle, textAlign: TextAlign.center, style: GoogleFonts.inter(fontSize: 10, color: const Color(0xFF94A3B8))), + ]), + ), + ), + ); + } + + Widget _field(String label, TextEditingController ctrl, bool isPass) { + return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text(label, style: GoogleFonts.inter(fontSize: 12, color: const Color(0xFF64748B))), + const SizedBox(height: 5), + TextField( + controller: ctrl, + obscureText: isPass, + style: GoogleFonts.inter(fontSize: 13), + decoration: InputDecoration( + border: OutlineInputBorder(borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFFE2E8F0))), + enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFFE2E8F0))), + focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF1A56DB), width: 2)), + contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + ), + ), + ]); + } +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/features/auth/splash_screen.dart b/walkguide-mobile/walkguide_app/lib/features/auth/splash_screen.dart new file mode 100644 index 0000000..da5973e --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/features/auth/splash_screen.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import '../../../../core/storage/secure_storage.dart'; +import '../../../../core/services/tts_service.dart'; +import '../../../../injection_container.dart'; + +class SplashScreen extends StatefulWidget { + const SplashScreen({super.key}); + + @override + State createState() => _SplashScreenState(); +} + +class _SplashScreenState extends State { + @override + void initState() { + super.initState(); + _checkAuth(); + } + + Future _checkAuth() async { + await Future.delayed(const Duration(milliseconds: 800)); + final storage = sl(); + final token = await storage.getAccessToken(); + final role = await storage.getUserRole(); + + if (!mounted) return; + + if (token == null || role == null) { + context.go('/login'); + return; + } + + final name = await storage.getDisplayName() ?? 'kembali'; + sl().speak('Selamat datang, $name'); + + if (role == 'ROLE_GUARDIAN') { + context.go('/guardian/dashboard'); + } else { + context.go('/user/walkguide'); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFF1A56DB), + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 80, height: 80, + decoration: BoxDecoration(color: Colors.white.withOpacity(0.15), borderRadius: BorderRadius.circular(20)), + child: const Icon(Icons.navigation_rounded, color: Colors.white, size: 44), + ), + const SizedBox(height: 20), + Text('WalkGuide', style: GoogleFonts.outfit(fontSize: 32, fontWeight: FontWeight.w700, color: Colors.white)), + const SizedBox(height: 8), + Text('AI Navigation Assistant', style: GoogleFonts.inter(fontSize: 14, color: Colors.white60)), + const SizedBox(height: 48), + const CircularProgressIndicator(color: Colors.white54, strokeWidth: 2), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/features/server_connect/server_connect_server.dart b/walkguide-mobile/walkguide_app/lib/features/server_connect/server_connect_server.dart new file mode 100644 index 0000000..25a6f54 --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/features/server_connect/server_connect_server.dart @@ -0,0 +1,184 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:dio/dio.dart'; + +import '../../../../core/constants/app_constants.dart'; +import '../../../../injection_container.dart'; +import '../../../../core/network/api_client.dart'; + +class ServerConnectScreen extends StatefulWidget { + const ServerConnectScreen({super.key}); + + @override + State createState() => _ServerConnectScreenState(); +} + +class _ServerConnectScreenState extends State { + final _urlCtrl = TextEditingController(text: 'http://202.46.28.160:8080'); + bool _testing = false; + bool _connected = false; + String? _errorMsg; + String? _serverInfo; + + Future _testConnection() async { + final url = _urlCtrl.text.trim(); + if (url.isEmpty) return; + + setState(() { _testing = true; _connected = false; _errorMsg = null; _serverInfo = null; }); + + try { + final tempDio = Dio(BaseOptions( + connectTimeout: AppConstants.pingTimeout, + receiveTimeout: AppConstants.pingTimeout, + )); + final res = await tempDio.get('$url/api/v1/auth/ping'); + if (res.statusCode == 200 && res.data['success'] == true) { + setState(() { + _connected = true; + _serverInfo = 'Server aktif — ${res.data['message'] ?? 'OK'}'; + }); + } else { + setState(() => _errorMsg = 'Server merespons tapi tidak valid. Cek URL.'); + } + } on DioException catch (e) { + String msg; + if (e.type == DioExceptionType.connectionTimeout || + e.type == DioExceptionType.receiveTimeout) { + msg = 'Koneksi timeout. Pastikan server berjalan dan URL benar.'; + } else if (e.type == DioExceptionType.connectionError) { + msg = 'Tidak bisa terhubung. Cek URL dan pastikan HP di jaringan yang sama dengan server.'; + } else { + msg = 'Error: ${e.message}'; + } + setState(() => _errorMsg = msg); + } catch (e) { + setState(() => _errorMsg = 'Error tidak dikenal: $e'); + } finally { + setState(() => _testing = false); + } + } + + Future _continueToApp() async { + final url = _urlCtrl.text.trim(); + await AppConstants.setServerUrl(url); + await sl().init(url); + if (mounted) context.go('/splash'); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFFF1F5F9), + body: Center( + child: SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: Container( + constraints: const BoxConstraints(maxWidth: 440), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.08), blurRadius: 40, offset: const Offset(0, 16))], + ), + padding: const EdgeInsets.all(32), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Logo + Row(children: [ + Container( + width: 40, height: 40, + decoration: BoxDecoration(color: const Color(0xFF1A56DB), borderRadius: BorderRadius.circular(10)), + child: const Icon(Icons.navigation_rounded, color: Colors.white, size: 22), + ), + const SizedBox(width: 10), + Text('WalkGuide', style: GoogleFonts.outfit(fontSize: 20, fontWeight: FontWeight.w700, color: const Color(0xFF0F172A))), + ]), + const SizedBox(height: 28), + Text('Connect to Server', style: GoogleFonts.outfit(fontSize: 26, fontWeight: FontWeight.w700, color: const Color(0xFF0F172A))), + const SizedBox(height: 6), + Text('Masukkan URL server yang diberikan oleh dosen/instructor.', style: GoogleFonts.inter(fontSize: 13, color: const Color(0xFF64748B))), + const SizedBox(height: 24), + + // URL Input + Text('Server URL', style: GoogleFonts.inter(fontSize: 12, fontWeight: FontWeight.w500, color: const Color(0xFF64748B))), + const SizedBox(height: 6), + TextField( + controller: _urlCtrl, + keyboardType: TextInputType.url, + style: GoogleFonts.inter(fontSize: 14, color: const Color(0xFF0F172A)), + decoration: InputDecoration( + hintText: 'http://202.46.28.160:8080', + hintStyle: GoogleFonts.inter(color: const Color(0xFFCBD5E1)), + border: OutlineInputBorder(borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Color(0xFFE2E8F0))), + enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Color(0xFFE2E8F0))), + focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Color(0xFF1A56DB), width: 2)), + contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), + ), + onChanged: (_) => setState(() { _connected = false; _errorMsg = null; }), + ), + const SizedBox(height: 16), + + // Status + if (_errorMsg != null) + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration(color: const Color(0xFFFEF2F2), borderRadius: BorderRadius.circular(8)), + child: Row(children: [ + const Icon(Icons.error_outline, color: Color(0xFFDC2626), size: 18), + const SizedBox(width: 8), + Expanded(child: Text(_errorMsg!, style: GoogleFonts.inter(fontSize: 12, color: const Color(0xFFDC2626)))), + ]), + ), + if (_connected && _serverInfo != null) + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration(color: const Color(0xFFF0FDF4), borderRadius: BorderRadius.circular(8)), + child: Row(children: [ + const Icon(Icons.check_circle_outline, color: Color(0xFF16A34A), size: 18), + const SizedBox(width: 8), + Expanded(child: Text(_serverInfo!, style: GoogleFonts.inter(fontSize: 12, color: const Color(0xFF16A34A)))), + ]), + ), + const SizedBox(height: 20), + + // Test button + SizedBox( + width: double.infinity, height: 44, + child: OutlinedButton( + onPressed: _testing ? null : _testConnection, + style: OutlinedButton.styleFrom( + side: const BorderSide(color: Color(0xFF1A56DB)), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + ), + child: _testing + ? const SizedBox(width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2)) + : Text('Test Connection', style: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.w500, color: const Color(0xFF1A56DB))), + ), + ), + const SizedBox(height: 10), + + // Continue button (only after successful test) + if (_connected) + SizedBox( + width: double.infinity, height: 44, + child: ElevatedButton( + onPressed: _continueToApp, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1A56DB), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + ), + child: Text('Continue to App', style: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.w600, color: Colors.white)), + ), + ), + + const SizedBox(height: 24), + Center(child: Text('v1.0.0 · For Testing Purposes', style: GoogleFonts.inter(fontSize: 11, color: const Color(0xFFCBD5E1)))), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/features/walk_guide/walk_guide_screen.dart b/walkguide-mobile/walkguide_app/lib/features/walk_guide/walk_guide_screen.dart new file mode 100644 index 0000000..c1de513 --- /dev/null +++ b/walkguide-mobile/walkguide_app/lib/features/walk_guide/walk_guide_screen.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import '../../core/services/voice_command_handler.dart'; +import '../../core/services/stt_service.dart'; +import '../../core/services/tts_service.dart'; +import '../../injection_container.dart'; + +class UserShell extends StatefulWidget { + final Widget child; + const UserShell({super.key, required this.child}); + @override + State createState() => _UserShellState(); +} + +class _UserShellState extends State { + + @override + void initState() { + super.initState(); + _startVoiceListening(); + _setupVoiceCommands(); + } + + void _startVoiceListening() { + sl().startListening(); + } + + void _setupVoiceCommands() { + sl().onCommand = (key) { + if (!mounted) return; + switch (key) { + case VoiceCommandKey.openWalkguide: + context.go('/user/walkguide'); + sl().speak('Walkguide menu opened'); + break; + case VoiceCommandKey.openNotification: + context.go('/user/notifications'); + sl().speak('Notifications opened'); + break; + case VoiceCommandKey.openSos: + context.go('/user/sos'); + sl().speak('SOS menu opened'); + break; + case VoiceCommandKey.openActivity: + context.go('/user/activity'); + sl().speak('Activity log opened'); + break; + case VoiceCommandKey.openNavigation: + context.go('/user/navigation'); + sl().speak('Navigation mode opened'); + break; + case VoiceCommandKey.openSettings: + context.go('/user/settings'); + sl().speak('Settings opened'); + break; + case VoiceCommandKey.callGuardian: + context.go('/user/call'); + break; + case VoiceCommandKey.sendSos: + case VoiceCommandKey.whereAmI: + case VoiceCommandKey.startWalkguide: + case VoiceCommandKey.stopWalkguide: + case VoiceCommandKey.readAllNotif: + // These are handled by individual screens + break; + default: + break; + } + }; + } + + int _tabFromLocation(String location) { + if (location.startsWith('/user/walkguide')) return 0; + if (location.startsWith('/user/sos')) return 1; + if (location.startsWith('/user/activity')) return 2; + if (location.startsWith('/user/notifications')) return 3; + if (location.startsWith('/user/navigation')) return 4; + return 5; + } + + @override + Widget build(BuildContext context) { + final location = GoRouterState.of(context).matchedLocation; + final currentTab = _tabFromLocation(location); + + // Hide bottom nav during full-screen screens + final hideNav = location.startsWith('/user/call') || location.startsWith('/user/pairing'); + + return Scaffold( + body: widget.child, + bottomNavigationBar: hideNav ? null : Container( + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.08), blurRadius: 20, offset: const Offset(0, -4))], + ), + child: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _navItem(context, 0, currentTab, Icons.remove_red_eye_outlined, Icons.remove_red_eye, 'Guide', '/user/walkguide'), + _navItem(context, 1, currentTab, Icons.warning_amber_outlined, Icons.warning_amber, 'SOS', '/user/sos'), + _navItem(context, 2, currentTab, Icons.list_alt_outlined, Icons.list_alt, 'Activity', '/user/activity'), + _navItem(context, 3, currentTab, Icons.notifications_outlined, Icons.notifications, 'Notif', '/user/notifications'), + _navItem(context, 4, currentTab, Icons.map_outlined, Icons.map, 'Navigate', '/user/navigation'), + _navItem(context, 5, currentTab, Icons.settings_outlined, Icons.settings, 'Settings', '/user/settings'), + ], + ), + ), + ), + ), + ); + } + + Widget _navItem(BuildContext ctx, int idx, int current, IconData icon, IconData activeIcon, String label, String route) { + final active = idx == current; + return GestureDetector( + onTap: () => ctx.go(route), + child: AnimatedContainer( + duration: const Duration(milliseconds: 200), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: active ? const Color(0xFFEFF6FF) : Colors.transparent, + borderRadius: BorderRadius.circular(10), + ), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + Icon(active ? activeIcon : icon, size: 22, color: active ? const Color(0xFF1A56DB) : const Color(0xFF94A3B8)), + const SizedBox(height: 3), + Text(label, style: GoogleFonts.inter(fontSize: 10, fontWeight: active ? FontWeight.w600 : FontWeight.w400, + color: active ? const Color(0xFF1A56DB) : const Color(0xFF94A3B8))), + ]), + ), + ); + } +} \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/lib/main.dart b/walkguide-mobile/walkguide_app/lib/main.dart index 0c15adb..8e25c7e 100644 --- a/walkguide-mobile/walkguide_app/lib/main.dart +++ b/walkguide-mobile/walkguide_app/lib/main.dart @@ -1,39 +1,30 @@ import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:camera/camera.dart'; -import 'features/auth/presentation/login_screen.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'injection_container.dart'; +import 'app/app.dart'; -// Variabel global buat nyimpen daftar kamera di HP List cameras = []; Future main() async { - // Wajib dipanggil sebelum inisialisasi hardware WidgetsFlutterBinding.ensureInitialized(); - - // Ambil daftar kamera yang ada di HP + + // Init cameras try { cameras = await availableCameras(); } catch (e) { - debugPrint('Error inisialisasi kamera: $e'); + debugPrint('Camera init error: $e'); } + // Init Firebase (skip jika belum setup google-services.json) + try { + await Firebase.initializeApp(); + } catch (e) { + debugPrint('Firebase init skipped: $e'); + } + + // Init GetIt dependencies + await initDependencies(); + runApp(const WalkGuideApp()); -} - -class WalkGuideApp extends StatelessWidget { - const WalkGuideApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Walk Guide', - debugShowCheckedModeBanner: false, - theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF2563EB)), - textTheme: GoogleFonts.interTextTheme(), - useMaterial3: true, - ), - home: const LoginScreen(), - ); - } } \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/linux/flutter/generated_plugin_registrant.cc b/walkguide-mobile/walkguide_app/linux/flutter/generated_plugin_registrant.cc index d0e7f79..4088865 100644 --- a/walkguide-mobile/walkguide_app/linux/flutter/generated_plugin_registrant.cc +++ b/walkguide-mobile/walkguide_app/linux/flutter/generated_plugin_registrant.cc @@ -7,9 +7,17 @@ #include "generated_plugin_registrant.h" #include +#include +#include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); + g_autoptr(FlPluginRegistrar) record_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "RecordLinuxPlugin"); + record_linux_plugin_register_with_registrar(record_linux_registrar); + g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin"); + sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar); } diff --git a/walkguide-mobile/walkguide_app/linux/flutter/generated_plugins.cmake b/walkguide-mobile/walkguide_app/linux/flutter/generated_plugins.cmake index b29e9ba..1a53f44 100644 --- a/walkguide-mobile/walkguide_app/linux/flutter/generated_plugins.cmake +++ b/walkguide-mobile/walkguide_app/linux/flutter/generated_plugins.cmake @@ -4,9 +4,12 @@ list(APPEND FLUTTER_PLUGIN_LIST flutter_secure_storage_linux + record_linux + sqlite3_flutter_libs ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + tflite_flutter ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/walkguide-mobile/walkguide_app/macos/Flutter/GeneratedPluginRegistrant.swift b/walkguide-mobile/walkguide_app/macos/Flutter/GeneratedPluginRegistrant.swift index 61d01d0..6017910 100644 --- a/walkguide-mobile/walkguide_app/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/walkguide-mobile/walkguide_app/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,42 @@ import FlutterMacOS import Foundation -import flutter_secure_storage_darwin +import agora_rtc_engine +import audio_session +import connectivity_plus +import device_info_plus +import firebase_core +import firebase_messaging +import flutter_local_notifications +import flutter_secure_storage_macos +import flutter_tts +import geolocator_apple +import iris_method_channel +import just_audio import path_provider_foundation +import record_darwin +import shared_preferences_foundation +import speech_to_text +import sqflite_darwin +import sqlite3_flutter_libs func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin")) + AgoraRtcNgPlugin.register(with: registry.registrar(forPlugin: "AgoraRtcNgPlugin")) + AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) + ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) + FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) + FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) + FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin")) + GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) + IrisMethodChannelPlugin.register(with: registry.registrar(forPlugin: "IrisMethodChannelPlugin")) + JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + RecordPlugin.register(with: registry.registrar(forPlugin: "RecordPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SpeechToTextPlugin.register(with: registry.registrar(forPlugin: "SpeechToTextPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) + Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) } diff --git a/walkguide-mobile/walkguide_app/pubspec.lock b/walkguide-mobile/walkguide_app/pubspec.lock index d386e1c..e1d099e 100644 --- a/walkguide-mobile/walkguide_app/pubspec.lock +++ b/walkguide-mobile/walkguide_app/pubspec.lock @@ -1,14 +1,54 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - animate_do: - dependency: "direct main" + _fe_analyzer_shared: + dependency: transitive description: - name: animate_do - sha256: ddc9bde27df897088e02553f0aec44c614595de01fe357ffb257ecaf7d40c8fa + name: _fe_analyzer_shared + sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "85.0.0" + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: ff0a84a2734d9e1089f8aedd5c0af0061b82fb94e95260d943404e0ef2134b11 + url: "https://pub.dev" + source: hosted + version: "1.3.59" + agora_rtc_engine: + dependency: "direct main" + description: + name: agora_rtc_engine + sha256: "6559294d18ce4445420e19dbdba10fb58cac955cd8f22dbceae26716e194d70e" + url: "https://pub.dev" + source: hosted + version: "6.5.3" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d" + url: "https://pub.dev" + source: hosted + version: "7.7.1" + archive: + dependency: transitive + description: + name: archive + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff + url: "https://pub.dev" + source: hosted + version: "4.0.9" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" async: dependency: transitive description: @@ -17,6 +57,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.13.1" + audio_session: + dependency: transitive + description: + name: audio_session + sha256: "2b7fff16a552486d078bfc09a8cde19f426dc6d6329262b684182597bec5b1ac" + url: "https://pub.dev" + source: hosted + version: "0.1.25" + bloc: + dependency: transitive + description: + name: bloc + sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e" + url: "https://pub.dev" + source: hosted + version: "8.1.4" + bloc_test: + dependency: "direct dev" + description: + name: bloc_test + sha256: "165a6ec950d9252ebe36dc5335f2e6eb13055f33d56db0eeb7642768849b43d2" + url: "https://pub.dev" + source: hosted + version: "9.1.7" boolean_selector: dependency: transitive description: @@ -25,30 +89,118 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + build: + dependency: transitive + description: + name: build + sha256: ce76b1d48875e3233fde17717c23d1f60a91cc631597e49a400c89b475395b1d + url: "https://pub.dev" + source: hosted + version: "3.1.0" + build_config: + dependency: transitive + description: + name: build_config + sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957 + url: "https://pub.dev" + source: hosted + version: "4.1.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: d1d57f7807debd7349b4726a19fd32ec8bc177c71ad0febf91a20f84cd2d4b46 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: b24597fceb695969d47025c958f3837f9f0122e237c6a22cb082a5ac66c3ca30 + url: "https://pub.dev" + source: hosted + version: "2.7.1" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "066dda7f73d8eb48ba630a55acb50c4a84a2e6b453b1cb4567f581729e794f7b" + url: "https://pub.dev" + source: hosted + version: "9.3.1" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "34e4067d30ce212937df995f03b69992eea683539ceeac7f679a1f1eba055b56" + url: "https://pub.dev" + source: hosted + version: "8.12.6" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" + url: "https://pub.dev" + source: hosted + version: "1.3.1" camera: dependency: "direct main" description: name: camera - sha256: "034c38cb8014d29698dcae6d20276688a1bf74e6487dfeb274d70ea05d5f7777" + sha256: "4142a19a38e388d3bab444227636610ba88982e36dff4552d5191a86f65dc437" url: "https://pub.dev" source: hosted - version: "0.12.0+1" + version: "0.11.4" camera_android_camerax: dependency: transitive description: name: camera_android_camerax - sha256: b5064cf25a2787d122d0bf12e77c7b1033a2b983d0730e3091f770ee376efde5 + sha256: "8516fe308bc341a5067fb1a48edff0ddfa57c0d3cdcc9dbe7ceca3ba119e2577" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.6.30" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "90e4cc3fde331581a3b2d35d83be41dbb7393af0ab857eb27b732174289cb96d" + sha256: "11b4aee2f5e5e038982e152b4a342c749b414aa27857899d20f4323e94cb5f0b" url: "https://pub.dev" source: hosted - version: "0.10.1" + version: "0.9.23+2" camera_platform_interface: dependency: transitive description: @@ -73,6 +225,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a + url: "https://pub.dev" + source: hosted + version: "1.4.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" clock: dependency: transitive description: @@ -81,6 +265,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "6a6cab2ba4680d6423f34a9b972a4c9a94ebe1b62ecec4e1a1f2cba91fd1319d" + url: "https://pub.dev" + source: hosted + version: "4.11.1" collection: dependency: transitive description: @@ -89,6 +281,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + connectivity_plus: + dependency: "direct main" + description: + name: connectivity_plus + sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec + url: "https://pub.dev" + source: hosted + version: "6.1.5" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "3c09627c536d22fd24691a905cdd8b14520de69da52c7a97499c8be5284a32ed" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" + url: "https://pub.dev" + source: hosted + version: "1.15.0" cross_file: dependency: transitive description: @@ -113,6 +337,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.9" + dart_earcut: + dependency: transitive + description: + name: dart_earcut + sha256: e485001bfc05dcbc437d7bfb666316182e3522d4c3f9668048e004d0eb2ce43b + url: "https://pub.dev" + source: hosted + version: "1.2.0" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" + url: "https://pub.dev" + source: hosted + version: "3.1.1" dartz: dependency: "direct main" description: @@ -121,6 +361,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.10.1" + dbus: + dependency: transitive + description: + name: dbus + sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 + url: "https://pub.dev" + source: hosted + version: "0.7.12" + device_info_plus: + dependency: transitive + description: + name: device_info_plus + sha256: "98f28b42168cc509abc92f88518882fd58061ea372d7999aecc424345c7bff6a" + url: "https://pub.dev" + source: hosted + version: "11.5.0" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f + url: "https://pub.dev" + source: hosted + version: "7.0.3" + diff_match_patch: + dependency: transitive + description: + name: diff_match_patch + sha256: "2efc9e6e8f449d0abe15be240e2c2a3bcd977c8d126cfd70598aee60af35c0a4" + url: "https://pub.dev" + source: hosted + version: "0.4.1" dio: dependency: "direct main" description: @@ -137,6 +409,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + drift: + dependency: "direct main" + description: + name: drift + sha256: "83290a32ae006a7535c5ecf300722cb77177250d9df4ee2becc5fa8a36095114" + url: "https://pub.dev" + source: hosted + version: "2.29.0" + drift_dev: + dependency: "direct dev" + description: + name: drift_dev + sha256: "6019f827544e77524ffd5134ae0cb75dfd92ef5ef3e269872af92840c929cd43" + url: "https://pub.dev" + source: hosted + version: "2.29.0" fake_async: dependency: transitive description: @@ -153,19 +441,144 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "7be63a3f841fc9663342f7f3a011a42aef6a61066943c90b1c434d79d5c995c5" + url: "https://pub.dev" + source: hosted + version: "3.15.2" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: "0ecda14c1bfc9ed8cac303dd0f8d04a320811b479362a9a4efb14fd331a473ce" + url: "https://pub.dev" + source: hosted + version: "6.0.3" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" + url: "https://pub.dev" + source: hosted + version: "2.24.1" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + sha256: "60be38574f8b5658e2f22b7e311ff2064bea835c248424a383783464e8e02fcc" + url: "https://pub.dev" + source: hosted + version: "15.2.10" + firebase_messaging_platform_interface: + dependency: transitive + description: + name: firebase_messaging_platform_interface + sha256: "685e1771b3d1f9c8502771ccc9f91485b376ffe16d553533f335b9183ea99754" + url: "https://pub.dev" + source: hosted + version: "4.6.10" + firebase_messaging_web: + dependency: transitive + description: + name: firebase_messaging_web + sha256: "0d1be17bc89ed3ff5001789c92df678b2e963a51b6fa2bdb467532cc9dbed390" + url: "https://pub.dev" + source: hosted + version: "3.10.10" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_animate: + dependency: "direct main" + description: + name: flutter_animate + sha256: "7befe2d3252728afb77aecaaea1dec88a89d35b9b1d2eea6d04479e8af9117b5" + url: "https://pub.dev" + source: hosted + version: "4.5.2" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a + url: "https://pub.dev" + source: hosted + version: "8.1.6" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "4.0.0" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: "674173fd3c9eda9d4c8528da2ce0ea69f161577495a9cc835a2a4ecd7eadeb35" + url: "https://pub.dev" + source: hosted + version: "17.2.4" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af + url: "https://pub.dev" + source: hosted + version: "4.0.1" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66" + url: "https://pub.dev" + source: hosted + version: "7.2.0" + flutter_map: + dependency: "direct main" + description: + name: flutter_map + sha256: "2ecb34619a4be19df6f40c2f8dce1591675b4eff7a6857bd8f533706977385da" + url: "https://pub.dev" + source: hosted + version: "7.0.2" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -178,68 +591,177 @@ packages: dependency: "direct main" description: name: flutter_secure_storage - sha256: da922f2aab2d733db7e011a6bcc4a825b844892d4edd6df83ff156b09a9b2e40 + sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea" url: "https://pub.dev" source: hosted - version: "10.0.0" - flutter_secure_storage_darwin: - dependency: transitive - description: - name: flutter_secure_storage_darwin - sha256: "8878c25136a79def1668c75985e8e193d9d7d095453ec28730da0315dc69aee3" - url: "https://pub.dev" - source: hosted - version: "0.2.0" + version: "9.2.4" flutter_secure_storage_linux: dependency: transitive description: name: flutter_secure_storage_linux - sha256: "2b5c76dce569ab752d55a1cee6a2242bcc11fdba927078fb88c503f150767cda" + sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688 url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "1.2.3" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247" + url: "https://pub.dev" + source: hosted + version: "3.1.3" flutter_secure_storage_platform_interface: dependency: transitive description: name: flutter_secure_storage_platform_interface - sha256: "8ceea1223bee3c6ac1a22dabd8feefc550e4729b3675de4b5900f55afcb435d6" + sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "1.1.2" flutter_secure_storage_web: dependency: transitive description: name: flutter_secure_storage_web - sha256: "6a1137df62b84b54261dca582c1c09ea72f4f9a4b2fcee21b025964132d5d0c3" + sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "1.2.1" flutter_secure_storage_windows: dependency: transitive description: name: flutter_secure_storage_windows - sha256: "3b7c8e068875dfd46719ff57c90d8c459c87f2302ed6b00ff006b3c9fcad1613" + sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "3.1.2" + flutter_shaders: + dependency: transitive + description: + name: flutter_shaders + sha256: "34794acadd8275d971e02df03afee3dee0f98dbfb8c4837082ad0034f612a3e2" + url: "https://pub.dev" + source: hosted + version: "0.1.3" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_tts: + dependency: "direct main" + description: + name: flutter_tts + sha256: ce5eb209b40e95f2f4a1397116c87ab2fcdff32257d04ed7a764e75894c03775 + url: "https://pub.dev" + source: hosted + version: "4.2.5" flutter_web_plugins: dependency: transitive description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "149876cc5207a0f5daf4fdd3bfcf0a0f27258b3fe95108fa084f527ad0568f1b" + url: "https://pub.dev" + source: hosted + version: "12.0.0" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: fcb1760a50d7500deca37c9a666785c047139b5f9ee15aa5469fae7dbbe3170d + url: "https://pub.dev" + source: hosted + version: "4.6.2" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 + url: "https://pub.dev" + source: hosted + version: "2.3.13" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" + url: "https://pub.dev" + source: hosted + version: "4.2.6" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 + url: "https://pub.dev" + source: hosted + version: "4.1.3" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" + url: "https://pub.dev" + source: hosted + version: "0.2.5" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: ae78de7c3f2304b8d81f2bb6e320833e5e81de942188542328f074978cc0efa9 + url: "https://pub.dev" + source: hosted + version: "8.3.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: f02fd7d2a4dc512fec615529824fdd217fecb3a3d3de68360293a551f21634b3 + url: "https://pub.dev" + source: hosted + version: "14.8.1" google_fonts: dependency: "direct main" description: name: google_fonts - sha256: db9df7a5898d894eeda4c78143f35c30a243558be439518972366880b80bf88e + sha256: ba03d03bcaa2f6cb7bd920e3b5027181db75ab524f8891c8bc3aa603885b8055 url: "https://pub.dev" source: hosted - version: "8.0.2" + version: "6.3.3" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" http: dependency: transitive description: @@ -248,6 +770,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.6.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" http_parser: dependency: transitive description: @@ -256,6 +786,91 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + image: + dependency: "direct main" + description: + name: image + sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce + url: "https://pub.dev" + source: hosted + version: "4.8.0" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + intl: + dependency: transitive + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + iris_method_channel: + dependency: transitive + description: + name: iris_method_channel + sha256: "114bbe541369add8dd0727858e7df5764f375e3fb88374ad487301733fddb57f" + url: "https://pub.dev" + source: hosted + version: "2.2.5" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8 + url: "https://pub.dev" + source: hosted + version: "4.11.0" + just_audio: + dependency: "direct main" + description: + name: just_audio + sha256: f978d5b4ccea08f267dae0232ec5405c1b05d3f3cd63f82097ea46c015d5c09e + url: "https://pub.dev" + source: hosted + version: "0.9.46" + just_audio_platform_interface: + dependency: transitive + description: + name: just_audio_platform_interface + sha256: "2532c8d6702528824445921c5ff10548b518b13f808c2e34c2fd54793b999a6a" + url: "https://pub.dev" + source: hosted + version: "4.6.0" + just_audio_web: + dependency: transitive + description: + name: just_audio_web + sha256: "6ba8a2a7e87d57d32f0f7b42856ade3d6a9fbe0f1a11fabae0a4f00bb73f0663" + url: "https://pub.dev" + source: hosted + version: "0.4.16" + latlong2: + dependency: "direct main" + description: + name: latlong2 + sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe" + url: "https://pub.dev" + source: hosted + version: "0.9.1" leak_tracker: dependency: transitive description: @@ -284,10 +899,34 @@ packages: dependency: transitive description: name: lints - sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "4.0.0" + lists: + dependency: transitive + description: + name: lists + sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + logger: + dependency: transitive + description: + name: logger + sha256: "25aee487596a6257655a1e091ec2ae66bc30e7af663592cc3a27e6591e05035c" + url: "https://pub.dev" + source: hosted + version: "2.7.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" matcher: dependency: transitive description: @@ -312,6 +951,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.16.0" + mgrs_dart: + dependency: transitive + description: + name: mgrs_dart + sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 + url: "https://pub.dev" + source: hosted + version: "2.0.0" mime: dependency: transitive description: @@ -320,8 +967,64 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" - path: + mockito: + dependency: "direct dev" + description: + name: mockito + sha256: "2314cbe9165bcd16106513df9cf3c3224713087f09723b128928dc11a4379f99" + url: "https://pub.dev" + source: hosted + version: "5.5.0" + mocktail: dependency: transitive + description: + name: mocktail + sha256: "5e1bf53cc7baa8062a33b84424deb61513858ea05c601b8509e683815b5914aa" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" + path: + dependency: "direct main" description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" @@ -329,7 +1032,7 @@ packages: source: hosted version: "1.9.1" path_provider: - dependency: transitive + dependency: "direct main" description: name: path_provider sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" @@ -376,6 +1079,70 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + pedantic: + dependency: transitive + description: + name: pedantic + sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" + url: "https://pub.dev" + source: hosted + version: "11.4.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc + url: "https://pub.dev" + source: hosted + version: "12.1.0" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 + url: "https://pub.dev" + source: hosted + version: "9.4.7" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" + url: "https://pub.dev" + source: hosted + version: "0.1.3+5" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 + url: "https://pub.dev" + source: hosted + version: "4.3.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" + url: "https://pub.dev" + source: hosted + version: "7.0.2" platform: dependency: transitive description: @@ -392,11 +1159,275 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + polylabel: + dependency: transitive + description: + name: polylabel + sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + pool: + dependency: transitive + description: + name: pool + sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + url: "https://pub.dev" + source: hosted + version: "1.5.2" + posix: + dependency: transitive + description: + name: posix + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" + url: "https://pub.dev" + source: hosted + version: "6.5.0" + process: + dependency: transitive + description: + name: process + sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 + url: "https://pub.dev" + source: hosted + version: "5.0.5" + proj4dart: + dependency: transitive + description: + name: proj4dart + sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e + url: "https://pub.dev" + source: hosted + version: "2.1.0" + provider: + dependency: transitive + description: + name: provider + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" + url: "https://pub.dev" + source: hosted + version: "6.1.5+1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + quiver: + dependency: transitive + description: + name: quiver + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" + record: + dependency: "direct main" + description: + name: record + sha256: "2e3d56d196abcd69f1046339b75e5f3855b2406fc087e5991f6703f188aa03a6" + url: "https://pub.dev" + source: hosted + version: "5.2.1" + record_android: + dependency: transitive + description: + name: record_android + sha256: "94783f08403aed33ffb68797bf0715b0812eb852f3c7985644c945faea462ba1" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + record_darwin: + dependency: transitive + description: + name: record_darwin + sha256: e487eccb19d82a9a39cd0126945cfc47b9986e0df211734e2788c95e3f63c82c + url: "https://pub.dev" + source: hosted + version: "1.2.2" + record_linux: + dependency: transitive + description: + name: record_linux + sha256: "74d41a9ebb1eb498a38e9a813dd524e8f0b4fdd627270bda9756f437b110a3e3" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + record_platform_interface: + dependency: transitive + description: + name: record_platform_interface + sha256: "8a81dbc4e14e1272a285bbfef6c9136d070a47d9b0d1f40aa6193516253ee2f6" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + record_web: + dependency: transitive + description: + name: record_web + sha256: "7e9846981c1f2d111d86f0ae3309071f5bba8b624d1c977316706f08fc31d16d" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + record_windows: + dependency: transitive + description: + name: record_windows + sha256: "223258060a1d25c62bae18282c16783f28581ec19401d17e56b5205b9f039d78" + url: "https://pub.dev" + source: hosted + version: "1.0.7" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf + url: "https://pub.dev" + source: hosted + version: "2.5.5" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 + url: "https://pub.dev" + source: hosted + version: "2.4.23" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + shimmer: + dependency: "direct main" + description: + name: shimmer + sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" + url: "https://pub.dev" + source: hosted + version: "3.0.0" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.0" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "7b19d6ba131c6eb98bfcbf8d56c1a7002eba438af2e7ae6f8398b2b0f4f381e3" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" source_span: dependency: transitive description: @@ -405,6 +1436,94 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.2" + speech_to_text: + dependency: "direct main" + description: + name: speech_to_text + sha256: c07557664974afa061f221d0d4186935bea4220728ea9446702825e8b988db04 + url: "https://pub.dev" + source: hosted + version: "7.3.0" + speech_to_text_platform_interface: + dependency: transitive + description: + name: speech_to_text_platform_interface + sha256: a1935847704e41ee468aad83181ddd2423d0833abe55d769c59afca07adb5114 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + speech_to_text_windows: + dependency: transitive + description: + name: speech_to_text_windows + sha256: "2c9846d18253c7bbe059a276297ef9f27e8a2745dead32192525beb208195072" + url: "https://pub.dev" + source: hosted + version: "1.0.0+beta.8" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88 + url: "https://pub.dev" + source: hosted + version: "2.4.2+2" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + sqlite3: + dependency: transitive + description: + name: sqlite3 + sha256: "3145bd74dcdb4fd6f5c6dda4d4e4490a8087d7f286a14dee5d37087290f0f8a2" + url: "https://pub.dev" + source: hosted + version: "2.9.4" + sqlite3_flutter_libs: + dependency: "direct main" + description: + name: sqlite3_flutter_libs + sha256: eeb9e3a45207649076b808f8a5a74d68770d0b7f26ccef6d5f43106eee5375ad + url: "https://pub.dev" + source: hosted + version: "0.5.42" + sqlparser: + dependency: transitive + description: + name: sqlparser + sha256: "162435ede92bcc793ea939fdc0452eef0a73d11f8ed053b58a89792fba749da5" + url: "https://pub.dev" + source: hosted + version: "0.42.1" stack_trace: dependency: transitive description: @@ -437,6 +1556,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 + url: "https://pub.dev" + source: hosted + version: "3.4.0" term_glyph: dependency: transitive description: @@ -445,6 +1580,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.2" + test: + dependency: transitive + description: + name: test + sha256: "65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb" + url: "https://pub.dev" + source: hosted + version: "1.26.2" test_api: dependency: transitive description: @@ -453,6 +1596,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.6" + test_core: + dependency: transitive + description: + name: test_core + sha256: "80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a" + url: "https://pub.dev" + source: hosted + version: "0.6.11" + tflite_flutter: + dependency: "direct main" + description: + name: tflite_flutter + sha256: ffb8651fdb116ab0131d6dc47ff73883e0f634ad1ab12bb2852eef1bbeab4a6a + url: "https://pub.dev" + source: hosted + version: "0.10.4" + timezone: + dependency: transitive + description: + name: timezone + sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" + url: "https://pub.dev" + source: hosted + version: "0.9.4" + timing: + dependency: transitive + description: + name: timing + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" + source: hosted + version: "1.0.2" typed_data: dependency: transitive description: @@ -461,6 +1636,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + unicode: + dependency: transitive + description: + name: unicode + sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + uuid: + dependency: transitive + description: + name: uuid + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" + url: "https://pub.dev" + source: hosted + version: "4.5.3" vector_math: dependency: transitive description: @@ -469,6 +1660,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + vibration: + dependency: "direct main" + description: + name: vibration + sha256: "3b08a0579c2f9c18d5d78cb5c74f1005f731e02eeca6d72561a2e8059bf98ec3" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + vibration_platform_interface: + dependency: transitive + description: + name: vibration_platform_interface + sha256: "6ffeee63547562a6fef53c05a41d4fdcae2c0595b83ef59a4813b0612cd2bc36" + url: "https://pub.dev" + source: hosted + version: "0.0.3" vm_service: dependency: transitive description: @@ -477,6 +1684,14 @@ packages: url: "https://pub.dev" source: hosted version: "15.1.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635" + url: "https://pub.dev" + source: hosted + version: "1.2.1" web: dependency: transitive description: @@ -485,6 +1700,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + webdriver: + dependency: transitive + description: + name: webdriver + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" win32: dependency: transitive description: @@ -493,6 +1740,22 @@ packages: url: "https://pub.dev" source: hosted version: "5.15.0" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + wkt_parser: + dependency: transitive + description: + name: wkt_parser + sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" + url: "https://pub.dev" + source: hosted + version: "2.0.0" xdg_directories: dependency: transitive description: @@ -501,6 +1764,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" sdks: dart: ">=3.9.0 <4.0.0" flutter: ">=3.35.0" diff --git a/walkguide-mobile/walkguide_app/pubspec.yaml b/walkguide-mobile/walkguide_app/pubspec.yaml index 67bf0cc..3c9979f 100644 --- a/walkguide-mobile/walkguide_app/pubspec.yaml +++ b/walkguide-mobile/walkguide_app/pubspec.yaml @@ -1,97 +1,103 @@ name: walkguide_app -description: "A new Flutter project." -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -# In Windows, build-name is used as the major, minor, and patch parts -# of the product and file versions while build-number is used as the build suffix. +description: "WalkGuide - AI Navigation for Visually Impaired" +publish_to: 'none' version: 1.0.0+1 environment: - sdk: ^3.9.0 + sdk: ^3.4.0 -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.8 - dio: ^5.9.2 - flutter_secure_storage: ^10.0.0 - google_fonts: ^8.0.2 + # State management + flutter_bloc: ^8.1.6 + + # Navigation + go_router: ^14.2.7 + + # Network + dio: ^5.4.3+1 + + # Storage + flutter_secure_storage: ^9.2.2 + shared_preferences: ^2.3.2 + drift: ^2.18.0 + sqlite3_flutter_libs: ^0.5.24 + path_provider: ^2.1.3 + path: ^1.9.0 + + # Firebase / FCM + firebase_core: ^3.3.0 + firebase_messaging: ^15.1.0 + flutter_local_notifications: ^17.2.1+2 + + # Camera & AI + camera: ^0.11.0+2 + tflite_flutter: ^0.10.4 + image: ^4.2.0 + + # Audio & TTS + flutter_tts: ^4.0.2 + speech_to_text: ^7.0.0 + just_audio: ^0.9.40 + record: ^5.1.2 + + # Maps (OpenStreetMap - FREE) + flutter_map: ^7.0.2 + latlong2: ^0.9.1 + + # Location + geolocator: ^12.0.0 + + # Agora VoIP + agora_rtc_engine: ^6.3.2 + + # Permissions + permission_handler: ^11.3.1 + + # Haptic + vibration: ^2.0.0 + + # Connectivity + connectivity_plus: ^6.0.3 + + # Functional programming (Either) dartz: ^0.10.1 - camera: ^0.12.0+1 - animate_do: ^5.1.0 + + # DI + get_it: ^8.0.2 + + # UI + google_fonts: ^6.2.1 + flutter_animate: ^4.5.0 + cupertino_icons: ^1.0.8 + cached_network_image: ^3.3.1 + shimmer: ^3.0.0 dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^4.0.0 + build_runner: ^2.4.11 + drift_dev: ^2.18.0 + integration_test: + sdk: flutter + mockito: ^5.4.4 + bloc_test: ^9.1.7 - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^5.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. uses-material-design: true assets: - assets/images/ - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package + - assets/models/ + fonts: + - family: Inter + fonts: + - asset: assets/fonts/Inter-Regular.ttf + - asset: assets/fonts/Inter-Medium.ttf + weight: 500 + - asset: assets/fonts/Inter-SemiBold.ttf + weight: 600 + - asset: assets/fonts/Inter-Bold.ttf + weight: 700 \ No newline at end of file diff --git a/walkguide-mobile/walkguide_app/windows/flutter/generated_plugin_registrant.cc b/walkguide-mobile/walkguide_app/windows/flutter/generated_plugin_registrant.cc index 0c50753..c75836c 100644 --- a/walkguide-mobile/walkguide_app/windows/flutter/generated_plugin_registrant.cc +++ b/walkguide-mobile/walkguide_app/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,39 @@ #include "generated_plugin_registrant.h" +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + AgoraRtcEnginePluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("AgoraRtcEnginePlugin")); + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + FirebaseCorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); + FlutterTtsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterTtsPlugin")); + GeolocatorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GeolocatorWindows")); + IrisMethodChannelPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("IrisMethodChannelPluginCApi")); + PermissionHandlerWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); + RecordWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("RecordWindowsPluginCApi")); + SpeechToTextWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SpeechToTextWindows")); + Sqlite3FlutterLibsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin")); } diff --git a/walkguide-mobile/walkguide_app/windows/flutter/generated_plugins.cmake b/walkguide-mobile/walkguide_app/windows/flutter/generated_plugins.cmake index 4fc759c..4664fac 100644 --- a/walkguide-mobile/walkguide_app/windows/flutter/generated_plugins.cmake +++ b/walkguide-mobile/walkguide_app/windows/flutter/generated_plugins.cmake @@ -3,10 +3,21 @@ # list(APPEND FLUTTER_PLUGIN_LIST + agora_rtc_engine + connectivity_plus + firebase_core flutter_secure_storage_windows + flutter_tts + geolocator_windows + iris_method_channel + permission_handler_windows + record_windows + speech_to_text_windows + sqlite3_flutter_libs ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + tflite_flutter ) set(PLUGIN_BUNDLED_LIBRARIES)