Commit d0cfc2ff authored by Yousef Sameh's avatar Yousef Sameh

inconnectivity loop

parent 8d528dbd
......@@ -6,6 +6,7 @@ using Supabase.Gotrue;
using Supabase.Gotrue.Interfaces;
using UnityEngine;
using UnityEngine.SceneManagement;
using TMPro;
public class AppRouter : MonoBehaviour
{
......@@ -15,9 +16,14 @@ public class AppRouter : MonoBehaviour
[Header("Splash UI (Boot Scene Only)")]
[SerializeField] private GameObject splashScreen;
[SerializeField] private GameObject errorPanel;
[SerializeField] private TextMeshProUGUI statusText;
[Header("Settings")]
public TransitionSettings transitionSettings;
private bool _booted;
[Header("Debug Testing")]
[Tooltip("Check this in the Inspector to simulate network loss and test the 'Waiting' loop.")]
[SerializeField] private bool simulateNetworkFailure;
private void Awake()
{
......@@ -30,6 +36,7 @@ public class AppRouter : MonoBehaviour
_instance = this;
DontDestroyOnLoad(gameObject);
// Standard mobile optimizations
Application.targetFrameRate = Screen.currentResolution.refreshRate;
Screen.orientation = ScreenOrientation.Portrait;
}
......@@ -42,7 +49,7 @@ public class AppRouter : MonoBehaviour
private void HandleBackButton()
{
// Don't interrupt active challenges
// Safety: Don't let the back button break an active game session
if (ChallengeManager.Instance != null && ChallengeManager.Instance.IsChallengeRunning)
return;
......@@ -66,74 +73,119 @@ public class AppRouter : MonoBehaviour
var cached = UserService.Instance.LoadFromCache();
TransitionManager.Instance().onTransitionCutPointReached += HideSplash;
bool ready = await SupabaseManager.Instance.Initialize();
if (!ready)
{
if (cached != null) { GoToHome(); return; }
ShowError("Failed to connect");
return;
}
// --- STEP 1: Network Connection Loop ---
// Execution halts here until isConnected is true
await EnsureNetworkConnection();
// --- STEP 2: Authentication Session ---
UpdateStatus("Checking session...");
var authResult = await SupabaseAuthentication.Instance.EnsureSession();
if (authResult.IsT1)
if (authResult.IsT1) // No valid session found
{
if (cached != null)
{
if (cached != null) { GoToHome(); return; }
Debug.Log("[Boot] Offline/No session, using cache.");
GoToHome();
return;
}
GoToLogin();
return;
}
// --- STEP 3: Load User Profile ---
UpdateStatus("Fetching profile...");
var prof = await UserService.Instance.GetCurrentUser();
prof.Switch(
async success =>
{
TransitionManager.Instance().Transition("MainMenu", transitionSettings, 0f);
UpdateStatus("Welcome back!");
TransitionManager.Instance().Transition("MainMenu", transitionSettings, 0.5f);
UserService.Instance.StartListening();
},
error =>
{
// If profile fetch fails but we have a cache, let them in
if (cached != null)
{
Debug.LogWarning($"[Boot] Network profile fetch failed, using cache");
Debug.LogWarning($"[Boot] Profile fetch failed, falling back to cache.");
GoToHome();
}
else
{
Debug.LogError($"[Boot] Failed to load user profile: {error}");
Debug.LogError($"[Boot] Critical load error: {error}");
GoToLogin();
}
}
);
}
// ─── Auth State Listener (Safety Net Only) ───────────────────────
private async UniTask EnsureNetworkConnection()
{
bool isConnected = false;
int attempts = 0;
while (!isConnected)
{
attempts++;
UpdateStatus(attempts == 1 ? "Connecting..." : "Waiting for network...");
if (simulateNetworkFailure)
{
Debug.LogWarning("[TEST] simulateNetworkFailure is ON. Mocking connection failure.");
isConnected = false;
}
else
{
isConnected = await SupabaseManager.Instance.Initialize();
}
if (!isConnected)
{
// Wait 3 seconds before the next heartbeat
// Uses the object's token to stop if the user quits the app
await UniTask.Delay(TimeSpan.FromSeconds(3), cancellationToken: this.GetCancellationTokenOnDestroy());
}
}
UpdateStatus("Connected!");
await UniTask.Delay(500); // Visual polish
}
private void UpdateStatus(string message)
{
if (statusText != null)
statusText.text = message;
Debug.Log($"[AppRouter] {message}");
}
// ─── Auth State Listener (Safety Net) ───────────────────────────
private void OnAuthStateChanged(IGotrueClient<Supabase.Gotrue.User, Supabase.Gotrue.Session> sender, Constants.AuthState newState)
{
switch (newState)
{
case Constants.AuthState.SignedOut:
// Only react if WE didn't trigger the sign-out
if (!SupabaseAuthentication.Instance.IsLoading)
{
Debug.LogWarning("[Auth] Unexpected sign-out detected");
UserService.Instance.ClearUser();
GoToLogin();
}
break;
case Constants.AuthState.TokenRefreshed:
Debug.Log("[Auth] Token refreshed");
Debug.Log("[Auth] Session token refreshed.");
break;
}
}
// ─── Navigation ──────────────────────────────────────────────────
public async static void GoToLogin()
// ─── Navigation Logic ───────────────────────────────────────────
public static void GoToLogin()
{
TransitionManager.Instance().Transition("Login", _instance.transitionSettings, 0f);
}
public async static void GoToHome()
public static void GoToHome()
{
TransitionManager.Instance().Transition("MainMenu", _instance.transitionSettings, 0f);
UserService.Instance.StartListening();
......@@ -151,7 +203,7 @@ public class AppRouter : MonoBehaviour
try { SSAudioManager.Instance?.StopMusic(); } catch { }
}
// ─── Helpers ─────────────────────────────────────────────────────
// ─── UI Helpers ──────────────────────────────────────────────────
private static void HideSplash()
{
if (_instance == null) return;
......@@ -163,6 +215,6 @@ public class AppRouter : MonoBehaviour
{
if (splashScreen != null) splashScreen.SetActive(false);
if (errorPanel != null) errorPanel.SetActive(true);
Debug.LogError($"[Boot] {message}");
Debug.LogError($"[Boot Error] {message}");
}
}
\ No newline at end of file
......@@ -50,23 +50,23 @@ public class SupabaseManager
client.Auth.SetPersistence(new UnitySession());
client.Auth.Options.AllowUnconfirmedUserSessions = true;
// string url = $"{SupabaseSettings.SupabaseURL}/auth/v1/settings?apikey={SupabaseSettings.SupabaseAnonKey}";
string url = $"{SupabaseSettings.SupabaseURL}/auth/v1/settings?apikey={SupabaseSettings.SupabaseAnonKey}";
// await client.InitializeAsync();
// try
// {
// client.Auth.Online = await _networkStatus.StartAsync(url);
// }
// catch (NotSupportedException)
// {
// client.Auth.Online = true;
// }
// catch (Exception e)
// {
// Debug.LogWarning($"Network check failed: {e.Message}");
// client.Auth.Online = false;
// }
try
{
client.Auth.Online = await _networkStatus.StartAsync(url);
}
catch (NotSupportedException)
{
client.Auth.Online = true;
}
catch (Exception e)
{
Debug.LogWarning($"Network check failed: {e.Message}");
client.Auth.Online = false;
}
// if (client.Auth.Online)
// {
......
......@@ -95,6 +95,7 @@ public class HomeController : MonoBehaviour
SetPlayButtonsEnabled(enough);
},
_ => SetPlayButtonsEnabled(false),
curriculumId: 1,
gradeId: user.Grade,
termId: user.Term
));
......
......@@ -166,7 +166,9 @@ MonoBehaviour:
m_EditorClassIdentifier: Assembly-CSharp::AppRouter
splashScreen: {fileID: 90795484556287063}
errorPanel: {fileID: 0}
statusText: {fileID: 0}
transitionSettings: {fileID: 11400000, guid: 91673b50629b1ae4f938d0b25135d085, type: 2}
simulateNetworkFailure: 0
--- !u!1 &787965442
GameObject:
m_ObjectHideFlags: 0
......
......@@ -349,6 +349,7 @@ namespace com.al_arcade.shared
// ═══════════════════════════════════════════════════
public IEnumerator GetChapters(Action<ChapterInfo[]> onSuccess,
Action<string> onError,
int curriculumId = 0,
int subjectId = 0,
int gradeId = 0,
int termId = 0)
......@@ -357,6 +358,7 @@ namespace com.al_arcade.shared
if (subjectId > 0) p["subject_id"] = subjectId.ToString();
if (gradeId > 0) p["grade_id"] = gradeId.ToString();
if (termId > 0) p["term_id"] = termId.ToString();
if (curriculumId > 0) p["curriculum_id"] = curriculumId.ToString();
yield return GetRequest("get_chapters", p,
json =>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment