diff --git a/CLAUDE.md b/CLAUDE.md
index 1951c3b..ef005ec 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -252,5 +252,9 @@ Claude, so they carry the same middleware chain.
resource merge).
- **Always device-verify Compose changes** (`installDebug` + screenshot), not just `assembleDebug` โ
a green build can still crash at runtime (e.g. the empty-font bug).
+- **Never start the Android emulator** unless the user asked for it, or said yes when asked. It is
+ slow to boot and device checks belong on the connected phone. If the phone can't take the build
+ (a debug build can't replace a Play-installed one: the signatures differ, and uninstalling wipes
+ the app's data), stop and ask how to verify instead of reaching for the emulator.
- A few inline strings remain (Premium feature descriptions, quick-action labels, Tibetan
placeholders) โ externalize if expanding i18n.
diff --git a/app/build.gradle b/app/build.gradle
index 2c737c9..6455cc0 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -31,10 +31,10 @@ android {
// installed devices on API 23 (0.03%).
minSdkVersion 24
targetSdkVersion 36
- versionCode project.hasProperty('versionCode') ? project.property('versionCode').toInteger() : 57
+ versionCode project.hasProperty('versionCode') ? project.property('versionCode').toInteger() : 58
// RevenueCat targeting rules match on this (App version >= 2.3.0).
- versionName "2.3.0"
+ versionName "2.3.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c85e175..a79782b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -28,7 +28,8 @@
+ android:exported="false"
+ android:theme="@style/Theme.TibetanKeyboard.Sheet" />
Unit,
@@ -75,6 +84,8 @@ class HomeActions(
val onAbout: () -> Unit,
val onUpgrade: () -> Unit,
val onJourney: () -> Unit,
+ val onSignIn: () -> Unit,
+ val onAccount: () -> Unit,
)
private data class QuickAction(
@@ -124,7 +135,7 @@ fun HomeScreen(
Box(modifier = Modifier.fillMaxSize()) {
ScreenScaffold(horizontalPadding = 18.dp) {
Spacer(Modifier.height(8.dp))
- BrandHeader()
+ BrandHeader(state.account, onSignIn = actions.onSignIn, onAccount = actions.onAccount)
Spacer(Modifier.height(18.dp))
SetupCard(
state = state,
@@ -229,7 +240,7 @@ private fun UpdateReadyBanner(onInstall: () -> Unit, modifier: Modifier = Modifi
}
@Composable
-private fun BrandHeader() {
+private fun BrandHeader(account: HomeAccount?, onSignIn: () -> Unit, onAccount: () -> Unit) {
Row(
modifier = Modifier.fillMaxWidth().padding(vertical = 6.dp),
verticalAlignment = Alignment.CenterVertically,
@@ -248,10 +259,50 @@ private fun BrandHeader() {
modifier = Modifier.size(72.dp,).clip(RoundedCornerShape(10.dp))
)
}
- Column {
- Text(stringResource(R.string.app_name), color = TibetanColors.Cream, fontSize = 18.sp, fontWeight = FontWeight.ExtraBold)
+ Column(Modifier.weight(1f)) {
+ Text(
+ stringResource(R.string.app_name),
+ color = TibetanColors.Cream, fontSize = 18.sp, fontWeight = FontWeight.ExtraBold,
+ maxLines = 1, overflow = TextOverflow.Ellipsis,
+ )
BoText(stringResource(R.string.bo_app_name), color = TibetanColors.CreamDim, fontSize = 13.sp)
}
+ AccountControl(account, onSignIn = onSignIn, onAccount = onAccount)
+ }
+}
+
+/**
+ * Top right of Home: "Sign in" for a signed-out user, their picture once signed in. Without it
+ * the only way to sign in was to reach a PRO screen first, so a subscriber on a new phone had no
+ * obvious way back to their PRO.
+ */
+@Composable
+private fun AccountControl(account: HomeAccount?, onSignIn: () -> Unit, onAccount: () -> Unit) {
+ if (account == null) {
+ Row(
+ modifier = Modifier
+ .clip(TibetanTokens.Pill)
+ .border(1.dp, TibetanColors.Gold400.copy(alpha = 0.7f), TibetanTokens.Pill)
+ .clickable(role = Role.Button, onClick = onSignIn)
+ .padding(horizontal = 14.dp, vertical = 10.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(6.dp),
+ ) {
+ Icon(AppIcons.Person, null, tint = TibetanColors.Gold300, modifier = Modifier.size(17.dp))
+ Text(stringResource(R.string.sign_in), color = TibetanColors.Gold300, fontSize = 13.sp, fontWeight = FontWeight.Bold)
+ }
+ } else {
+ AccountAvatar(
+ name = account.name,
+ photoUrl = account.photoUrl,
+ modifier = Modifier
+ .clip(CircleShape)
+ .clickable(
+ onClickLabel = stringResource(R.string.title_account),
+ role = Role.Button,
+ onClick = onAccount,
+ ),
+ )
}
}
diff --git a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/home/HomeViewModel.kt b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/home/HomeViewModel.kt
index 14bfb66..2b39735 100644
--- a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/home/HomeViewModel.kt
+++ b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/home/HomeViewModel.kt
@@ -53,6 +53,18 @@ class HomeViewModel(app: Application) : AndroidViewModel(app) {
init {
premiumLiveData.observeForever(premiumObserver)
RevenueCatManager.getInstance().refreshCustomerInfo()
+ refreshAccount()
+ }
+
+ /** Re-read who is signed in (every resume: signing in and out happen on other screens). */
+ fun refreshAccount() {
+ val account = if (authManager.isUserAuthenticated()) {
+ HomeAccount(
+ name = authManager.getCurrentUserName(),
+ photoUrl = authManager.getCurrentUserPhotoUrl().takeIf { it.isNotBlank() },
+ )
+ } else null
+ _uiState.update { it.copy(account = account) }
}
/** Called by the Activity after it reads keyboard-enabled / default-IME status. */
diff --git a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/login/LoginActivity.kt b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/login/LoginActivity.kt
index 8d5ec60..043ebc4 100644
--- a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/login/LoginActivity.kt
+++ b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/login/LoginActivity.kt
@@ -83,6 +83,8 @@ class LoginActivity : AppCompatActivity() {
onGoogleSignIn = { signInWithGoogle() },
onTerms = { openTermsOfService() },
onPrivacy = { openPrivacyPolicy() },
+ // Swiped away, tapped outside or Back: whatever is underneath is still there.
+ onDismiss = { finish() },
)
}
}
diff --git a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/login/LoginScreen.kt b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/login/LoginScreen.kt
index fc36ec3..2b2d267 100644
--- a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/login/LoginScreen.kt
+++ b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/login/LoginScreen.kt
@@ -1,5 +1,6 @@
package com.kharagedition.tibetankeyboard.ui.login
+import androidx.annotation.StringRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -8,98 +9,156 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.statusBarsPadding
-import androidx.compose.foundation.layout.systemBarsPadding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.CircularProgressIndicator
-import androidx.compose.material3.Icon
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
+import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.kharagedition.tibetankeyboard.R
import com.kharagedition.tibetankeyboard.ui.compose.components.AppIcons
-import com.kharagedition.tibetankeyboard.ui.compose.components.BoText
+import com.kharagedition.tibetankeyboard.ui.compose.components.IconTile
import com.kharagedition.tibetankeyboard.ui.compose.theme.TibetanColors
import com.kharagedition.tibetankeyboard.ui.compose.theme.TibetanTokens
+/** One thing an account gives. */
+private data class SignInBenefit(
+ val icon: ImageVector,
+ @StringRes val title: Int,
+ @StringRes val description: Int,
+)
+
+/** Only what the app really ties to the account; typing stats, for one, stay on the phone. */
+private val SignInBenefits = listOf(
+ SignInBenefit(AppIcons.Crown, R.string.sign_in_benefit_pro, R.string.sign_in_benefit_pro_desc),
+ SignInBenefit(AppIcons.Bot, R.string.sign_in_benefit_ai, R.string.sign_in_benefit_ai_desc),
+ SignInBenefit(AppIcons.Star, R.string.sign_in_benefit_community, R.string.sign_in_benefit_community_desc),
+)
+
+/**
+ * Sign-in as a bottom sheet over the screen that asked for it: the user keeps their place, sees
+ * what an account is for, and can swipe the sheet away. [LoginActivity]'s window is see-through
+ * and shows nothing else.
+ */
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LoginScreen(
isLoading: Boolean,
onGoogleSignIn: () -> Unit,
onTerms: () -> Unit,
onPrivacy: () -> Unit,
+ onDismiss: () -> Unit,
) {
- Box(
- modifier = Modifier.fillMaxSize().background(TibetanColors.Bg900).systemBarsPadding(),
- contentAlignment = Alignment.Center,
+ ModalBottomSheet(
+ onDismissRequest = onDismiss,
+ sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
+ shape = RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp),
+ containerColor = TibetanColors.Bg800,
+ contentColor = TibetanColors.Cream,
+ scrimColor = TibetanColors.Espresso.copy(alpha = 0.72f),
+ dragHandle = { SheetHandle() },
) {
Column(
- modifier = Modifier.fillMaxWidth().padding(horizontal = 32.dp),
+ modifier = Modifier
+ .fillMaxWidth()
+ .verticalScroll(rememberScrollState())
+ .padding(horizontal = 24.dp)
+ .padding(bottom = 20.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
- // brand
- Box(
- modifier = Modifier.size(80.dp).clip(RoundedCornerShape(22.dp)).background(TibetanTokens.GoldVertical),
- contentAlignment = Alignment.Center,
- ) {
- Icon(AppIcons.Lotus, null, tint = TibetanColors.Espresso, modifier = Modifier.size(44.dp))
- }
- Spacer(Modifier.height(20.dp))
- Text(stringResource(R.string.app_name), color = TibetanColors.Cream, fontSize = 24.sp, fontWeight = FontWeight.ExtraBold)
- Spacer(Modifier.height(4.dp))
- BoText(stringResource(R.string.bo_app_name), color = TibetanColors.Gold300, fontSize = 16.sp)
-
- Spacer(Modifier.height(40.dp))
- Text(stringResource(R.string.welcome), color = TibetanColors.Cream, fontSize = 20.sp, fontWeight = FontWeight.Bold)
+ Image(
+ painter = painterResource(R.mipmap.ic_launcher),
+ contentDescription = null,
+ modifier = Modifier.size(56.dp).clip(RoundedCornerShape(16.dp)),
+ )
+ Spacer(Modifier.height(14.dp))
+ Text(
+ stringResource(R.string.sign_in_title, stringResource(R.string.app_name)),
+ color = TibetanColors.Cream, fontSize = 21.sp, fontWeight = FontWeight.ExtraBold,
+ textAlign = TextAlign.Center,
+ )
Spacer(Modifier.height(6.dp))
Text(
- stringResource(R.string.login_subtitle),
- color = TibetanColors.CreamDim, fontSize = 14.sp, lineHeight = 21.sp,
+ stringResource(R.string.sign_in_subtitle),
+ color = TibetanColors.CreamDim, fontSize = 14.sp, lineHeight = 20.sp,
textAlign = TextAlign.Center,
)
- Spacer(Modifier.height(28.dp))
+ Spacer(Modifier.height(22.dp))
+ Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(14.dp)) {
+ SignInBenefits.forEach { BenefitRow(it) }
+ }
+
+ Spacer(Modifier.height(24.dp))
GoogleSignInButton(isLoading = isLoading, onClick = onGoogleSignIn)
+ Spacer(Modifier.height(14.dp))
+ LegalLine(onTerms = onTerms, onPrivacy = onPrivacy)
}
+ }
+}
- // privacy footer
- Row(
- modifier = Modifier
- .align(Alignment.BottomCenter)
- .statusBarsPadding()
- .padding(horizontal = 32.dp, vertical = 24.dp),
- horizontalArrangement = Arrangement.Center,
- ) {
- Column(horizontalAlignment = Alignment.CenterHorizontally) {
- Text(stringResource(R.string.by_signing_in), color = TibetanColors.CreamFaint, fontSize = 12.sp)
- Row(horizontalArrangement = Arrangement.Center) {
- Text(
- stringResource(R.string.terms_of_service)+" ",
- color = TibetanColors.Gold300, fontSize = 12.sp, fontWeight = FontWeight.SemiBold,
- modifier = Modifier.clickable(onClick = onTerms),
- )
- Text(stringResource(R.string.and_word)+" ", color = TibetanColors.CreamFaint, fontSize = 12.sp)
- Text(
- stringResource(R.string.privacy_policy),
- color = TibetanColors.Gold300, fontSize = 12.sp, fontWeight = FontWeight.SemiBold,
- modifier = Modifier.clickable(onClick = onPrivacy),
- )
- }
- }
+@Composable
+private fun SheetHandle() {
+ Box(
+ modifier = Modifier
+ .padding(top = 12.dp, bottom = 18.dp)
+ .size(width = 40.dp, height = 4.dp)
+ .clip(TibetanTokens.Pill)
+ .background(TibetanColors.Line2),
+ )
+}
+
+@Composable
+private fun BenefitRow(benefit: SignInBenefit) {
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ IconTile(benefit.icon, size = 40.dp, iconSize = 20.dp)
+ Spacer(Modifier.width(14.dp))
+ Column(Modifier.weight(1f)) {
+ Text(
+ stringResource(benefit.title),
+ color = TibetanColors.Cream, fontSize = 14.5.sp, fontWeight = FontWeight.Bold,
+ )
+ Text(stringResource(benefit.description), color = TibetanColors.CreamDim, fontSize = 12.5.sp)
+ }
+ }
+}
+
+@Composable
+private fun LegalLine(onTerms: () -> Unit, onPrivacy: () -> Unit) {
+ Column(horizontalAlignment = Alignment.CenterHorizontally) {
+ Text(stringResource(R.string.by_signing_in), color = TibetanColors.CreamFaint, fontSize = 12.sp)
+ Row(horizontalArrangement = Arrangement.Center) {
+ Text(
+ stringResource(R.string.terms_of_service) + " ",
+ color = TibetanColors.Gold300, fontSize = 12.sp, fontWeight = FontWeight.SemiBold,
+ modifier = Modifier.clickable(role = Role.Button, onClick = onTerms),
+ )
+ Text(stringResource(R.string.and_word) + " ", color = TibetanColors.CreamFaint, fontSize = 12.sp)
+ Text(
+ stringResource(R.string.privacy_policy),
+ color = TibetanColors.Gold300, fontSize = 12.sp, fontWeight = FontWeight.SemiBold,
+ modifier = Modifier.clickable(role = Role.Button, onClick = onPrivacy),
+ )
}
}
}
@@ -112,7 +171,7 @@ private fun GoogleSignInButton(isLoading: Boolean, onClick: () -> Unit) {
.height(54.dp)
.clip(RoundedCornerShape(27.dp))
.background(TibetanColors.Cream)
- .clickable(enabled = !isLoading, onClick = onClick),
+ .clickable(enabled = !isLoading, role = Role.Button, onClick = onClick),
contentAlignment = Alignment.Center,
) {
if (isLoading) {
diff --git a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsActivity.kt b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsActivity.kt
index 322dbc4..94dd7a9 100644
--- a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsActivity.kt
+++ b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsActivity.kt
@@ -17,6 +17,7 @@ import com.kharagedition.tibetankeyboard.BuildConfig
import com.kharagedition.tibetankeyboard.ui.subscription.ManageSubscriptionActivity
import com.kharagedition.tibetankeyboard.R
import com.kharagedition.tibetankeyboard.analytics.AppAnalytics
+import com.kharagedition.tibetankeyboard.auth.AuthManager
import com.kharagedition.tibetankeyboard.ui.compose.theme.TibetanKeyboardTheme
import com.kharagedition.tibetankeyboard.util.openPremiumUpgrade
import com.kharagedition.tibetankeyboard.util.showConfirmationDialog
@@ -59,6 +60,7 @@ class SettingsActivity : AppCompatActivity() {
onStreakReminder = viewModel::setStreakReminder,
onUpgrade = { openPremiumUpgrade(AppAnalytics.UpgradeSource.SETTINGS) },
onManageSubscription = { ManageSubscriptionActivity.open(this) },
+ onSignIn = { viewModel.signIn() },
onLogout = {
showConfirmationDialog(
title = getString(R.string.sign_out),
@@ -71,8 +73,8 @@ class SettingsActivity : AppCompatActivity() {
private fun signOut() {
viewModel.signOut {
- viewModel.redirectToLogin()
showToast(getString(R.string.signed_out))
+ AuthManager(this).redirectToHome()
}
}
diff --git a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsScreen.kt b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsScreen.kt
index 24eaf7b..21f00ff 100644
--- a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsScreen.kt
+++ b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsScreen.kt
@@ -60,6 +60,9 @@ data class SettingsState(
val streakReminder: Boolean = true,
val isPremium: Boolean = false,
val isAuthenticated: Boolean = false,
+ /** The signed-in account, shown at the top of the Account group. */
+ val accountName: String = "",
+ val accountEmail: String = "",
)
class SettingsActions(
@@ -72,6 +75,7 @@ class SettingsActions(
val onStreakReminder: (Boolean) -> Unit,
val onUpgrade: () -> Unit,
val onManageSubscription: () -> Unit,
+ val onSignIn: () -> Unit,
val onLogout: () -> Unit,
)
@@ -146,6 +150,22 @@ fun SettingsScreen(
SectionLabel(stringResource(R.string.title_account))
Spacer(Modifier.height(9.dp))
SettingsGroup {
+ if (state.isAuthenticated) {
+ SettingsRow(
+ icon = AppIcons.Person,
+ title = state.accountName,
+ subtitle = state.accountEmail.takeIf { it.isNotBlank() },
+ )
+ } else {
+ SettingsRow(
+ icon = AppIcons.Person,
+ title = stringResource(R.string.sign_in),
+ subtitle = stringResource(R.string.sign_in_benefit),
+ onClick = actions.onSignIn,
+ trailing = { ChevronIcon() },
+ )
+ }
+ SettingsDivider()
SettingsRow(
icon = AppIcons.Crown,
title = stringResource(R.string.subscription),
@@ -182,7 +202,7 @@ fun SettingsScreen(
SettingsDivider()
SettingsRow(
icon = AppIcons.Logout,
- title = stringResource(R.string.logout),
+ title = stringResource(R.string.sign_out),
onClick = actions.onLogout,
trailing = { ChevronIcon() },
)
diff --git a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsViewModel.kt b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsViewModel.kt
index 4394013..c9b4b80 100644
--- a/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsViewModel.kt
+++ b/app/src/main/java/com/kharagedition/tibetankeyboard/ui/settings/SettingsViewModel.kt
@@ -20,9 +20,7 @@ class SettingsViewModel(app: Application) : AndroidViewModel(app) {
private val authManager = AuthManager(app)
private val premiumLiveData = RevenueCatManager.getInstance().isPremiumUser
- private val _uiState = MutableStateFlow(
- SettingsPrefs.read(app).copy(isAuthenticated = authManager.isUserAuthenticated())
- )
+ private val _uiState = MutableStateFlow(SettingsPrefs.read(app).withAccount())
val uiState: StateFlow = _uiState.asStateFlow()
private val premiumObserver = Observer { isPremium ->
@@ -68,12 +66,21 @@ class SettingsViewModel(app: Application) : AndroidViewModel(app) {
/** Reload prefs in case they changed elsewhere (e.g. legacy preference screen). */
fun reload() {
val current = _uiState.value
- _uiState.value = SettingsPrefs.read(getApplication())
- .copy(isPremium = current.isPremium, isAuthenticated = authManager.isUserAuthenticated())
+ _uiState.value = SettingsPrefs.read(getApplication()).copy(isPremium = current.isPremium).withAccount()
+ }
+
+ private fun SettingsState.withAccount(): SettingsState {
+ val signedIn = authManager.isUserAuthenticated()
+ return copy(
+ isAuthenticated = signedIn,
+ accountName = if (signedIn) authManager.getCurrentUserName() else "",
+ accountEmail = if (signedIn) authManager.getCurrentUserEmail() else "",
+ )
}
fun signOut(onComplete: () -> Unit) = authManager.signOut(onComplete)
- fun redirectToLogin() = authManager.redirectToLogin()
+ /** Sign in from Settings: this screen stays underneath, so the user lands back here. */
+ fun signIn() = authManager.redirectToLogin(finishCaller = false, returnAfterLogin = true)
fun refreshPremium() = RevenueCatManager.getInstance().refreshCustomerInfo()
override fun onCleared() {
diff --git a/app/src/main/res/values-mcc402/strings.xml b/app/src/main/res/values-mcc402/strings.xml
index e89e362..1296ec3 100644
--- a/app/src/main/res/values-mcc402/strings.xml
+++ b/app/src/main/res/values-mcc402/strings.xml
@@ -5,7 +5,6 @@
Dzongkha
Dzongkha Assistant
Ask in English/Dzongkha
- Your AI Assistant for Dzongkha Language
Enter Dzongkha text to analyze
Analyze your Dzongkha text for grammar, spelling, and style
Enter text to transliterate…
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4a7968a..31d0471 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -48,10 +48,19 @@
Typing...
App Logo
- Your AI Assistant for Tibetan Language
Welcome Back
Sign in to continue chatting
Continue with Google
+ Sign in
+ Keep PRO on every device
+ Sign in to %1$s
+ One tap with your Google account.
+ PRO on every device
+ Your subscription follows your account
+ AI chat and translate
+ Ask questions and translate with AI
+ Community comparison
+ See how your streak compares
By signing in, you agree to our Terms of Service and Privacy Policy
@@ -62,7 +71,7 @@
Clear Chat
Profile
- Sign Out
+ Sign out
Loading...
@@ -245,7 +254,6 @@
Subscription
Premium plan
Free plan
- Logout
Done
AI Assistant
Online ยท Tibetan
@@ -301,7 +309,6 @@
GitHub
Contact
Get
- Welcome
By signing in, you agree to our
Terms of Service
and
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index cd1478a..8f4357a 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,7 +1,9 @@
+
+
+
+
+
+
+
+
+
+