diff --git a/app/src/conjugate/java/be/scri/activities/MainActivity.kt b/app/src/conjugate/java/be/scri/activities/MainActivity.kt index ca54f9859..9254eb621 100644 --- a/app/src/conjugate/java/be/scri/activities/MainActivity.kt +++ b/app/src/conjugate/java/be/scri/activities/MainActivity.kt @@ -6,18 +6,20 @@ package be.scri.activities +import android.os.Build import android.os.Bundle import androidx.activity.ComponentActivity +import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatDelegate -import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.core.view.WindowCompat import androidx.navigation.compose.rememberNavController import be.scri.ScribeApp import be.scri.helpers.PreferencesHelper @@ -38,7 +40,8 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) AppCompatDelegate.setDefaultNightMode(PreferencesHelper.getUserDarkModePreference(this)) - enableEdgeToEdge() + val isDark = PreferencesHelper.getUserDarkModePreference(this) == AppCompatDelegate.MODE_NIGHT_YES + applyNavigationBarStyle(isDark) setContent { val context = LocalContext.current @@ -76,6 +79,7 @@ class MainActivity : ComponentActivity() { ) isDarkMode.value = darkMode + applyNavigationBarStyle(darkMode) } ScribeTheme( @@ -98,9 +102,26 @@ class MainActivity : ComponentActivity() { }, context = context, navController = navController, - modifier = Modifier.navigationBarsPadding(), + modifier = Modifier, ) } } } + + private fun applyNavigationBarStyle(isDark: Boolean) { + enableEdgeToEdge( + navigationBarStyle = + if (isDark) { + SystemBarStyle.dark(android.graphics.Color.BLACK) + } else { + SystemBarStyle.light(android.graphics.Color.WHITE, android.graphics.Color.WHITE) + }, + ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + window.isNavigationBarContrastEnforced = false + } + WindowCompat.getInsetsController(window, window.decorView).apply { + isAppearanceLightNavigationBars = !isDark + } + } } diff --git a/app/src/main/java/be/scri/helpers/ui/ShareHelper.kt b/app/src/main/java/be/scri/helpers/ui/ShareHelper.kt index 9031a1063..4e914dfee 100644 --- a/app/src/main/java/be/scri/helpers/ui/ShareHelper.kt +++ b/app/src/main/java/be/scri/helpers/ui/ShareHelper.kt @@ -14,7 +14,10 @@ interface ShareHelperInterface { * * @param context The Android context used to perform the share action. */ - fun shareScribe(context: Context) + fun shareScribe( + context: Context, + isConjugateApp: Boolean = false, + ) } /** Implementation of ShareHelperInterface to handle sharing a scribe. */ @@ -24,14 +27,30 @@ class ShareHelperImpl : ShareHelperInterface { * * @param context The context from which to launch the share intent. */ - override fun shareScribe(context: Context) { + override fun shareScribe( + context: Context, + isConjugateApp: Boolean, + ) { + val shareText = + if (isConjugateApp) { + "Check out Scribe Conjugate!" + } else { + "Check out Scribe!" + } val sendIntent = Intent().apply { action = Intent.ACTION_SEND - putExtra(Intent.EXTRA_TEXT, "Check out Scribe!") + putExtra(Intent.EXTRA_TEXT, shareText) type = "text/plain" } - val shareIntent = Intent.createChooser(sendIntent, "Share Scribe via…") + + val shareTitle = + if (isConjugateApp) { + "Share Scribe Conjugate via…" + } else { + "Share Scribe via…" + } + val shareIntent = Intent.createChooser(sendIntent, shareTitle) context.startActivity(shareIntent) } } diff --git a/app/src/main/java/be/scri/ui/screens/about/AboutScreen.kt b/app/src/main/java/be/scri/ui/screens/about/AboutScreen.kt index f5d18c700..efa44720a 100644 --- a/app/src/main/java/be/scri/ui/screens/about/AboutScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/about/AboutScreen.kt @@ -16,6 +16,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import be.scri.R +import be.scri.helpers.AppFlavor +import be.scri.helpers.FlavorProvider import be.scri.helpers.ui.HintUtils import be.scri.ui.common.ScribeBaseScreen import be.scri.ui.common.components.ItemCardContainerWithTitle @@ -36,6 +38,7 @@ fun AboutScreen( context: Context, modifier: Modifier = Modifier, ) { + val isConjugateApp = FlavorProvider.get() == AppFlavor.CONJUGATE val scrollState = rememberScrollState() val communityList = @@ -43,8 +46,9 @@ fun AboutScreen( onWikimediaAndScribeClick = { onWikiClick() }, - onShareScribeClick = { AboutUtil.onShareScribeClick(context) }, + onShareScribeClick = { AboutUtil.onShareScribeClick(context, isConjugateApp) }, context = context, + isConjugateApp = isConjugateApp, ) val feedbackAndSupportList = @@ -56,6 +60,7 @@ fun AboutScreen( resetHints() }, context = context, + isConjugateApp = isConjugateApp, ) val legalItemsList = diff --git a/app/src/main/java/be/scri/ui/screens/about/AboutUtil.kt b/app/src/main/java/be/scri/ui/screens/about/AboutUtil.kt index c25e25589..67e0a637e 100644 --- a/app/src/main/java/be/scri/ui/screens/about/AboutUtil.kt +++ b/app/src/main/java/be/scri/ui/screens/about/AboutUtil.kt @@ -33,12 +33,14 @@ object ExternalLinks { * @param context Context to launch intents for opening URLs. * @param onShareScribeClick Callback invoked when the "Share Scribe" item is clicked. * @param onWikimediaAndScribeClick Callback invoked when the Wikimedia item is clicked. + * @param isConjugateApp Flag indicating flavor * @return A list of [ScribeItem.ExternalLinkItem] representing community links and actions. */ fun buildCommunityList( context: Context, onShareScribeClick: () -> Unit, onWikimediaAndScribeClick: () -> Unit, + isConjugateApp: Boolean = false, ): List = listOf( ScribeItem.ExternalLinkItem( @@ -63,7 +65,12 @@ fun buildCommunityList( ), ScribeItem.ExternalLinkItem( leadingIcon = R.drawable.share_icon, - title = R.string.i18n_app_about_community_share_scribe, + title = + if (isConjugateApp) { + R.string.i18n_app_about_community_share_conjugate + } else { + R.string.i18n_app_about_community_share_scribe + }, trailingIcon = R.drawable.external_link, url = null, onClick = { onShareScribeClick() }, @@ -103,6 +110,7 @@ fun getLegalItemSpecs(): List = * @param onRateScribeClick Callback invoked when user selects "Rate Scribe". * @param onMailClick Callback invoked when user wants to send feedback email. * @param onResetHintsClick Callback invoked to reset onboarding hints. + * @param isConjugateApp Flag indicating flavor * @return A list of [ScribeItem.ExternalLinkItem] for feedback and support options. */ fun feedbackAndSupportList( @@ -110,11 +118,17 @@ fun feedbackAndSupportList( onRateScribeClick: () -> Unit, onMailClick: () -> Unit, onResetHintsClick: () -> Unit, + isConjugateApp: Boolean = false, ): List = listOf( ScribeItem.ExternalLinkItem( leadingIcon = R.drawable.star, - title = R.string.i18n_app_about_feedback_rate_scribe, + title = + if (isConjugateApp) { + R.string.i18n_app_about_feedback_rate_conjugate + } else { + R.string.i18n_app_about_feedback_rate_scribe + }, trailingIcon = R.drawable.external_link, url = null, onClick = { onRateScribeClick() }, @@ -190,9 +204,13 @@ object AboutUtil { * Shares the Scribe app via the system's share sheet. * * @param context Context used to launch the sharing intent. + * @param isConjugateApp Flag indicating flavor */ - fun onShareScribeClick(context: Context) { - shareHelper.shareScribe(context) + fun onShareScribeClick( + context: Context, + isConjugateApp: Boolean = false, + ) { + shareHelper.shareScribe(context, isConjugateApp) } /** @@ -219,6 +237,7 @@ object AboutUtil { * @param onWikimediaAndScribeClick Callback invoked when Wikimedia link is clicked. * @param onShareScribeClick Callback invoked when Share Scribe link is clicked. * @param context Android context to open URLs. + * @param isConjugateApp Flag indicating flavor. * * @return A [ScribeItemList] wrapping community external links. */ @@ -227,10 +246,17 @@ object AboutUtil { onWikimediaAndScribeClick: () -> Unit, onShareScribeClick: () -> Unit, context: Context, + isConjugateApp: Boolean = false, ): ScribeItemList = - remember { + remember(isConjugateApp) { ScribeItemList( - items = buildCommunityList(context, onShareScribeClick, onWikimediaAndScribeClick), + items = + buildCommunityList( + context, + onShareScribeClick, + onWikimediaAndScribeClick, + isConjugateApp, + ), ) } @@ -241,6 +267,7 @@ object AboutUtil { * @param onMailClick Callback to open email intent. * @param onResetHintsClick Callback to reset onboarding hints. * @param context Android context used to launch external intents. + * @param isConjugateApp Flag indicating flavor. * * @return A [ScribeItemList] wrapping feedback and support options. */ @@ -250,8 +277,9 @@ object AboutUtil { onMailClick: () -> Unit, onResetHintsClick: () -> Unit, context: Context, + isConjugateApp: Boolean = false, ): ScribeItemList = - remember { + remember(isConjugateApp) { ScribeItemList( items = feedbackAndSupportList( @@ -259,6 +287,7 @@ object AboutUtil { onRateScribeClick, onMailClick, onResetHintsClick, + isConjugateApp, ), ) } diff --git a/app/src/test/kotlin/be/scri/ui/screens/about/AboutUtilTest.kt b/app/src/test/kotlin/be/scri/ui/screens/about/AboutUtilTest.kt index de752c3fc..f5ab1ddc0 100644 --- a/app/src/test/kotlin/be/scri/ui/screens/about/AboutUtilTest.kt +++ b/app/src/test/kotlin/be/scri/ui/screens/about/AboutUtilTest.kt @@ -71,7 +71,6 @@ class AboutUtilTest { assertEquals(5, list.size) - // Checking the resource IDs are preserved, not string values. assertEquals(R.string.i18n_app_about_feedback_rate_scribe, list[0].title) assertEquals(R.string.i18n_app_about_feedback_bug_report, list[1].title) assertEquals(R.string.i18n_app_about_feedback_send_email, list[2].title) @@ -109,13 +108,16 @@ class AboutUtilTest { @Test fun testOnShareScribeClick() { - // Arrange val mockHelper = mockk(relaxed = true) AboutUtil.shareHelper = mockHelper - // Act - AboutUtil.onShareScribeClick(context) - verify { mockHelper.shareScribe(context) } + // Conjugate - true + AboutUtil.onShareScribeClick(context, isConjugateApp = true) + verify { mockHelper.shareScribe(context, true) } + + // Conjugate - false + AboutUtil.onShareScribeClick(context, isConjugateApp = false) + verify { mockHelper.shareScribe(context, false) } } @Test @@ -169,4 +171,54 @@ class AboutUtilTest { verify(exactly = 1) { HintUtils.resetHints(mockContext) } assertTrue(called) } + + @Test + fun `buildCommunityList returns conjugate share string when isConjugateApp is true`() { + val list = + buildCommunityList( + context = context, + onShareScribeClick = {}, + onWikimediaAndScribeClick = {}, + isConjugateApp = true, + ) + assertEquals(R.string.i18n_app_about_community_share_conjugate, list[2].title) + } + + @Test + fun `buildCommunityList returns default share string when isConjugateApp is false`() { + val list = + buildCommunityList( + context = context, + onShareScribeClick = {}, + onWikimediaAndScribeClick = {}, + isConjugateApp = false, + ) + assertEquals(R.string.i18n_app_about_community_share_scribe, list[2].title) + } + + @Test + fun `feedbackAndSupportList returns conjugate rate string when isConjugateApp is true`() { + val list = + feedbackAndSupportList( + context = context, + onRateScribeClick = {}, + onMailClick = {}, + onResetHintsClick = {}, + isConjugateApp = true, + ) + assertEquals(R.string.i18n_app_about_feedback_rate_conjugate, list[0].title) + } + + @Test + fun `feedbackAndSupportList returns default rate string when isConjugateApp is false`() { + val list = + feedbackAndSupportList( + context = context, + onRateScribeClick = {}, + onMailClick = {}, + onResetHintsClick = {}, + isConjugateApp = false, + ) + assertEquals(R.string.i18n_app_about_feedback_rate_scribe, list[0].title) + } }