# Architecture d'iMedia TV+ ## Principes fondateurs - **Clean Architecture** simplifiée : UI → ViewModel → Repository → Data - **Unidirectional Data Flow (UDF)** : les events montent, les states descendent - **Single Activity** : une seule `MainActivity`, navigation par écrans Compose - **Programmation réactive** : Kotlin Coroutines + Flow pour tout ce qui est async - **Séparation claire** : chaque couche ignore l'existence des couches au-dessus d'elle ## Flux de données complet ```mermaid sequenceDiagram actor User as Utilisateur (Télécommande) participant UI as Compose Screen participant VM as ViewModel participant Repo as Repository participant API as Retrofit / Xtream participant DB as Room (Cache) participant Store as EncryptedSP User->>UI: Appuie sur OK (connexion) UI->>VM: Event: Login(server, user, pass) VM->>Repo: authRepository.login(server, user, pass) Repo->>API: POST /player_api.php?username=... API-->>Repo: Response { auth: "1", status: "Active" } Repo->>Store: saveCredentials(encrypted) Repo-->>VM: Result.Success(userInfo) VM->>VM: _uiState = UiState.Success VM-->>UI: StateFlow: HomeScreen data UI-->>User: Affiche la liste des chaînes ``` ## Diagramme de navigation des écrans ```mermaid stateDiagram-v2 [*] --> SplashScreen SplashScreen --> LoginScreen : Pas de session SplashScreen --> HomeScreen : Session valide LoginScreen --> HomeScreen : Connexion OK LoginScreen --> LoginScreen : Erreur → reste HomeScreen --> PlayerScreen : Sélection chaîne Live HomeScreen --> ProgramGuideScreen : Appui Guide TV HomeScreen --> ReplayGuideScreen : Appui Replay HomeScreen --> VodScreen : Appui VOD HomeScreen --> SeriesScreen : Appui Séries ProgramGuideScreen --> PlayerScreen : "Regarder" ReplayGuideScreen --> PlayerScreen : "Revoir" VodScreen --> PlayerScreen : Lecture film SeriesScreen --> PlayerScreen : Lecture épisode PlayerScreen --> HomeScreen : Retour × 2 PlayerScreen --> ProgramGuideScreen : Retour × 1 (si venu du guide) PlayerScreen --> ReplayGuideScreen : Retour × 1 (si venu du replay) HomeScreen --> ConfirmQuit : Retour ConfirmQuit --> [*] : Confirmer ConfirmQuit --> HomeScreen : Annuler ``` ## Organisation des ViewModels Chaque ViewModel expose : - Un `StateFlow>` pour l'état de l'UI - Des fonctions `onAction(X)` pour les intents utilisateur - Une vue unique (`viewModelScope`) pour les coroutines ```kotlin class HomeViewModel( private val liveRepo: LiveRepository, private val epgRepo: EpgRepository, private val favRepo: FavoritesRepository ) : ViewModel() { private val _uiState = MutableStateFlow>(UiState.Loading) val uiState: StateFlow> = _uiState.asStateFlow() sealed interface Action { data class SelectCategory(val id: Int) : Action data class ToggleFavorite(val streamId: Int) : Action data class PinChannel(val streamId: Int) : Action object Refresh : Action } fun onAction(action: Action) { // ... } } ``` ## Injection de dépendances Utilisation d'un **manual DI** simple via `AppContainer` (pas de framework lourd comme Hilt/Dagger pour un projet de cette taille). ```kotlin // AppContainer.kt class AppContainer(context: Context) { private val secureStorage = SecureStorage(context) private val okHttpClient = OkHttpClient.Builder() .addInterceptor(ErrorInterceptor()) .addInterceptor(AuthInterceptor(secureStorage)) .connectTimeout(15, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .build() private val retrofit = Retrofit.Builder() .baseUrl("http://placeholder") // overridden per-call .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() val xtreamApi = retrofit.create(XtreamApi::class.java) // Repositories val authRepository = AuthRepository(xtreamApi, secureStorage) val liveRepository = LiveRepository(xtreamApi) val epgRepository = EpgRepository(xtreamApi, EpgDatabase.getInstance(context)) // ... } ``` ## Décisions d'architecture | Décision | Alternative écartée | Raison | |----------|-------------------|--------| | Single Activity | Multi-Activity | Navigation + état simplifiés | | Manual DI | Hilt / Koin | Pas de overhead pour projet solo | | Room pour cache EPG | Simple JSON file | Requêtes typées, ACID, migrations | | EncryptedSharedPreferences | DataStore | Chiffrement natif, API simple | | ViewModel + StateFlow | MVVM + LiveData | Flow plus puissant, compose-ready | | sealed interface pour actions | Callbacks | Testable, traçable, immutable |