import 'package:dio/dio.dart'; import '../about/external/data/pages/request/CommitmentsRequest.dart'; import '../about/external/data/pages/request/HistoryRequest.dart'; import '../about/external/initial/AbandonRequest.dart'; import '../about/external/initial/AmnestyRequest.dart'; import '../about/external/initial/CommitmentRequest.dart'; import '../about/external/initial/CompletionRequest.dart'; import '../about/external/initial/DeferralRequest.dart'; import '../about/external/initial/DeviceRequest.dart'; import '../about/external/initial/GoalRequest.dart'; import '../about/external/initial/IdRequest.dart'; import '../about/external/initial/LoginData.dart'; import '../about/external/initial/ReportCardRequest.dart'; import '../about/external/initial/SessionLogRequest.dart'; import '../about/external/initial/SickModeRequest.dart'; import '../about/external/initial/ToneRequest.dart'; import '../about/internal/application/MeDescription.dart'; import '../about/internal/application/Pair.dart'; import '../configs/Env.dart'; import '../memory/ConnectInternalMemory.dart'; import 'CommsDirections.dart'; import 'ConnectComms.dart'; class Comms implements ConnectComms { Dio dio = Dio(); ConnectInternalMemory helper; Comms(this.helper); /// Builds the identity headers and resolves the URL. Headers are reset on /// every call so a stale Authorization can never leak into an auth-flow /// request. Future getRequestHeaders(String url, String urlData) async { dio.options.headers = {}; MeDescription data = await helper.getMyDescription(); if (data.token.isNotEmpty && url != deviceToken) { dio.options.headers["Authorization"] = "Bearer ${data.token}"; } if (url == logoutRequest) { dio.options.headers.remove("Authorization"); } dio.options.contentType = Headers.jsonContentType; dio.options.responseType = ResponseType.json; // The backend identity contract: what = encrypted access code, // whom = encrypted device id, version = the app build. dio.options.headers["what"] = data.name; dio.options.headers["whom"] = data.id; dio.options.headers["version"] = localisedAppVersion; return Pair("${_routeFor(url)}$url$urlData", dio.options.headers); } /// Auth-flow paths go to Prospect, training paths to Training, everything /// else to the Discipline service. String _routeFor(String url) { if (url == deviceReg || url == deviceToken || url == loginUser || url == logoutRequest || url == aboutMe || url == accountRecovery || url.startsWith('InAugurate/')) { return prospectRoute; } if (url.startsWith('Program/') || url.startsWith('Session/') || url.startsWith('Metrics/')) { return trainingRoute; } return disciplineRoute; } // ── Auth ────────────────────────────────────────────────────────────────── @override Future registerDevice(DeviceRequest request) async { Pair navigation = await getRequestHeaders(deviceReg, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future registerDeviceToken(String token) async { Pair navigation = await getRequestHeaders(deviceToken, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: {"token": token}); } @override Future login(LoginData request) async { Pair navigation = await getRequestHeaders(loginUser, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future logout() async { Pair navigation = await getRequestHeaders(logoutRequest, ""); dio.options.headers = navigation.value; return await dio.get(navigation.key); } @override Future me() async { Pair navigation = await getRequestHeaders(aboutMe, ""); dio.options.headers = navigation.value; return await dio.get(navigation.key); } // ── Goals ───────────────────────────────────────────────────────────────── @override Future getMyGoals(HistoryRequest request) async { Pair navigation = await getRequestHeaders(myGoals, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future saveGoalEntry(GoalRequest request) async { Pair navigation = await getRequestHeaders(saveGoal, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getGoalTasks(IdRequest request) async { Pair navigation = await getRequestHeaders(goalTasks, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future archiveGoalEntry(IdRequest request) async { Pair navigation = await getRequestHeaders(archiveGoal, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } // ── Commitments ─────────────────────────────────────────────────────────── @override Future getTodayPlan(CommitmentsRequest request) async { Pair navigation = await getRequestHeaders(todayPlan, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getMyCommitments(CommitmentsRequest request) async { Pair navigation = await getRequestHeaders(myCommitments, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getOverdueQueue(HistoryRequest request) async { Pair navigation = await getRequestHeaders(overdueQueue, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future saveCommitmentEntry(CommitmentRequest request) async { Pair navigation = await getRequestHeaders(saveCommitment, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future updateCommitmentEntry(CommitmentRequest request) async { Pair navigation = await getRequestHeaders(updateCommitment, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future deleteCommitmentEntry(IdRequest request) async { Pair navigation = await getRequestHeaders(deleteCommitment, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future completeCommitmentEntry(CompletionRequest request) async { Pair navigation = await getRequestHeaders(completeCommitment, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future deferCommitmentEntry(DeferralRequest request) async { Pair navigation = await getRequestHeaders(deferCommitment, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future abandonCommitmentEntry(AbandonRequest request) async { Pair navigation = await getRequestHeaders(abandonCommitment, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getCommitmentHistory(HistoryRequest request) async { Pair navigation = await getRequestHeaders(commitmentHistory, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getCommitmentEvents(IdRequest request) async { Pair navigation = await getRequestHeaders(commitmentEvents, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } // ── Capacity ────────────────────────────────────────────────────────────── @override Future checkCapacity(CommitmentsRequest request) async { Pair navigation = await getRequestHeaders(capacityCheck, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getCapacityProfileEntry() async { Pair navigation = await getRequestHeaders(capacityProfilePath, ""); dio.options.headers = navigation.value; return await dio.get(navigation.key); } // ── Debt & standing ─────────────────────────────────────────────────────── @override Future getDebtSummary() async { Pair navigation = await getRequestHeaders(debtSummary, ""); dio.options.headers = navigation.value; return await dio.get(navigation.key); } @override Future getDebtLedger(HistoryRequest request) async { Pair navigation = await getRequestHeaders(debtLedger, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getDebtTrend(ReportCardRequest request) async { Pair navigation = await getRequestHeaders(debtTrendPath, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getStanding() async { Pair navigation = await getRequestHeaders(standingPath, ""); dio.options.headers = navigation.value; return await dio.get(navigation.key); } @override Future getStandingHistory(HistoryRequest request) async { Pair navigation = await getRequestHeaders(standingHistory, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } // ── Excuses ─────────────────────────────────────────────────────────────── @override Future getExcuseClusters(ReportCardRequest request) async { Pair navigation = await getRequestHeaders(excuseClusters, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } // ── Proof ───────────────────────────────────────────────────────────────── @override Future uploadPhotoProof(FormData request) async { Pair navigation = await getRequestHeaders(uploadProofPhoto, ""); dio.options.headers = navigation.value; dio.options.contentType = Headers.multipartFormDataContentType; return await dio.post(navigation.key, data: request); } @override Future submitTimerProofEntry(CompletionRequest request) async { Pair navigation = await getRequestHeaders(submitTimerProof, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future submitLocationProofEntry(CompletionRequest request) async { Pair navigation = await getRequestHeaders(submitLocationProof, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } // ── Guardrails ──────────────────────────────────────────────────────────── @override Future spendAmnestyToken(AmnestyRequest request) async { Pair navigation = await getRequestHeaders(spendAmnesty, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getAmnestyBalance() async { Pair navigation = await getRequestHeaders(amnestyBalance, ""); dio.options.headers = navigation.value; return await dio.get(navigation.key); } @override Future updateSickMode(SickModeRequest request) async { Pair navigation = await getRequestHeaders(setSickMode, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future checkDistress() async { Pair navigation = await getRequestHeaders(distressCheck, ""); dio.options.headers = navigation.value; return await dio.get(navigation.key); } @override Future updateTone(ToneRequest request) async { Pair navigation = await getRequestHeaders(setTone, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } // ── Habits & routines ───────────────────────────────────────────────────── @override Future getMyHabits(HistoryRequest request) async { Pair navigation = await getRequestHeaders(myHabits, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future saveHabitEntry(Map request) async { Pair navigation = await getRequestHeaders(saveHabit, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future logHabitEntry(IdRequest request) async { Pair navigation = await getRequestHeaders(logHabit, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getKeystoneHabits() async { Pair navigation = await getRequestHeaders(keystoneHabits, ""); dio.options.headers = navigation.value; return await dio.get(navigation.key); } @override Future getMyRoutines(HistoryRequest request) async { Pair navigation = await getRequestHeaders(myRoutines, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future logRoutineChainEntry(Map request) async { Pair navigation = await getRequestHeaders(logRoutineChain, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } // ── Training ────────────────────────────────────────────────────────────── @override Future getMyPrograms(HistoryRequest request) async { Pair navigation = await getRequestHeaders(myPrograms, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future saveProgramEntry(Map request) async { Pair navigation = await getRequestHeaders(saveProgram, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future activateProgramEntry(IdRequest request) async { Pair navigation = await getRequestHeaders(activateProgram, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getProgramSessions(IdRequest request) async { Pair navigation = await getRequestHeaders(programSessions, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future startSessionEntry(IdRequest request) async { Pair navigation = await getRequestHeaders(startSession, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future saveSessionLogEntry(SessionLogRequest request) async { Pair navigation = await getRequestHeaders(saveSessionLog, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getSessionHistory(HistoryRequest request) async { Pair navigation = await getRequestHeaders(sessionHistory, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getLastSessionFor(IdRequest request) async { Pair navigation = await getRequestHeaders(lastSessionFor, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getWeeklyVolume(ReportCardRequest request) async { Pair navigation = await getRequestHeaders(weeklyVolume, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getContactVolume(ReportCardRequest request) async { Pair navigation = await getRequestHeaders(contactVolume, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getPersonalRecords(HistoryRequest request) async { Pair navigation = await getRequestHeaders(personalRecords, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } // ── Report card ─────────────────────────────────────────────────────────── @override Future getWeeklyReportCard(ReportCardRequest request) async { Pair navigation = await getRequestHeaders(weeklyReportCard, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future getMonthlyReportCard(ReportCardRequest request) async { Pair navigation = await getRequestHeaders(monthlyReportCard, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } // ── Notifications ───────────────────────────────────────────────────────── @override Future getMyNotifications(HistoryRequest request) async { Pair navigation = await getRequestHeaders(myNotifications, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } @override Future acknowledgeNudgeEntry(IdRequest request) async { Pair navigation = await getRequestHeaders(acknowledgeNudge, ""); dio.options.headers = navigation.value; return await dio.post(navigation.key, data: request); } }