diff --git a/app/src/main/java/fr/free/nrw/commons/AboutActivity.kt b/app/src/main/java/fr/free/nrw/commons/AboutActivity.kt index 865ad3ddb13..efba7d7f4e9 100644 --- a/app/src/main/java/fr/free/nrw/commons/AboutActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/AboutActivity.kt @@ -1,207 +1,118 @@ package fr.free.nrw.commons -import android.annotation.SuppressLint import android.content.ActivityNotFoundException +import android.content.Context import android.content.Intent import android.content.Intent.ACTION_VIEW -import android.net.Uri import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import android.view.View -import android.widget.ArrayAdapter -import android.widget.LinearLayout -import android.widget.Spinner -import fr.free.nrw.commons.CommonsApplication.Companion.instance -import fr.free.nrw.commons.databinding.ActivityAboutBinding +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.ui.Modifier +import androidx.core.net.toUri import fr.free.nrw.commons.theme.BaseActivity +import fr.free.nrw.commons.theme.CommonsAppTheme import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha -import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog -import java.util.Collections -import androidx.core.net.toUri -import fr.free.nrw.commons.utils.applyEdgeToEdgeTopInsets import fr.free.nrw.commons.utils.handleWebUrl -import fr.free.nrw.commons.utils.setUnderlinedText /** * Represents about screen of this app */ class AboutActivity : BaseActivity() { - /* - This View Binding class is auto-generated for each xml file. The format is usually the name - of the file with PascalCasing (The underscore characters will be ignored). - More information is available at https://developer.android.com/topic/libraries/view-binding - */ - private var binding: ActivityAboutBinding? = null - /** - * This method helps in the creation About screen - * - * @param savedInstanceState Data bundle - */ - @SuppressLint("StringFormatInvalid") //TODO: public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - /* - Instead of just setting the view with the xml file. We need to use View Binding class. - */ - binding = ActivityAboutBinding.inflate(layoutInflater) - val view: View = binding!!.root - applyEdgeToEdgeTopInsets(binding!!.toolbarLayout) - setContentView(view) - - setSupportActionBar(binding!!.toolbarBinding.toolbar) - supportActionBar!!.setDisplayHomeAsUpEnabled(true) - val aboutText = getString(R.string.about_license) - /* - We can then access all the views by just using the id names like this. - camelCasing is used with underscore characters being ignored. - */ - binding!!.aboutLicense.setHtmlText(aboutText) - - @SuppressLint("StringFormatMatches") // TODO: - val improveText = - String.format(getString(R.string.about_improve), Urls.NEW_ISSUE_URL) - binding!!.aboutImprove.setHtmlText(improveText) - binding!!.aboutVersion.text = applicationContext.getVersionNameWithSha() - - binding!!.aboutFaq.setUnderlinedText(R.string.about_faq) - binding!!.aboutRateUs.setUnderlinedText(R.string.about_rate_us) - binding!!.aboutUserGuide.setUnderlinedText(R.string.user_guide) - binding!!.aboutPrivacyPolicy.setUnderlinedText(R.string.about_privacy_policy) - binding!!.aboutTranslate.setUnderlinedText(R.string.about_translate) - binding!!.aboutCredits.setUnderlinedText(R.string.about_credits) - - /* - To set listeners, we can create a separate method and use lambda syntax. - */ - binding!!.facebookLaunchIcon.setOnClickListener(::launchFacebook) - binding!!.githubLaunchIcon.setOnClickListener(::launchGithub) - binding!!.websiteLaunchIcon.setOnClickListener(::launchWebsite) - binding!!.aboutRateUs.setOnClickListener(::launchRatings) - binding!!.aboutCredits.setOnClickListener(::launchCredits) - binding!!.aboutPrivacyPolicy.setOnClickListener(::launchPrivacyPolicy) - binding!!.aboutUserGuide.setOnClickListener(::launchUserGuide) - binding!!.aboutFaq.setOnClickListener(::launchFrequentlyAskedQuesions) - binding!!.aboutTranslate.setOnClickListener(::launchTranslate) + enableEdgeToEdge() + val versionName = applicationContext.getVersionNameWithSha() + + setContent { + CommonsAppTheme{ + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + AboutScreen( + versionName = versionName, + onNavigateUp = { onBackPressedDispatcher.onBackPressed() }, + onShareClicked = { shareApp() }, + onFacebookClicked = { launchFacebook(this) }, + onGithubClicked = { launchGithub(this) }, + onWebsiteClicked = { launchWebsite(this) }, + onRateUsClicked = { launchRatings(this) }, + onUserGuideClicked = { launchUserGuide(this) }, + onPrivacyPolicyClicked = { launchPrivacyPolicy(this) }, + onTranslateProceed = { langCode -> launchTranslate(this, langCode) }, + onCreditsClicked = { launchCredits(this) }, + onFaqClicked = { launchFrequentlyAskedQuesions(this) } + ) + } + } + } } - - override fun onSupportNavigateUp(): Boolean { - onBackPressed() - return true + private fun shareApp() { + val shareText = getString(R.string.share_text).format(Urls.PLAY_STORE_URL_PREFIX + packageName) + val sendIntent = Intent().apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_TEXT, shareText) + type = "text/plain" + } + startActivity(Intent.createChooser(sendIntent, getString(R.string.share_via))) } - fun launchFacebook(view: View?) { - val intent: Intent - try { - intent = Intent(ACTION_VIEW, Urls.FACEBOOK_APP_URL.toUri()) + private fun launchFacebook(context: Context) { + try{ + val intent = Intent(ACTION_VIEW, Urls.FACEBOOK_APP_URL.toUri()) intent.setPackage(Urls.FACEBOOK_PACKAGE_NAME) - startActivity(intent) + context.startActivity(intent) } catch (e: Exception) { - handleWebUrl(this, Urls.FACEBOOK_WEB_URL.toUri()) + handleWebUrl(context, Urls.FACEBOOK_WEB_URL.toUri()) } } - fun launchGithub(view: View?) { - val intent: Intent - try { - intent = Intent(ACTION_VIEW, Urls.GITHUB_REPO_URL.toUri()) + private fun launchGithub(context: Context) { + try{ + val intent = Intent(ACTION_VIEW, Urls.GITHUB_REPO_URL.toUri()) intent.setPackage(Urls.GITHUB_PACKAGE_NAME) - startActivity(intent) + context.startActivity(intent) } catch (e: Exception) { - handleWebUrl(this, Urls.GITHUB_REPO_URL.toUri()) + handleWebUrl(context, Urls.GITHUB_REPO_URL.toUri()) } } - fun launchWebsite(view: View?) { - handleWebUrl(this, Urls.WEBSITE_URL.toUri()) + private fun launchWebsite(context: Context) { + handleWebUrl(context, Urls.WEBSITE_URL.toUri()) } - fun launchRatings(view: View?) { + private fun launchRatings(context: Context) { try { - startActivity( + context.startActivity( Intent( ACTION_VIEW, (Urls.PLAY_STORE_PREFIX + packageName).toUri() ) ) } catch (_: ActivityNotFoundException) { - handleWebUrl(this, (Urls.PLAY_STORE_URL_PREFIX + packageName).toUri()) + handleWebUrl(context, (Urls.PLAY_STORE_URL_PREFIX + packageName).toUri()) } } - fun launchCredits(view: View?) { - handleWebUrl(this, Urls.CREDITS_URL.toUri()) + private fun launchCredits(context: Context) { + handleWebUrl(context, Urls.CREDITS_URL.toUri()) } - fun launchUserGuide(view: View?) { - handleWebUrl(this, Urls.USER_GUIDE_URL.toUri()) + private fun launchUserGuide(context: Context) { + handleWebUrl(context, Urls.USER_GUIDE_URL.toUri()) } - fun launchPrivacyPolicy(view: View?) { - handleWebUrl(this, BuildConfig.PRIVACY_POLICY_URL.toUri()) - } - - fun launchFrequentlyAskedQuesions(view: View?) { - handleWebUrl(this, Urls.FAQ_URL.toUri()) - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - val inflater = menuInflater - inflater.inflate(R.menu.menu_about, menu) - return super.onCreateOptionsMenu(menu) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.share_app_icon -> { - val shareText = String.format( - getString(R.string.share_text), - Urls.PLAY_STORE_URL_PREFIX + this.packageName - ) - val sendIntent = Intent() - sendIntent.setAction(Intent.ACTION_SEND) - sendIntent.putExtra(Intent.EXTRA_TEXT, shareText) - sendIntent.setType("text/plain") - startActivity(Intent.createChooser(sendIntent, getString(R.string.share_via))) - return true - } + private fun launchPrivacyPolicy(context: Context) { + handleWebUrl(context, BuildConfig.PRIVACY_POLICY_URL.toUri()) } - else -> return super.onOptionsItemSelected(item) - } + private fun launchFrequentlyAskedQuesions(context: Context) { + handleWebUrl(context, Urls.FAQ_URL.toUri()) } - - fun launchTranslate(view: View?) { - val sortedLocalizedNamesRef = instance.languageLookUpTable!!.getCanonicalNames() - Collections.sort(sortedLocalizedNamesRef) - val languageAdapter = ArrayAdapter( - this@AboutActivity, - android.R.layout.simple_spinner_dropdown_item, sortedLocalizedNamesRef - ) - val spinner = Spinner(this@AboutActivity) - spinner.layoutParams = - LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ) - spinner.adapter = languageAdapter - spinner.gravity = 17 - spinner.setPadding(50, 0, 0, 0) - - val positiveButtonRunnable = Runnable { - val langCode = instance.languageLookUpTable!!.getCodes()[spinner.selectedItemPosition] - handleWebUrl(this@AboutActivity, (Urls.TRANSLATE_WIKI_URL + langCode).toUri()) - } - showAlertDialog( - this, - getString(R.string.about_translate_title), - getString(R.string.about_translate_message), - getString(R.string.about_translate_proceed), - getString(R.string.about_translate_cancel), - positiveButtonRunnable, - {}, - spinner - ) + private fun launchTranslate(context: Context, langCode: String) { + handleWebUrl(context, (Urls.TRANSLATE_WIKI_URL + langCode).toUri()) } } diff --git a/app/src/main/java/fr/free/nrw/commons/AboutScreen.kt b/app/src/main/java/fr/free/nrw/commons/AboutScreen.kt new file mode 100644 index 00000000000..dfd38840e22 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/AboutScreen.kt @@ -0,0 +1,250 @@ +package fr.free.nrw.commons + +import android.widget.TextView +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Share +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView +import androidx.core.text.HtmlCompat +import fr.free.nrw.commons.CommonsApplication.Companion.instance +import java.util.Collections +import androidx.compose.ui.graphics.toArgb +import android.text.method.LinkMovementMethod + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun AboutScreen( + versionName: String, + onNavigateUp: () -> Unit, + onShareClicked: () -> Unit, + onFacebookClicked: () -> Unit, + onGithubClicked: () -> Unit, + onWebsiteClicked: () -> Unit, + onRateUsClicked: () -> Unit, + onUserGuideClicked: () -> Unit, + onPrivacyPolicyClicked: () -> Unit, + onTranslateProceed: (String) -> Unit, + onCreditsClicked: () -> Unit, + onFaqClicked: () -> Unit +) { + var showTranslateDialog by remember { mutableStateOf(false) } + + Scaffold( + topBar = { + TopAppBar( + title = { Text(text = stringResource(R.string.title_activity_about)) }, + navigationIcon = { + IconButton(onClick = onNavigateUp) { + Icon(Icons.Default.ArrowBack, contentDescription = "Back") + } + }, + actions = { + IconButton(onClick = onShareClicked) { + Icon(Icons.Default.Share, contentDescription = "Share") + } + } + ) + } + ) { paddingValues -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .padding(horizontal = 16.dp) + .verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(modifier = Modifier.height(24.dp)) + + Image( + painter = painterResource(id = R.drawable.ic_launcher), + contentDescription = stringResource(id = R.string.commons_logo) + ) + + Text( + text = stringResource(id = R.string.app_name), + style = MaterialTheme.typography.titleLarge, + modifier = Modifier.padding(top = 8.dp) + ) + + Text( + text = versionName, + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier.padding(top = 4.dp) + ) + + Spacer(modifier = Modifier.height(16.dp)) + + HtmlText( + htmlString = stringResource(id = R.string.about_license), + modifier = Modifier.padding(vertical = 8.dp) + ) + + val improveText = stringResource(id = R.string.about_improve).format(Urls.NEW_ISSUE_URL) + HtmlText( + htmlString = improveText, + modifier = Modifier.padding(vertical = 8.dp) + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Row( + horizontalArrangement = Arrangement.Center, + modifier = Modifier.fillMaxWidth() + ) { + IconButton(onClick = onWebsiteClicked) { + Icon( + painter = painterResource(id = R.drawable.ic_action_website), + contentDescription = stringResource(id = R.string.commons_website) + ) + } + Spacer(modifier = Modifier.width(16.dp)) + IconButton(onClick = onFacebookClicked) { + Icon( + painter = painterResource(id = R.drawable.ic_action_facebook), + contentDescription = stringResource(id = R.string.commons_facebook) + ) + } + Spacer(modifier = Modifier.width(16.dp)) + IconButton(onClick = onGithubClicked) { + Icon( + painter = painterResource(id = R.drawable.ic_action_github), + contentDescription = stringResource(id = R.string.commons_github) + ) + } + } + + Spacer(modifier = Modifier.height(24.dp)) + + LinkText(text = stringResource(id = R.string.about_rate_us), onClick = onRateUsClicked) + LinkText(text = stringResource(id = R.string.user_guide), onClick = onUserGuideClicked) + LinkText(text = stringResource(id = R.string.about_privacy_policy), onClick = onPrivacyPolicyClicked) + LinkText(text = stringResource(id = R.string.about_translate), onClick = { showTranslateDialog = true }) + LinkText(text = stringResource(id = R.string.about_credits), onClick = onCreditsClicked) + LinkText(text = stringResource(id = R.string.about_faq), onClick = onFaqClicked) + + Spacer(modifier = Modifier.height(24.dp)) + } + + if (showTranslateDialog) { + TranslateDialog( + onDismiss = { showTranslateDialog = false }, + onProceed = { langCode -> + onTranslateProceed(langCode) + showTranslateDialog = false + } + ) + } + } +} + +@Composable +fun LinkText(text: String, onClick: () -> Unit) { + Text( + text = text, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier + .clickable { onClick() } + .padding(vertical = 8.dp) + ) +} + +@Composable +fun HtmlText(htmlString: String, modifier: Modifier = Modifier) { + val textColor = MaterialTheme.colorScheme.onSurface.toArgb() + val linkColor = MaterialTheme.colorScheme.primary.toArgb() + AndroidView( + modifier = modifier, + factory = { context -> + TextView(context).apply { + textAlignment = android.view.View.TEXT_ALIGNMENT_CENTER + movementMethod = LinkMovementMethod.getInstance() + + } + }, + update = { textView -> + textView.text = HtmlCompat.fromHtml(htmlString, HtmlCompat.FROM_HTML_MODE_COMPACT) + textView.setTextColor(textColor) + textView.setLinkTextColor(linkColor) + } + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun TranslateDialog(onDismiss: () -> Unit, onProceed: (String) -> Unit) { + var expanded by remember { mutableStateOf(false) } + + val sortedLocalizedNamesRef = instance.languageLookUpTable?.getCanonicalNames() ?: emptyList() + val languageCodes = instance.languageLookUpTable?.getCodes() ?: emptyList() + + Collections.sort(sortedLocalizedNamesRef) + + var selectedIndex by remember { mutableStateOf(0) } + val selectedLanguage = if (sortedLocalizedNamesRef.isNotEmpty()) sortedLocalizedNamesRef[selectedIndex] else "" + + AlertDialog( + onDismissRequest = onDismiss, + title = { Text(text = stringResource(R.string.about_translate_title)) }, + text = { + Column { + Text(text = stringResource(R.string.about_translate_message)) + Spacer(modifier = Modifier.height(16.dp)) + + ExposedDropdownMenuBox( + expanded = expanded, + onExpandedChange = { expanded = !expanded } + ) { + OutlinedTextField( + value = selectedLanguage, + onValueChange = {}, + readOnly = true, + trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, + modifier = Modifier.menuAnchor() + ) + ExposedDropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false } + ) { + sortedLocalizedNamesRef.forEachIndexed { index, langName -> + DropdownMenuItem( + text = { Text(langName) }, + onClick = { + selectedIndex = index + expanded = false + } + ) + } + } + } + } + }, + confirmButton = { + TextButton(onClick = { + if (languageCodes.isNotEmpty()) { + onProceed(languageCodes[selectedIndex]) + } + }) { + Text(stringResource(R.string.about_translate_proceed)) + } + }, + dismissButton = { + TextButton(onClick = onDismiss) { + Text(stringResource(R.string.about_translate_cancel)) + } + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/theme/Color.kt b/app/src/main/java/fr/free/nrw/commons/theme/Color.kt new file mode 100644 index 00000000000..a045daf6fcd --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/theme/Color.kt @@ -0,0 +1,10 @@ +package fr.free.nrw.commons.theme + +import androidx.compose.ui.graphics.Color + +val DarkBackground = Color(0xFF2E2E2E) +val DarkOnSurface = Color.White +val DarkPrimary = Color(0xFF4DD0E1) +val LightBackground = Color.White +val LightOnSurface = Color.Black +val LightPrimary = Color(0xFF006699) \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/theme/Theme.kt b/app/src/main/java/fr/free/nrw/commons/theme/Theme.kt new file mode 100644 index 00000000000..c14639ab7ea --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/theme/Theme.kt @@ -0,0 +1,35 @@ +package fr.free.nrw.commons.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable + +private val DarkColorPalette = darkColorScheme( + background = DarkBackground, + onSurface = DarkOnSurface, + primary = DarkPrimary +) +private val LightColorPalette = lightColorScheme( + background = LightBackground, + onSurface = LightOnSurface, + primary = LightPrimary +) + +@Composable +fun CommonsAppTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + val colorScheme = if (darkTheme) { + DarkColorPalette + } else { + LightColorPalette + } + + MaterialTheme( + colorScheme = colorScheme, + content = content + ) +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/AboutActivityUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/AboutActivityUnitTests.kt index 56549fa1c73..0dbdb0339d7 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/AboutActivityUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/AboutActivityUnitTests.kt @@ -1,9 +1,8 @@ package fr.free.nrw.commons import android.content.Context +import android.content.Intent import android.net.Uri -import android.view.Menu -import android.view.MenuItem import androidx.test.core.app.ApplicationProvider import org.junit.Assert import org.junit.Before @@ -14,16 +13,21 @@ import org.robolectric.Robolectric import org.robolectric.RobolectricTestRunner import org.robolectric.Shadows import org.robolectric.annotation.Config -import org.robolectric.fakes.RoboMenu -import org.robolectric.fakes.RoboMenuItem import org.robolectric.shadows.ShadowActivity +import java.lang.reflect.Method @RunWith(RobolectricTestRunner::class) @Config(sdk = [21], application = TestCommonsApplication::class) class AboutActivityUnitTests { private lateinit var activity: AboutActivity - + private lateinit var shadowActivity: ShadowActivity private lateinit var context: Context + private fun invokePrivateLaunchMethod(methodName: String) { + val method: Method = + AboutActivity::class.java.getDeclaredMethod(methodName, Context::class.java) + method.isAccessible = true + method.invoke(activity, activity) + } @Before fun setUp() { @@ -32,6 +36,7 @@ class AboutActivityUnitTests { activity = Robolectric.buildActivity(AboutActivity::class.java).create().get() context = ApplicationProvider.getApplicationContext() + shadowActivity = Shadows.shadowOf(activity) } @Test @@ -43,8 +48,7 @@ class AboutActivityUnitTests { @Test @Throws(Exception::class) fun testLaunchFacebook() { - activity.launchFacebook(null) - val shadowActivity: ShadowActivity = Shadows.shadowOf(activity) + invokePrivateLaunchMethod("launchFacebook") val startedIntent = shadowActivity.nextStartedActivity Assert.assertEquals(startedIntent.action, "android.intent.action.VIEW") Assert.assertEquals(startedIntent.`package`, "com.facebook.katana") @@ -54,64 +58,68 @@ class AboutActivityUnitTests { @Test @Throws(Exception::class) fun testLaunchGithub() { - activity.launchGithub(null) + invokePrivateLaunchMethod("launchGithub") + Assert.assertEquals(shadowActivity.nextStartedActivity.action, "android.intent.action.VIEW") } @Test @Throws(Exception::class) fun testLaunchWebsite() { - activity.launchWebsite(null) + invokePrivateLaunchMethod("launchWebsite") + Assert.assertEquals(shadowActivity.nextStartedActivity.action, "android.intent.action.VIEW") } @Test @Throws(Exception::class) fun testLaunchRatings() { - activity.launchRatings(null) + invokePrivateLaunchMethod("launchRatings") + Assert.assertEquals(shadowActivity.nextStartedActivity.action, "android.intent.action.VIEW") } @Test @Throws(Exception::class) fun testLaunchCredits() { - activity.launchCredits(null) + invokePrivateLaunchMethod("launchCredits") + Assert.assertEquals(shadowActivity.nextStartedActivity.action, "android.intent.action.VIEW") } @Test @Throws(Exception::class) fun testLaunchPrivacyPolicy() { - activity.launchPrivacyPolicy(null) + invokePrivateLaunchMethod("launchPrivacyPolicy") + Assert.assertEquals(shadowActivity.nextStartedActivity.action, "android.intent.action.VIEW") } @Test @Throws(Exception::class) fun testLaunchUserGuide() { - activity.launchUserGuide(null) + invokePrivateLaunchMethod("launchUserGuide") + Assert.assertEquals(shadowActivity.nextStartedActivity.action, "android.intent.action.VIEW") } @Test @Throws(Exception::class) fun testLaunchFrequentlyAskedQuestions() { - activity.launchFrequentlyAskedQuesions(null) - } - - @Test - @Throws(Exception::class) - fun testOnCreateOptionsMenu() { - val menu: Menu = RoboMenu(context) - activity.onCreateOptionsMenu(menu) + invokePrivateLaunchMethod("launchFrequentlyAskedQuesions") + Assert.assertEquals(shadowActivity.nextStartedActivity.action, "android.intent.action.VIEW") } @Test @Throws(Exception::class) - fun testOnOptionsItemSelected() { - val menuItem: MenuItem = RoboMenuItem(R.menu.menu_about) - activity.onOptionsItemSelected(menuItem) - val shadowActivity = Shadows.shadowOf(activity) - shadowActivity.clickMenuItem(R.id.share_app_icon) - } + fun testShareApp() { + val method: Method = AboutActivity::class.java.getDeclaredMethod("shareApp") + method.isAccessible = true + method.invoke(activity) - @Test - @Throws(Exception::class) - fun testOnSupportNavigateUp() { - activity.onSupportNavigateUp() + val startedIntent = shadowActivity.nextStartedActivity + val actualIntent = if (startedIntent.action == Intent.ACTION_CHOOSER) { + startedIntent.getParcelableExtra(Intent.EXTRA_INTENT) + } else { + startedIntent + } + + Assert.assertNotNull(actualIntent) + Assert.assertEquals(Intent.ACTION_SEND, actualIntent?.action) + Assert.assertEquals("text/plain", actualIntent?.type) } -} +} \ No newline at end of file