Skip to content

Commit 5885441

Browse files
committed
[other] ENGMT-1882: update android app for staging usage
Adds the ability to switch between apis Adds a request log
1 parent e98d011 commit 5885441

File tree

11 files changed

+621
-102
lines changed

11 files changed

+621
-102
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,9 @@
1414
.cxx
1515
local.properties
1616
*.aab
17+
.idea/
18+
app/src/main/res/drawable/
19+
.kotlin/errors/
20+
app/release
21+
app/src/main/ic_launcher-playstore.png
22+
app/src/main/res/

app/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
plugins {
22
id("com.android.application")
33
id("org.jetbrains.kotlin.android")
4+
id("kotlinx-serialization")
45
}
56

67
android {
@@ -72,4 +73,5 @@ dependencies {
7273
implementation("io.branch.sdk.android:library:5.9.0")
7374
implementation("com.google.android.gms:play-services-ads-identifier:18.0.1")
7475
implementation("com.android.installreferrer:installreferrer:2.2")
76+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
7577
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.branch.branchlinksimulator
2+
3+
import android.content.SharedPreferences
4+
5+
object ApiConfigManager {
6+
fun loadConfigOrDefault(preferences: SharedPreferences): ApiConfiguration {
7+
return loadConfig(preferences) ?: apiConfigurationsMap[STAGING] ?: ApiConfiguration("N/A", "N/A", "N/A", false)
8+
}
9+
10+
private fun loadConfig(preferences: SharedPreferences): ApiConfiguration? {
11+
val configName = preferences.getString(SELECTED_CONFIG_NAME, null)
12+
return configName?.let { apiConfigurationsMap[it] }
13+
}
14+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package io.branch.branchlinksimulator
2+
3+
data class ApiConfiguration(
4+
val branchKey: String,
5+
val apiUrl: String,
6+
val appId: String,
7+
val staging: Boolean
8+
)
9+
10+
const val STAGING = "Staging"
11+
const val PRODUCTION = "Production"
12+
const val STAGING_AC = "Staging AC"
13+
const val PRODUCTION_AC = "Production AC"
14+
15+
val apiConfigurationsMap: Map<String, ApiConfiguration> = mapOf(
16+
STAGING_AC to ApiConfiguration(
17+
branchKey = "key_live_juoZrlpzQZvBQbwR33GO5hicszlTGnVT",
18+
apiUrl = "https://protected-api.stage.branch.io/",
19+
appId = "1387589751543976586",
20+
staging = true
21+
),
22+
STAGING to ApiConfiguration(
23+
branchKey = "key_live_plqOidX7fW71Gzt0LdCThkemDEjCbTgx",
24+
apiUrl = "https://api.stage.branch.io/",
25+
appId = "436637608899006753",
26+
staging = true
27+
),
28+
PRODUCTION_AC to ApiConfiguration(
29+
branchKey = "key_live_hshD4wiPK2sSxfkZqkH30ggmyBfmGmD7",
30+
apiUrl = "https://protected-api.branch.io/",
31+
appId = "1284289243903971463",
32+
staging = false
33+
),
34+
PRODUCTION to ApiConfiguration(
35+
branchKey = "key_live_iDiV7ZewvDm9GIYxUnwdFdmmvrc9m3Aw",
36+
apiUrl = "https://api2.branch.io/",
37+
appId = "1364964166783226677",
38+
staging = false
39+
)
40+
)
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package io.branch.branchlinksimulator
2+
3+
import androidx.compose.ui.platform.ClipboardManager
4+
import android.content.Context
5+
import android.content.SharedPreferences
6+
import androidx.compose.foundation.background
7+
import androidx.compose.foundation.layout.*
8+
import androidx.compose.foundation.shape.RoundedCornerShape
9+
import androidx.compose.material3.*
10+
import androidx.compose.runtime.*
11+
import androidx.compose.ui.Alignment
12+
import androidx.compose.ui.Modifier
13+
import androidx.compose.ui.graphics.Color
14+
import androidx.compose.ui.platform.LocalClipboardManager
15+
import androidx.compose.ui.platform.LocalContext
16+
import androidx.compose.ui.text.AnnotatedString
17+
import androidx.compose.ui.text.style.TextAlign
18+
import androidx.compose.ui.text.style.TextOverflow
19+
import androidx.compose.ui.unit.dp
20+
import kotlin.system.exitProcess
21+
22+
const val SELECTED_CONFIG_NAME = "selectedConfigName"
23+
const val PREFERENCES_KEY = "ApiPreferences"
24+
25+
@Composable
26+
fun ApiSettingsPanel() {
27+
val context = LocalContext.current
28+
val preferences = remember { context.getSharedPreferences(PREFERENCES_KEY, Context.MODE_PRIVATE) }
29+
var selectedConfig by remember { mutableStateOf(ApiConfigManager.loadConfigOrDefault(preferences)) }
30+
31+
Column(
32+
verticalArrangement = Arrangement.spacedBy(10.dp),
33+
modifier = Modifier.padding(16.dp)
34+
) {
35+
ApiInfoRow(label = "Branch Key", value = selectedConfig.branchKey)
36+
ApiInfoRow(label = "API URL", value = selectedConfig.apiUrl)
37+
ApiInfoRow(label = "App ID", value = selectedConfig.appId)
38+
39+
Column(horizontalAlignment = Alignment.CenterHorizontally) {
40+
Row(horizontalArrangement = Arrangement.spacedBy(5.dp)) {
41+
ApiButton(configName = STAGING, selectedConfig = selectedConfig, Modifier.weight(1f), onSelect = {
42+
selectedConfig = it
43+
saveConfig(preferences, it)
44+
})
45+
ApiButton(configName = PRODUCTION, selectedConfig = selectedConfig, Modifier.weight(1f), onSelect = {
46+
selectedConfig = it
47+
saveConfig(preferences, it)
48+
})
49+
}
50+
51+
Row(horizontalArrangement = Arrangement.spacedBy(5.dp)) {
52+
ApiButton(configName = STAGING_AC, selectedConfig = selectedConfig, Modifier.weight(1f), onSelect = {
53+
selectedConfig = it
54+
saveConfig(preferences, it)
55+
})
56+
ApiButton(configName = PRODUCTION_AC, selectedConfig = selectedConfig, Modifier.weight(1f), onSelect = {
57+
selectedConfig = it
58+
saveConfig(preferences, it)
59+
})
60+
}
61+
}
62+
}
63+
}
64+
65+
@Composable
66+
fun ApiInfoRow(label: String, value: String) {
67+
val localClipboardManager = LocalClipboardManager.current
68+
69+
Row(
70+
modifier = Modifier
71+
.background(Color.LightGray, RoundedCornerShape(10.dp))
72+
.padding(horizontal = 10.dp, vertical = 5.dp),
73+
verticalAlignment = Alignment.CenterVertically
74+
) {
75+
Column(
76+
modifier = Modifier.weight(1f)
77+
) {
78+
Text(
79+
text = "$label:",
80+
style = MaterialTheme.typography.labelMedium,
81+
color = Color.Black
82+
)
83+
Text(
84+
text = value,
85+
style = MaterialTheme.typography.bodySmall,
86+
color = Color.Black
87+
)
88+
}
89+
90+
Button(
91+
onClick = { copyToClipboard(localClipboardManager, value) },
92+
) {
93+
Text("Copy")
94+
}
95+
}
96+
}
97+
98+
99+
@Composable
100+
fun ApiButton(
101+
configName: String,
102+
selectedConfig: ApiConfiguration,
103+
modifier: Modifier = Modifier,
104+
onSelect: (ApiConfiguration) -> Unit
105+
) {
106+
val config = apiConfigurationsMap[configName]
107+
val isSelected = selectedConfig == config
108+
109+
var showDialog by remember { mutableStateOf(false) }
110+
111+
Button(
112+
onClick = {
113+
if (config != null) {
114+
onSelect(config)
115+
showDialog = true
116+
}
117+
},
118+
modifier = modifier.padding(0.dp),
119+
colors = ButtonDefaults.buttonColors(
120+
containerColor = if (isSelected) Color.Blue else Color.Gray,
121+
contentColor = Color.White
122+
)
123+
) {
124+
Text(
125+
text = configName,
126+
maxLines = 1,
127+
overflow = TextOverflow.Ellipsis,
128+
textAlign = TextAlign.Center
129+
)
130+
}
131+
132+
if (showDialog) {
133+
AlertDialog(
134+
onDismissRequest = { showDialog = false },
135+
title = {
136+
Text(text = "Configuration Changed")
137+
},
138+
text = {
139+
Text(text = "You need to restart the app for the changes to take effect.")
140+
},
141+
dismissButton = {
142+
Button(onClick = { showDialog = false }) {
143+
Text("Cancel")
144+
}
145+
},
146+
confirmButton = {
147+
Button(onClick = { exitProcess(0) }) {
148+
Text("OK")
149+
}
150+
}
151+
)
152+
}
153+
}
154+
155+
fun saveConfig(preferences: SharedPreferences, config: ApiConfiguration) {
156+
val configName = apiConfigurationsMap.entries.firstOrNull { it.value == config }?.key ?: STAGING
157+
preferences.edit().putString(SELECTED_CONFIG_NAME, configName).apply()
158+
}
159+
160+
fun copyToClipboard(manager: ClipboardManager, text: String) {
161+
manager.setText(AnnotatedString(text))
162+
}

app/src/main/java/io/branch/branchlinksimulator/BranchLinkSimulatorApplication.kt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,22 @@ import io.branch.referral.Branch
66
import java.util.UUID
77

88
class BranchLinkSimulatorApplication: Application() {
9+
private lateinit var currentConfig: ApiConfiguration
10+
lateinit var roundTripStore: RoundTripStore
11+
private set
12+
913
override fun onCreate() {
1014
super.onCreate()
1115

12-
// Branch logging for debugging
13-
Branch.enableLogging()
14-
Branch.setAPIUrl("https://protected-api.branch.io/")
16+
val preferences = getSharedPreferences(PREFERENCES_KEY, Context.MODE_PRIVATE)
17+
currentConfig = ApiConfigManager.loadConfigOrDefault(preferences)
18+
19+
Branch.setAPIUrl(currentConfig.apiUrl)
1520

21+
roundTripStore = RoundTripStore(this)
22+
Branch.enableLogging(roundTripStore)
1623
// Branch object initialization
17-
Branch.getAutoInstance(this)
24+
Branch.getAutoInstance(this, currentConfig.branchKey)
1825

1926
// Retrieve or create the bls_session_id
2027
val sharedPreferences = getSharedPreferences("branch_session_prefs", Context.MODE_PRIVATE)
@@ -26,6 +33,5 @@ class BranchLinkSimulatorApplication: Application() {
2633

2734
// Set the bls_session_id in Branch request metadata
2835
Branch.getInstance().setRequestMetadata("bls_session_id", blsSessionId)
29-
3036
}
3137
}

0 commit comments

Comments
 (0)