Skip to content

Instantly share code, notes, and snippets.

@Debdutta-Panda
Created June 4, 2022 06:24
Show Gist options
  • Select an option

  • Save Debdutta-Panda/999e7576af798c212aa3118f1320b963 to your computer and use it in GitHub Desktop.

Select an option

Save Debdutta-Panda/999e7576af798c212aa3118f1320b963 to your computer and use it in GitHub Desktop.
Deep Link in jetpack compose setup and test
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.debduttapanda.powernavigation">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.PowerNavigation"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.PowerNavigation">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="powernavigation.debduttapanda.com"
/>
<data
android:scheme="powernavigation"
android:host="powernavigation.debduttapanda.com"
/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<!DOCTYPE html>
<html>
<head>
<title>Deep Link</title>
<style>
:root {
--textColor1: #008cff;
--textColor2: #fff;
--textColor3: #737594;
}
html, body {
height: 100%;
}
body {
background-color: #0e0e30;
margin: 0;
}
.wrapper {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 60px;
}
.button {
display: block;
margin: 20px 0;
min-height: 50px;
padding: 13px 24px;
font-family: "Lucida Grande", "Helvetica", sans-serif;
font-size: 16px;
line-height: 20px;
font-weight: bold;
text-transform: uppercase;
text-align: center;
border: none;
border-radius: 4px;
outline: none;
box-shadow: none;
background-color: transparent;
background-position: top center;
cursor: pointer;
transition: 0.3s ease-in-out;
transition-property: background, color;
text-decoration: none;
}
.button1 {
position: relative;
display: block;
color: var(--textColor1);
border-radius: 26px;
box-sizing: border-box;
border: 2px solid transparent;
background-color: #0e0e30;
background-clip: padding-box;
overflow: hidden;
z-index: 1;
}
.button1::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
border: 2px solid transparent;
background-image: linear-gradient(#0e0e30, #0e0e30), linear-gradient(90deg, #008cff, #6942ef);
background-clip: padding-box, border-box;
background-repeat: repeat-x;
background-size: calc(100% + 2px * 2) calc(100% + 2px * 2);
background-position: center;
border-radius: 26px;
z-index: -1;
transition: border-color 0.2s;
}
.button1::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 70vmax;
height: 70vmax;
border-radius: 50%;
background-image: linear-gradient(90deg, #008cff, #6942ef);
transform-origin: center;
transform: translate(-50%, -50%) scale(0);
transition: transform 0.4s ease-in-out;
z-index: -1;
}
.button1:hover {
color: var(--textColor2);
}
.button1:hover::after {
transform: translate(-50%, -50%) scale(1);
}
.button1:active {
color: #c3c4d5;
}
.button1:focus {
color: white;
}
.button1:focus::before {
border-color: #00b8d9;
}
.button2 {
position: relative;
color: var(--textColor2);
border-radius: 26px;
background-image: linear-gradient(90deg, #0065ff, #6942ef, #6554c0, #008cff, #0065ff, #6942ef);
background-size: 400%;
background-position: 0% 0%;
}
.button2::before {
content: "";
position: absolute;
left: -2px;
top: -2px;
right: -2px;
bottom: -2px;
border-radius: 26px;
background-image: linear-gradient(90deg, #0065ff, #6942ef, #6554c0, #008cff, #0065ff, #6942ef);
background-size: 500%;
background-position: 0% 0%;
filter: blur(10px);
opacity: 0;
z-index: -1;
transition: opacity 0.2s;
}
.button2:hover {
animation: gradientRotate 2s infinite;
}
.button2:hover::before {
opacity: 1;
animation: gradientRotate 2s infinite;
}
.button2:active {
color: #c3c4d5;
}
.button2:focus::before {
opacity: 1;
}
.button3 {
position: relative;
border-radius: 26px;
color: var(--textColor3);
background-color: transparent;
border: 2px solid transparent;
background-clip: padding-box;
overflow: hidden;
z-index: 1;
}
.button3::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
border: 2px solid #313152;
background-position: center;
border-radius: 26px;
z-index: -1;
transition: border-color 0.2s;
}
.button3::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 70vmax;
height: 70vmax;
border-radius: 50%;
background-color: #737594;
opacity: 0.3;
transform-origin: center;
transform: translate(-50%, -50%) scale(0);
transition: transform 0.4s ease-in-out;
z-index: -1;
}
.button3--active::after {
background-color: #f7841d;
opacity: 1;
}
.button3:focus {
color: var(--textColor2);
}
.button3:focus::before {
border-color: #737594;
}
.button3:hover, .button3:hover:focus {
color: var(--textColor2);
}
.button3:hover::after, .button3:hover:focus::after {
transform: translate(-50%, -50%) scale(1);
}
.button3:active {
color: #c3c4d5;
}
.button4 {
position: relative;
border-radius: 26px;
color: var(--textColor3);
border: none;
overflow: hidden;
z-index: 1;
}
.button4::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
background-color: #0e0e30;
background-clip: padding-box;
border: 2px solid transparent;
border-radius: 26px;
z-index: -1;
transition: border-color 0.2s;
}
.button4::after {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
background-color: #737594;
border-radius: 26px;
z-index: -2;
transform: translate(-150%, -150%);
transform-origin: left top;
transition: transform 0.2s;
}
.button4:hover {
color: white;
}
.button4:hover::after {
transform: translate(0, 0);
}
.button4:active {
color: #c3c4d5;
}
.button4:focus {
color: #d8d8e3;
}
@keyframes gradientRotate {
0% {
background-position: 0% 0%;
}
100% {
background-position: 100% 100%;
}
}
</style>
</head>
<body>
<div class="wrapper">
<a class="button button1" href="powernavigation://powernavigation.debduttapanda.com/300?bonus=50">
300 + 50 bonus
</a>
<a class="button button1" href="powernavigation://powernavigation.debduttapanda.com/400?bonus=20">400 + 20 bonus</a>
<a class="button button1" href="powernavigation://powernavigation.debduttapanda.com/500?bonus=60">500 + 60 bonus</a>
<a class="button button1" href="powernavigation://powernavigation.debduttapanda.com/700">700 + no bonus</a>
<a class="button button1" href="powernavigation://powernavigation.debduttapanda.com/300">300 + no bonus</a>
</div>
</body>
</html>
package com.debduttapanda.powernavigation
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import androidx.navigation.navDeepLink
import com.debduttapanda.powernavigation.ui.theme.PowerNavigationTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val pageAViewModel: PageAViewModel by viewModels()
val pageBViewModel: PageBViewModel by viewModels()
setContent {
PowerNavigationTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Text(
"With MVVM",
fontSize = 24.sp,
color = Color(0xfff44336),
fontWeight = FontWeight.Bold
)
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "page_a"){
composable(
"page_a"
){
PageA(navController,pageAViewModel)
}
composable(
"page_b/{money}?bonus={bonus}",
arguments = listOf(
navArgument("money"){
type = NavType.IntType
},
navArgument("bonus"){
type = NavType.IntType
defaultValue = 0
}
),
deepLinks = listOf(
navDeepLink {
uriPattern = "https://powernavigation.debduttapanda.com/{money}?bonus={bonus}"
},
navDeepLink {
uriPattern = "powernavigation://powernavigation.debduttapanda.com/{money}?bonus={bonus}"
}
)
){backStackEntry->
PageB(
navController,
pageBViewModel,
backStackEntry.arguments?.getInt("money"),
backStackEntry.arguments?.getInt("bonus"),
)
}
}
}
}
}
}
}
package com.debduttapanda.powernavigation
import androidx.compose.runtime.MutableState
import androidx.lifecycle.LifecycleOwner
import androidx.navigation.NavHostController
typealias NavigationCallback = (NavHostController,LifecycleOwner)->Unit
fun MutableState<NavigationCallback?>.navigate(block: NavigationCallback?){
this.value = {navHostController, lifecycleOwner ->
block?.invoke(navHostController,lifecycleOwner)
this.value = null
}
}
fun MutableState<NavigationCallback?>.forward(navHostController: NavHostController,lifecycleOwner: LifecycleOwner){
this.value?.invoke(navHostController,lifecycleOwner)
}
package com.debduttapanda.powernavigation
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
@Composable
fun PageA(navController: NavHostController, pageAViewModel: PageAViewModel) {
val owner = LocalLifecycleOwner.current
LaunchedEffect(key1 = pageAViewModel.navigation.value){
pageAViewModel.navigation.forward(navController,owner)
}
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
){
TextField(
value = pageAViewModel.money.value.toString(),
onValueChange = {
try {
pageAViewModel.money.value = it.toInt()
} catch (e: Exception) {
pageAViewModel.money.value = 0
}
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number
)
)
Row(
verticalAlignment = Alignment.CenterVertically
){
Text("Bonus")
Checkbox(
checked = pageAViewModel.sendBonus.value,
onCheckedChange = {
pageAViewModel.sendBonus.value = it
}
)
}
Text(
"Page A: Send Money",
color = Color(0xfff44336),
fontSize = 24.sp,
fontWeight = FontWeight.Bold
)
Button(
onClick = {
pageAViewModel.onSendClick()
},
colors = ButtonDefaults.buttonColors(
backgroundColor = Color(0xfff44336),
contentColor = Color.White
)
) {
Text("Send Money")
}
if((pageAViewModel.totalReceived.value)>0){
Text("Acknowledgement of ${pageAViewModel.totalReceived.value} received")
}
}
}
package com.debduttapanda.powernavigation
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
class PageAViewModel: ViewModel() {
val navigation = mutableStateOf<NavigationCallback?>(null)
val money = mutableStateOf(0)
val sendBonus = mutableStateOf(false)
val totalReceived = mutableStateOf(0)
fun onSendClick() {
navigation.navigate{navHostController, lifecycleOwner ->
navHostController
.currentBackStackEntry
?.savedStateHandle
?.getLiveData<Int>("totalReceived")
?.observe(lifecycleOwner){
totalReceived.value = it
navHostController
.currentBackStackEntry
?.savedStateHandle
?.remove<Int>("totalReceived")
}
if(!sendBonus.value){
navHostController.navigate("page_b/${money.value}")
}
else{
navHostController.navigate("page_b/${money.value}?bonus=50")
}
}
}
}
package com.debduttapanda.powernavigation
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
@Composable
fun PageB(
navController: NavHostController,
pageBViewModel: PageBViewModel,
receivedMoney: Int?,
bonus: Int?
) {
val owner = LocalLifecycleOwner.current
LaunchedEffect(key1 = Unit){
pageBViewModel.setArguments(receivedMoney,bonus)
}
LaunchedEffect(key1 = pageBViewModel.navigation.value){
pageBViewModel.navigation.forward(navController,owner)
}
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
){
Text(
"Page B: received money ${pageBViewModel.receivedMoney.value} ${if(pageBViewModel.bonus.value>0) "got $bonus bonus" else "): no bonus this month"}",
color = Color(0xfff44336),
fontSize = 24.sp,
fontWeight = FontWeight.Bold
)
Button(
onClick = {
pageBViewModel.onGoBack()
},
colors = ButtonDefaults.buttonColors(
backgroundColor = Color(0xfff44336),
contentColor = Color.White
)
) {
Text("Go back and pay me again")
}
}
}
package com.debduttapanda.powernavigation
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
class PageBViewModel: ViewModel() {
val navigation = mutableStateOf<NavigationCallback?>(null)
val receivedMoney = mutableStateOf(0)
val bonus = mutableStateOf(0)
fun onGoBack() {
navigation.navigate { navHostController, lifecycleOwner ->
navHostController
.previousBackStackEntry
?.savedStateHandle
?.set("totalReceived",(receivedMoney.value)+(bonus.value))
navHostController.navigateUp()
}
}
fun setArguments(_receivedMoney: Int?, _bonus: Int?) {
receivedMoney.value = _receivedMoney?:0
bonus.value = _bonus?:0
}
}
adb shell am start -W -a android.intent.action.VIEW -d "https://powernavigation.debduttapanda.com/300?bonus=50" com.debduttapanda.powernavigation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment