Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions app/src/conjugate/java/be/scri/activities/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -76,6 +79,7 @@ class MainActivity : ComponentActivity() {
)

isDarkMode.value = darkMode
applyNavigationBarStyle(darkMode)
}

ScribeTheme(
Expand All @@ -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
}
}
}
27 changes: 23 additions & 4 deletions app/src/main/java/be/scri/helpers/ui/ShareHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand All @@ -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)
}
}
Expand Down
7 changes: 6 additions & 1 deletion app/src/main/java/be/scri/ui/screens/about/AboutScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -36,15 +38,17 @@ fun AboutScreen(
context: Context,
modifier: Modifier = Modifier,
) {
val isConjugateApp = FlavorProvider.get() == AppFlavor.CONJUGATE
val scrollState = rememberScrollState()

val communityList =
getCommunityList(
onWikimediaAndScribeClick = {
onWikiClick()
},
onShareScribeClick = { AboutUtil.onShareScribeClick(context) },
onShareScribeClick = { AboutUtil.onShareScribeClick(context, isConjugateApp) },
context = context,
isConjugateApp = isConjugateApp,
)

val feedbackAndSupportList =
Expand All @@ -56,6 +60,7 @@ fun AboutScreen(
resetHints()
},
context = context,
isConjugateApp = isConjugateApp,
)

val legalItemsList =
Expand Down
43 changes: 36 additions & 7 deletions app/src/main/java/be/scri/ui/screens/about/AboutUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<ScribeItem.ExternalLinkItem> =
listOf(
ScribeItem.ExternalLinkItem(
Expand All @@ -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() },
Expand Down Expand Up @@ -103,18 +110,25 @@ fun getLegalItemSpecs(): List<LegalItemSpec> =
* @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(
context: Context,
onRateScribeClick: () -> Unit,
onMailClick: () -> Unit,
onResetHintsClick: () -> Unit,
isConjugateApp: Boolean = false,
): List<ScribeItem.ExternalLinkItem> =
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() },
Expand Down Expand Up @@ -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)
}

/**
Expand All @@ -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.
*/
Expand All @@ -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,
),
)
}

Expand All @@ -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.
*/
Expand All @@ -250,15 +277,17 @@ object AboutUtil {
onMailClick: () -> Unit,
onResetHintsClick: () -> Unit,
context: Context,
isConjugateApp: Boolean = false,
): ScribeItemList =
remember {
remember(isConjugateApp) {
ScribeItemList(
items =
feedbackAndSupportList(
context,
onRateScribeClick,
onMailClick,
onResetHintsClick,
isConjugateApp,
),
)
}
Expand Down
62 changes: 57 additions & 5 deletions app/src/test/kotlin/be/scri/ui/screens/about/AboutUtilTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -109,13 +108,16 @@ class AboutUtilTest {

@Test
fun testOnShareScribeClick() {
// Arrange
val mockHelper = mockk<ShareHelperInterface>(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
Expand Down Expand Up @@ -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)
}
}
Loading