|
1 | 1 | package com.simdea.deeplinktester |
2 | 2 |
|
| 3 | +import android.app.Application |
| 4 | +import android.content.ActivityNotFoundException |
3 | 5 | import android.content.Intent |
4 | 6 | import android.net.Uri |
5 | 7 | import android.os.Bundle |
6 | | -import androidx.appcompat.app.AppCompatActivity |
7 | | -import androidx.databinding.DataBindingUtil |
8 | | -import com.simdea.deeplinktester.databinding.ActivityMainBinding |
| 8 | +import androidx.activity.ComponentActivity |
| 9 | +import androidx.activity.compose.setContent |
| 10 | +import androidx.compose.foundation.layout.* |
| 11 | +import androidx.compose.material.icons.Icons |
| 12 | +import androidx.compose.material.icons.filled.History |
| 13 | +import androidx.compose.material.icons.filled.Home |
| 14 | +import androidx.compose.material3.* |
| 15 | +import androidx.compose.runtime.* |
| 16 | +import androidx.compose.ui.Alignment |
| 17 | +import androidx.compose.ui.ExperimentalComposeUiApi |
| 18 | +import androidx.compose.ui.Modifier |
| 19 | +import androidx.compose.ui.platform.LocalContext |
| 20 | +import androidx.compose.ui.platform.LocalSoftwareKeyboardController |
| 21 | +import androidx.compose.foundation.text.KeyboardActions |
| 22 | +import androidx.compose.foundation.text.KeyboardOptions |
| 23 | +import androidx.compose.ui.text.input.ImeAction |
| 24 | +import androidx.compose.ui.res.stringResource |
| 25 | +import androidx.compose.ui.tooling.preview.Preview |
| 26 | +import androidx.compose.ui.unit.dp |
| 27 | +import androidx.lifecycle.viewmodel.compose.viewModel |
| 28 | +import androidx.navigation.NavDestination.Companion.hierarchy |
| 29 | +import androidx.navigation.NavGraph.Companion.findStartDestination |
| 30 | +import androidx.navigation.compose.NavHost |
| 31 | +import androidx.navigation.compose.composable |
| 32 | +import androidx.navigation.compose.currentBackStackEntryAsState |
| 33 | +import androidx.navigation.compose.rememberNavController |
| 34 | +import com.simdea.deeplinktester.data.Deeplink |
| 35 | +import com.simdea.deeplinktester.ui.ads.BannerAd |
| 36 | +import com.simdea.deeplinktester.ui.history.HistoryScreen |
| 37 | +import com.simdea.deeplinktester.ui.history.HistoryViewModel |
| 38 | +import com.simdea.deeplinktester.ui.theme.DeepLinkTestAndroidTheme |
| 39 | +import kotlinx.coroutines.launch |
9 | 40 |
|
10 | | -class MainActivity : AppCompatActivity() { |
| 41 | +sealed class Screen(val route: String, val resourceId: Int, val icon: @Composable () -> Unit) { |
| 42 | + object Main : Screen("main", R.string.main_screen_title, { Icon(Icons.Filled.Home, contentDescription = null) }) |
| 43 | + object History : Screen("history", R.string.history_screen_title, { Icon(Icons.Filled.History, contentDescription = null) }) |
| 44 | +} |
11 | 45 |
|
12 | | - private val dataBinding: ActivityMainBinding by lazy { |
13 | | - DataBindingUtil.setContentView(this, R.layout.activity_main) |
14 | | - } |
| 46 | +val items = listOf( |
| 47 | + Screen.Main, |
| 48 | + Screen.History |
| 49 | +) |
15 | 50 |
|
| 51 | +class MainActivity : ComponentActivity() { |
16 | 52 | override fun onCreate(savedInstanceState: Bundle?) { |
17 | 53 | super.onCreate(savedInstanceState) |
| 54 | + setContent { |
| 55 | + DeepLinkTestAndroidTheme { |
| 56 | + AppNavigation() |
| 57 | + } |
| 58 | + } |
| 59 | + } |
| 60 | +} |
18 | 61 |
|
19 | | - dataBinding.lifecycleOwner = this |
| 62 | +@OptIn(ExperimentalMaterial3Api::class) |
| 63 | +@Composable |
| 64 | +fun AppNavigation() { |
| 65 | + val navController = rememberNavController() |
| 66 | + val context = LocalContext.current |
| 67 | + val historyViewModel: HistoryViewModel = viewModel( |
| 68 | + factory = HistoryViewModel.HistoryViewModelFactory( |
| 69 | + context.applicationContext as Application |
| 70 | + ) |
| 71 | + ) |
| 72 | + val snackbarHostState = remember { SnackbarHostState() } |
| 73 | + val scope = rememberCoroutineScope() |
20 | 74 |
|
21 | | - dataBinding.btnSubmit.setOnClickListener { |
22 | | - launchBrowser(dataBinding.edtDL.text.toString()) |
| 75 | + Scaffold( |
| 76 | + snackbarHost = { SnackbarHost(snackbarHostState) }, |
| 77 | + bottomBar = { |
| 78 | + Column { |
| 79 | + BannerAd() |
| 80 | + NavigationBar { |
| 81 | + val navBackStackEntry by navController.currentBackStackEntryAsState() |
| 82 | + val currentDestination = navBackStackEntry?.destination |
| 83 | + items.forEach { screen -> |
| 84 | + NavigationBarItem( |
| 85 | + icon = { screen.icon() }, |
| 86 | + label = { Text(stringResource(screen.resourceId)) }, |
| 87 | + selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true, |
| 88 | + onClick = { |
| 89 | + navController.navigate(screen.route) { |
| 90 | + popUpTo(navController.graph.findStartDestination().id) { |
| 91 | + saveState = true |
| 92 | + } |
| 93 | + launchSingleTop = true |
| 94 | + restoreState = true |
| 95 | + } |
| 96 | + } |
| 97 | + ) |
| 98 | + } |
| 99 | + } |
| 100 | + } |
| 101 | + } |
| 102 | + ) { innerPadding -> |
| 103 | + NavHost(navController, startDestination = Screen.Main.route, Modifier.padding(innerPadding)) { |
| 104 | + composable(Screen.Main.route) { |
| 105 | + MainScreen( |
| 106 | + onLaunch = { deeplink -> |
| 107 | + historyViewModel.addDeeplink(deeplink) |
| 108 | + try { |
| 109 | + val launchBrowser = Intent(Intent.ACTION_VIEW).apply { |
| 110 | + data = Uri.parse(deeplink.deeplink) |
| 111 | + flags = Intent.FLAG_ACTIVITY_NEW_TASK |
| 112 | + } |
| 113 | + context.startActivity(launchBrowser) |
| 114 | + } catch (e: ActivityNotFoundException) { |
| 115 | + scope.launch { |
| 116 | + snackbarHostState.showSnackbar( |
| 117 | + message = context.getString(R.string.activity_not_found_error), |
| 118 | + duration = SnackbarDuration.Short |
| 119 | + ) |
| 120 | + } |
| 121 | + } |
| 122 | + } |
| 123 | + ) |
| 124 | + } |
| 125 | + composable(Screen.History.route) { |
| 126 | + val history by historyViewModel.history.collectAsState() |
| 127 | + HistoryScreen( |
| 128 | + history = history, |
| 129 | + onRetry = { deeplink -> |
| 130 | + try { |
| 131 | + val launchBrowser = Intent(Intent.ACTION_VIEW).apply { |
| 132 | + data = Uri.parse(deeplink.deeplink) |
| 133 | + flags = Intent.FLAG_ACTIVITY_NEW_TASK |
| 134 | + } |
| 135 | + context.startActivity(launchBrowser) |
| 136 | + } catch (e: ActivityNotFoundException) { |
| 137 | + scope.launch { |
| 138 | + snackbarHostState.showSnackbar( |
| 139 | + message = context.getString(R.string.activity_not_found_error), |
| 140 | + duration = SnackbarDuration.Short |
| 141 | + ) |
| 142 | + } |
| 143 | + } |
| 144 | + }, |
| 145 | + onRemove = { historyViewModel.removeDeeplink(it) } |
| 146 | + ) |
| 147 | + } |
23 | 148 | } |
| 149 | + } |
| 150 | +} |
| 151 | + |
| 152 | +@OptIn(ExperimentalComposeUiApi::class) |
| 153 | +@Composable |
| 154 | +fun MainScreen( |
| 155 | + onLaunch: (Deeplink) -> Unit |
| 156 | +) { |
| 157 | + var text by remember { mutableStateOf("") } |
| 158 | + val keyboardController = LocalSoftwareKeyboardController.current |
24 | 159 |
|
| 160 | + val submit = { |
| 161 | + if (text.isNotBlank()) { |
| 162 | + onLaunch(Deeplink(deeplink = text)) |
| 163 | + keyboardController?.hide() |
| 164 | + } |
25 | 165 | } |
26 | 166 |
|
27 | | - private fun launchBrowser(action: String) { |
28 | | - val launchBrowser = Intent(Intent.ACTION_VIEW).apply { |
29 | | - data = Uri.parse(action) |
30 | | - flags = Intent.FLAG_ACTIVITY_NEW_TASK |
| 167 | + Column( |
| 168 | + modifier = Modifier.fillMaxSize(), |
| 169 | + verticalArrangement = Arrangement.Center, |
| 170 | + horizontalAlignment = Alignment.CenterHorizontally |
| 171 | + ) { |
| 172 | + OutlinedTextField( |
| 173 | + value = text, |
| 174 | + onValueChange = { text = it }, |
| 175 | + label = { Text(stringResource(R.string.deeplink_label)) }, |
| 176 | + modifier = Modifier.width(300.dp), |
| 177 | + singleLine = true, |
| 178 | + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), |
| 179 | + keyboardActions = KeyboardActions(onDone = { submit() }) |
| 180 | + ) |
| 181 | + Spacer(modifier = Modifier.height(16.dp)) |
| 182 | + Button(onClick = submit) { |
| 183 | + Text(stringResource(R.string.open_deeplink_button)) |
31 | 184 | } |
32 | | - startActivity(launchBrowser) |
33 | 185 | } |
| 186 | +} |
34 | 187 |
|
| 188 | +@Preview(showBackground = true) |
| 189 | +@Composable |
| 190 | +fun DefaultPreview() { |
| 191 | + DeepLinkTestAndroidTheme { |
| 192 | + MainScreen(onLaunch = {}) |
| 193 | + } |
35 | 194 | } |
0 commit comments