Skip to content

Commit 3fe5236

Browse files
Save telegram id and hash in shared preferences instead of hardcode
1 parent f0d0730 commit 3fe5236

10 files changed

Lines changed: 172 additions & 29 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ com_crashlytics_export_strings.xml
4242
crashlytics.properties
4343
crashlytics-build.properties
4444
fabric.properties
45+
gradle.properties
4546

4647
# Editor-based Rest Client
4748
.idea/httpRequests

gradle.properties

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
22
android.useAndroidX=true
33
android.enableJetifier=true
4-
kotlin.code.style=official
5-
telegramAppId=***REMOVED***
6-
telegramAppHash=***REMOVED***
4+
kotlin.code.style=official

sample/app/build.gradle.kts

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import org.gradle.api.GradleException
2-
31
plugins {
42
alias(libs.plugins.android.application)
53
alias(libs.plugins.kotlin.android)
@@ -9,20 +7,6 @@ plugins {
97
alias(libs.plugins.kotlin.compose)
108
}
119

12-
fun readTelegramCredential(propertyKey: String, envKey: String): String {
13-
val propertyValue = findProperty(propertyKey)?.toString()?.trim()
14-
if (!propertyValue.isNullOrEmpty()) {
15-
return propertyValue
16-
}
17-
18-
val envValue = System.getenv(envKey)?.toString()?.trim()
19-
if (!envValue.isNullOrEmpty()) {
20-
return envValue
21-
}
22-
23-
throw GradleException("Missing Telegram credential. Provide '$propertyKey' Gradle property or '$envKey' environment variable.")
24-
}
25-
2610
android {
2711
namespace = "com.telegramflow.example"
2812
compileSdk = 36
@@ -34,12 +18,6 @@ android {
3418
versionCode = 20240621
3519
versionName = "0.1.0"
3620

37-
val telegramAppId = readTelegramCredential("telegramAppId", "TELEGRAM_APP_ID").toInt()
38-
val telegramAppHash = readTelegramCredential("telegramAppHash", "TELEGRAM_APP_HASH")
39-
40-
buildConfigField("int", "TELEGRAM_APP_ID", telegramAppId.toString())
41-
buildConfigField("String", "TELEGRAM_APP_HASH", "\"$telegramAppHash\"")
42-
4321
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
4422
vectorDrawables {
4523
useSupportLibrary = true
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.telegramflow.example.data.local
2+
3+
import android.content.Context
4+
import android.content.SharedPreferences
5+
import dagger.hilt.android.qualifiers.ApplicationContext
6+
import javax.inject.Inject
7+
import javax.inject.Singleton
8+
9+
@Singleton
10+
class TelegramConfigStorage @Inject constructor(
11+
@ApplicationContext context: Context
12+
) {
13+
private val prefs: SharedPreferences =
14+
context.getSharedPreferences("telegram_config", Context.MODE_PRIVATE)
15+
16+
var appId: Int
17+
get() = prefs.getInt(KEY_APP_ID, 0)
18+
set(value) = prefs.edit().putInt(KEY_APP_ID, value).apply()
19+
20+
var appHash: String?
21+
get() = prefs.getString(KEY_APP_HASH, null)
22+
set(value) = prefs.edit().putString(KEY_APP_HASH, value).apply()
23+
24+
val isConfigured: Boolean
25+
get() = appId != 0 && !appHash.isNullOrBlank()
26+
27+
companion object {
28+
private const val KEY_APP_ID = "app_id"
29+
private const val KEY_APP_HASH = "app_hash"
30+
}
31+
}

sample/app/src/main/java/com/telegramflow/example/data/repo/TelegramRepository.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.telegramflow.example.data.repo
22

33
import com.telegramflow.example.BuildConfig
44
import com.telegramflow.example.data.local.AuthState
5+
import com.telegramflow.example.data.local.TelegramConfigStorage
56
import javax.inject.Inject
67
import javax.inject.Singleton
78
import kotlinx.coroutines.flow.Flow
@@ -26,7 +27,10 @@ import kotlinx.telegram.flows.userStatusFlow
2627
import org.drinkless.tdlib.TdApi
2728

2829
@Singleton
29-
class TelegramRepository @Inject constructor(override val api: TelegramFlow) : UserKtx {
30+
class TelegramRepository @Inject constructor(
31+
override val api: TelegramFlow,
32+
private val configStorage: TelegramConfigStorage
33+
) : UserKtx {
3034

3135
val authFlow: Flow<AuthState?> = api.authorizationStateFlow()
3236
.onEach { authorizationState ->
@@ -146,8 +150,8 @@ class TelegramRepository @Inject constructor(override val api: TelegramFlow) : U
146150
deviceModel = "Android",
147151
systemVersion = "Example",
148152
applicationVersion = "1.1",
149-
apiId = BuildConfig.TELEGRAM_APP_ID,
150-
apiHash = BuildConfig.TELEGRAM_APP_HASH,
153+
apiId = configStorage.appId,
154+
apiHash = configStorage.appHash ?: "",
151155
useTestDc = false,
152156
filesDirectory = "/data/user/0/${BuildConfig.APPLICATION_ID}/files/td",
153157
databaseEncryptionKey = null,

sample/app/src/main/java/com/telegramflow/example/ui/screen/MainActivity.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,21 @@ import androidx.compose.ui.tooling.preview.Preview
1616
import androidx.navigation.compose.NavHost
1717
import androidx.navigation.compose.composable
1818
import androidx.navigation.compose.rememberNavController
19+
import com.telegramflow.example.data.local.TelegramConfigStorage
1920
import com.telegramflow.example.ui.screen.MainScreen
21+
import com.telegramflow.example.ui.screen.config.ConfigScreen
2022
import com.telegramflow.example.ui.screen.enterPhone.LoginScreen
2123
import com.telegramflow.example.ui.theme.TelegramFlowComposeTheme
2224
import dagger.hilt.android.AndroidEntryPoint
25+
import javax.inject.Inject
2326

2427
@ExperimentalComposeUiApi
2528
@AndroidEntryPoint
2629
class MainActivity : ComponentActivity() {
2730

31+
@Inject
32+
lateinit var configStorage: TelegramConfigStorage
33+
2834
override fun onCreate(savedInstanceState: Bundle?) {
2935
super.onCreate(savedInstanceState)
3036
setContent {
@@ -40,7 +46,18 @@ class MainActivity : ComponentActivity() {
4046
@Composable
4147
private fun AppNavigation() {
4248
val navController = rememberNavController()
43-
NavHost(navController = navController, startDestination = LoginRoute) {
49+
val startDestination = if (configStorage.isConfigured) LoginRoute else ConfigRoute
50+
NavHost(navController = navController, startDestination = startDestination) {
51+
composable<ConfigRoute> {
52+
ConfigScreen(
53+
onConfigSaved = {
54+
navController.navigate(LoginRoute) {
55+
popUpTo<ConfigRoute> { inclusive = true }
56+
}
57+
}
58+
)
59+
}
60+
4461
composable<UsersRoute> {
4562
MainScreen()
4663
}

sample/app/src/main/java/com/telegramflow/example/ui/screen/Routes.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ object LoginRoute
77

88
@Serializable
99
object UsersRoute
10+
11+
@Serializable
12+
object ConfigRoute
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.telegramflow.example.ui.screen.config
2+
3+
import androidx.compose.foundation.layout.*
4+
import androidx.compose.foundation.text.ClickableText
5+
import androidx.compose.foundation.text.KeyboardOptions
6+
import androidx.compose.material.*
7+
import androidx.compose.runtime.*
8+
import androidx.compose.ui.Alignment
9+
import androidx.compose.ui.Modifier
10+
import androidx.compose.ui.graphics.Color
11+
import androidx.compose.ui.platform.LocalUriHandler
12+
import androidx.compose.ui.res.stringResource
13+
import androidx.compose.ui.text.AnnotatedString
14+
import androidx.compose.ui.text.TextStyle
15+
import androidx.compose.ui.text.input.KeyboardType
16+
import androidx.compose.ui.unit.dp
17+
import androidx.hilt.navigation.compose.hiltViewModel
18+
import com.telegramflow.example.R
19+
20+
@Composable
21+
fun ConfigScreen(
22+
onConfigSaved: () -> Unit,
23+
viewModel: ConfigViewModel = hiltViewModel()
24+
) {
25+
var appId by remember { mutableStateOf("") }
26+
var appHash by remember { mutableStateOf("") }
27+
val uriHandler = LocalUriHandler.current
28+
29+
Column(
30+
modifier = Modifier
31+
.fillMaxSize()
32+
.padding(16.dp),
33+
verticalArrangement = Arrangement.Center,
34+
horizontalAlignment = Alignment.CenterHorizontally
35+
) {
36+
Text(
37+
text = stringResource(id = R.string.config_title),
38+
style = MaterialTheme.typography.h5,
39+
modifier = Modifier.padding(bottom = 16.dp)
40+
)
41+
42+
TextField(
43+
value = appId,
44+
onValueChange = { appId = it },
45+
label = { Text(stringResource(id = R.string.config_app_id_label)) },
46+
modifier = Modifier.fillMaxWidth(),
47+
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
48+
)
49+
50+
Spacer(modifier = Modifier.height(8.dp))
51+
52+
TextField(
53+
value = appHash,
54+
onValueChange = { appHash = it },
55+
label = { Text(stringResource(id = R.string.config_app_hash_label)) },
56+
modifier = Modifier.fillMaxWidth()
57+
)
58+
59+
Spacer(modifier = Modifier.height(16.dp))
60+
61+
Text(
62+
text = stringResource(id = R.string.config_help_text),
63+
style = MaterialTheme.typography.body2
64+
)
65+
ClickableText(
66+
text = AnnotatedString("https://my.telegram.org"),
67+
style = TextStyle(color = Color.Blue),
68+
onClick = {
69+
uriHandler.openUri("https://my.telegram.org")
70+
}
71+
)
72+
73+
Spacer(modifier = Modifier.height(24.dp))
74+
75+
Button(
76+
onClick = {
77+
val id = appId.toIntOrNull()
78+
if (id != null && appHash.isNotBlank()) {
79+
viewModel.saveConfig(id, appHash)
80+
onConfigSaved()
81+
}
82+
},
83+
modifier = Modifier.fillMaxWidth(),
84+
enabled = appId.isNotBlank() && appHash.isNotBlank()
85+
) {
86+
Text(stringResource(id = R.string.config_save_action))
87+
}
88+
}
89+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.telegramflow.example.ui.screen.config
2+
3+
import androidx.lifecycle.ViewModel
4+
import com.telegramflow.example.data.local.TelegramConfigStorage
5+
import dagger.hilt.android.lifecycle.HiltViewModel
6+
import javax.inject.Inject
7+
8+
@HiltViewModel
9+
class ConfigViewModel @Inject constructor(
10+
private val configStorage: TelegramConfigStorage
11+
) : ViewModel() {
12+
13+
fun saveConfig(appId: Int, appHash: String) {
14+
configStorage.appId = appId
15+
configStorage.appHash = appHash
16+
}
17+
}

sample/app/src/main/res/values/strings.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,9 @@
33
<string name="cd_app_logo">App Logo</string>
44
<string name="welcome_hint">Welcome to the Telegram Flow example. Start by entering your phone number.</string>
55
<string name="action_continue">Continue</string>
6+
<string name="config_title">Telegram API Configuration</string>
7+
<string name="config_app_id_label">App ID</string>
8+
<string name="config_app_hash_label">App Hash</string>
9+
<string name="config_help_text">You can get your App ID and Hash at </string>
10+
<string name="config_save_action">Save and Continue</string>
611
</resources>

0 commit comments

Comments
 (0)