11package org.mozilla.tryfox
22
3- import android.content.ActivityNotFoundException
43import android.content.Intent
5- import android.net.Uri
64import android.os.Bundle
75import android.util.Log
8- import android.widget.Toast
96import androidx.activity.ComponentActivity
107import androidx.activity.compose.setContent
118import androidx.activity.enableEdgeToEdge
129import androidx.compose.runtime.Composable
13- import androidx.compose.runtime.LaunchedEffect
14- import androidx.core.content.FileProvider
1510import androidx.navigation.NavHostController
1611import androidx.navigation.NavType
1712import androidx.navigation.compose.NavHost
@@ -20,30 +15,58 @@ import androidx.navigation.compose.rememberNavController
2015import androidx.navigation.navArgument
2116import androidx.navigation.navDeepLink
2217import org.koin.androidx.compose.koinViewModel
23- import org.koin.androidx.viewmodel.ext.android.viewModel
18+ import org.koin.core.parameter.parametersOf
2419import org.mozilla.tryfox.ui.screens.HomeScreen
25- import org.mozilla.tryfox.ui.screens.HomeViewModel
2620import org.mozilla.tryfox.ui.screens.ProfileScreen
27- import org.mozilla.tryfox.ui.screens.ProfileViewModel
2821import org.mozilla.tryfox.ui.screens.TryFoxMainScreen
2922import org.mozilla.tryfox.ui.theme.TryFoxTheme
30- import java.io.File
3123import java.net.URLDecoder
3224
25+ /* *
26+ * Sealed class representing the navigation screens in the application.
27+ * Each object corresponds to a specific route in the navigation graph.
28+ */
3329sealed class NavScreen (val route : String ) {
30+ /* *
31+ * Represents the Home screen.
32+ */
3433 data object Home : NavScreen (" home" )
34+
35+ /* *
36+ * Represents the Treeherder search screen without arguments.
37+ */
3538 data object TreeherderSearch : NavScreen (" treeherder_search" )
39+
40+ /* *
41+ * Represents the Treeherder search screen with project and revision arguments.
42+ */
3643 data object TreeherderSearchWithArgs : NavScreen (" treeherder_search/{project}/{revision}" ) {
44+ /* *
45+ * Creates a route for the Treeherder search screen with the given project and revision.
46+ * @param project The project name.
47+ * @param revision The revision hash.
48+ * @return The formatted route string.
49+ */
3750 fun createRoute (project : String , revision : String ) = " treeherder_search/$project /$revision "
3851 }
52+
53+ /* *
54+ * Represents the Profile screen.
55+ */
3956 data object Profile : NavScreen (" profile" )
57+
58+ /* *
59+ * Represents the Profile screen filtered by email.
60+ */
4061 data object ProfileByEmail : NavScreen (" profile_by_email?email={email}" )
4162}
4263
64+ /* *
65+ * The main activity of the TryFox application.
66+ * This activity sets up the navigation host and handles deep links.
67+ */
4368class MainActivity : ComponentActivity () {
4469
45- // Inject FenixInstallerViewModel using Koin
46- private val tryFoxViewModel: TryFoxViewModel by viewModel()
4770 private lateinit var navController: NavHostController
4871
4972 override fun onCreate (savedInstanceState : Bundle ? ) {
@@ -53,7 +76,7 @@ class MainActivity : ComponentActivity() {
5376 setContent {
5477 TryFoxTheme {
5578 // Pass the Koin-injected ViewModel
56- AppNavigation (tryFoxViewModel )
79+ AppNavigation ()
5780 }
5881 }
5982 }
@@ -67,47 +90,29 @@ class MainActivity : ComponentActivity() {
6790 }
6891 }
6992
70- private fun installApk (file : File ) {
71- val fileUri: Uri = FileProvider .getUriForFile(
72- this ,
73- " ${BuildConfig .APPLICATION_ID } .provider" ,
74- file,
75- )
76- val intent = Intent (Intent .ACTION_VIEW ).apply {
77- setDataAndType(fileUri, " application/vnd.android.package-archive" )
78- addFlags(Intent .FLAG_GRANT_READ_URI_PERMISSION )
79- addFlags(Intent .FLAG_ACTIVITY_NEW_TASK )
80- }
81- try {
82- startActivity(intent)
83- } catch (e: ActivityNotFoundException ) {
84- Toast .makeText(this , " No application found to install APK" , Toast .LENGTH_LONG ).show()
85- Log .e(" MainActivity" , " Error installing APK" , e)
86- }
87- }
88-
93+ /* *
94+ * Composable function that sets up the application's navigation.
95+ * It defines the navigation graph and handles different routes and deep links.
96+ */
8997 @Composable
90- fun AppNavigation (mainActivityViewModel : TryFoxViewModel ) {
98+ fun AppNavigation () {
9199 val localNavController = rememberNavController()
92100 this @MainActivity.navController = localNavController
93101 Log .d(" MainActivity" , " AppNavigation: NavController instance assigned: $localNavController " )
94102
95103 NavHost (navController = localNavController, startDestination = NavScreen .Home .route) {
96104 composable(NavScreen .Home .route) {
97105 // Inject HomeViewModel using Koin in Composable
98- val homeViewModel: HomeViewModel = koinViewModel()
99- homeViewModel.onInstallApk = ::installApk
100106 HomeScreen (
101107 onNavigateToTreeherder = { localNavController.navigate(NavScreen .TreeherderSearch .route) },
102108 onNavigateToProfile = { localNavController.navigate(NavScreen .Profile .route) },
103- homeViewModel = homeViewModel ,
109+ homeViewModel = koinViewModel() ,
104110 )
105111 }
106112 composable(NavScreen .TreeherderSearch .route) {
107113 // mainActivityViewModel is already injected and passed as a parameter
108- mainActivityViewModel.onInstallApk = ::installApk
109114 TryFoxMainScreen (
110- tryFoxViewModel = mainActivityViewModel ,
115+ tryFoxViewModel = koinViewModel() ,
111116 onNavigateUp = { localNavController.popBackStack() },
112117 )
113118 }
@@ -134,52 +139,29 @@ class MainActivity : ComponentActivity() {
134139 " MainActivity" ,
135140 " TreeherderSearchWithArgs composable: project='$project ', revision='$revision ' from NavBackStackEntry. ID: ${backStackEntry.id} " ,
136141 )
137-
138- LaunchedEffect (project, revision) {
139- Log .d(
140- " MainActivity" ,
141- " TreeherderSearchWithArgs LaunchedEffect: project='$project ', revision='$revision '" ,
142- )
143- mainActivityViewModel.setRevisionFromDeepLinkAndSearch(
144- project,
145- revision,
146- )
147- }
148- mainActivityViewModel.onInstallApk = ::installApk
149142 TryFoxMainScreen (
150- tryFoxViewModel = mainActivityViewModel ,
143+ tryFoxViewModel = koinViewModel { parametersOf(project, revision) } ,
151144 onNavigateUp = { localNavController.popBackStack() },
152145 )
153146 }
154147 composable(NavScreen .Profile .route) {
155- // Inject ProfileViewModel using Koin in Composable
156- val profileViewModel: ProfileViewModel = koinViewModel()
157- profileViewModel.onInstallApk = ::installApk // Assuming ProfileViewModel also needs this
158148 ProfileScreen (
159149 onNavigateUp = { localNavController.popBackStack() },
160- profileViewModel = profileViewModel ,
150+ profileViewModel = koinViewModel() ,
161151 )
162152 }
163153 composable(
164154 route = NavScreen .ProfileByEmail .route,
165155 arguments = listOf (navArgument(" email" ) { type = NavType .StringType }),
166156 deepLinks = listOf (navDeepLink { uriPattern = " https://treeherder.mozilla.org/jobs?repo={repo}&author={email}" }),
167157 ) { backStackEntry ->
168- val profileViewModel: ProfileViewModel = koinViewModel()
169- val encodedEmail = backStackEntry.arguments?.getString(" email" )
170-
171- LaunchedEffect (encodedEmail) {
172- encodedEmail?.let {
173- val email = URLDecoder .decode(it, " UTF-8" )
174- profileViewModel.updateAuthorEmail(email)
175- profileViewModel.searchByAuthor()
176- }
158+ val email = backStackEntry.arguments?.getString(" email" )?.let {
159+ URLDecoder .decode(it, " UTF-8" )
177160 }
178161
179- profileViewModel.onInstallApk = ::installApk
180162 ProfileScreen (
181163 onNavigateUp = { localNavController.popBackStack() },
182- profileViewModel = profileViewModel ,
164+ profileViewModel = koinViewModel { parametersOf(email) } ,
183165 )
184166 }
185167 }
0 commit comments