diff --git a/app/src/main/java/be/scri/fragments/AboutFragment.kt b/app/src/main/java/be/scri/fragments/AboutFragment.kt index bcda33a2..4427a6db 100644 --- a/app/src/main/java/be/scri/fragments/AboutFragment.kt +++ b/app/src/main/java/be/scri/fragments/AboutFragment.kt @@ -5,27 +5,23 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.addCallback -import androidx.recyclerview.widget.LinearLayoutManager -import be.scri.BuildConfig +import androidx.appcompat.app.AppCompatDelegate +import androidx.compose.ui.platform.ComposeView import be.scri.R import be.scri.activities.MainActivity -import be.scri.databinding.FragmentAboutBinding -import be.scri.extensions.addCustomItemDecoration -import be.scri.helpers.CustomAdapter import be.scri.helpers.HintUtils +import be.scri.helpers.PreferencesHelper import be.scri.helpers.RatingHelper import be.scri.helpers.ShareHelper -import be.scri.models.ItemsViewModel +import be.scri.ui.screens.AboutScreen +import be.scri.ui.theme.ScribeTheme class AboutFragment : ScribeFragment("About") { - private lateinit var binding: FragmentAboutBinding - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View { - binding = FragmentAboutBinding.inflate(inflater, container, false) val callback = requireActivity().onBackPressedDispatcher.addCallback(this) { getParentFragmentManager().popBackStack() @@ -34,149 +30,33 @@ class AboutFragment : ScribeFragment("About") { (requireActivity() as MainActivity).setActionBarTitle(R.string.app_about_title) (requireActivity() as MainActivity).setActionBarVisibility(false) (requireActivity() as MainActivity).setActionBarButtonVisibility(false) - return binding.root - } - - override fun onViewCreated( - view: View, - savedInstanceState: Bundle?, - ) { - super.onViewCreated(view, savedInstanceState) - setupRecyclerViews() - } - private fun setupRecyclerViews() { - val recyclerView1 = binding.recycleView2 - recyclerView1.layoutManager = LinearLayoutManager(context) - recyclerView1.adapter = CustomAdapter(getFirstRecyclerViewData(), requireContext()) - recyclerView1.suppressLayout(true) - recyclerView1.apply { - addCustomItemDecoration(requireContext()) - } - val recyclerView2 = binding.recycleView - recyclerView2.layoutManager = LinearLayoutManager(context) - recyclerView2.adapter = CustomAdapter(getSecondRecyclerViewData(), requireContext()) - recyclerView2.suppressLayout(true) - recyclerView2.apply { - addCustomItemDecoration(requireContext()) - } - val recyclerView3 = binding.recycleView3 - recyclerView3.layoutManager = LinearLayoutManager(context) - recyclerView3.adapter = CustomAdapter(getThirdRecyclerViewData(), requireContext()) - recyclerView3.suppressLayout(true) - recyclerView3.apply { - addCustomItemDecoration(requireContext()) + return ComposeView(requireContext()).apply { + setContent { + ScribeTheme( + useDarkTheme = + PreferencesHelper.getUserDarkModePreference(requireContext()) + == AppCompatDelegate.MODE_NIGHT_YES, + ) { + AboutScreen( + onWikimediaAndScribeClick = { + loadOtherFragment(WikimediaScribeFragment(), "WikimediaScribePage") + }, + onShareScribeClick = { ShareHelper.shareScribe(requireContext()) }, + onPrivacyPolicyClick = { loadOtherFragment(PrivacyPolicyFragment(), null) }, + onThirdPartyLicensesClick = { loadOtherFragment(ThirdPartyFragment(), null) }, + onRateScribeClick = { + RatingHelper.rateScribe(requireContext(), activity as MainActivity) + }, + onMailClick = { ShareHelper.sendEmail(requireContext()) }, + onResetHintsClick = ::resetHints, + context = requireContext(), + ) + } + } } } - private fun getFirstRecyclerViewData(): List = - listOf( - ItemsViewModel( - image = R.drawable.github_logo, - text = ItemsViewModel.Text(R.string.app_about_community_github), - image2 = R.drawable.external_link, - url = "https://github.com/scribe-org/Scribe-Android", - activity = null, - action = null, - ), - ItemsViewModel( - image = R.drawable.matrix_icon, - text = ItemsViewModel.Text(R.string.app_about_community_matrix), - image2 = R.drawable.external_link, - url = "https://matrix.to/%23/%23scribe_community:matrix.org", - activity = null, - action = null, - ), - ItemsViewModel( - image = R.drawable.mastodon_svg_icon, - text = ItemsViewModel.Text(R.string.app_about_community_mastodon), - image2 = R.drawable.external_link, - url = "https://wikis.world/@scribe", - activity = null, - action = null, - ), - ItemsViewModel( - image = R.drawable.share_icon, - text = ItemsViewModel.Text(R.string.app_about_community_share_scribe), - image2 = R.drawable.external_link, - url = null, - activity = null, - action = ({ ShareHelper.shareScribe(requireContext()) }), - ), - ItemsViewModel( - image = R.drawable.wikimedia_logo_black, - text = ItemsViewModel.Text(R.string.app_about_community_wikimedia), - image2 = R.drawable.right_arrow, - url = null, - activity = null, - action = ({ loadOtherFragment(WikimediaScribeFragment(), "WikimediaScribePage") }), - ), - ) - - private fun getSecondRecyclerViewData(): List = - listOf( - ItemsViewModel( - image = R.drawable.star, - text = ItemsViewModel.Text(R.string.app_about_feedback_rate_scribe), - image2 = R.drawable.external_link, - url = null, - activity = null, - action = ({ RatingHelper.rateScribe(requireContext(), activity as MainActivity) }), - ), - ItemsViewModel( - image = R.drawable.bug_report_icon, - text = ItemsViewModel.Text(R.string.app_about_feedback_bug_report), - image2 = R.drawable.external_link, - url = "https://github.com/scribe-org/Scribe-Android/issues", - activity = null, - action = null, - ), - ItemsViewModel( - image = R.drawable.mail_icon, - text = ItemsViewModel.Text(R.string.app_about_feedback_email), - image2 = R.drawable.external_link, - url = null, - activity = null, - action = ({ ShareHelper.sendEmail(requireContext()) }), - ), - ItemsViewModel( - image = R.drawable.bookmark_icon, - text = ItemsViewModel.Text(R.string.app_about_feedback_version, BuildConfig.VERSION_NAME), - image2 = R.drawable.external_link, - url = "https://github.com/scribe-org/Scribe-Android/releases/", - activity = null, - action = null, - ), - ItemsViewModel( - image = R.drawable.light_bulb_icon, - text = ItemsViewModel.Text(R.string.app_about_feedback_app_hints), - image2 = R.drawable.counter_clockwise_icon, - url = null, - activity = null, - action = ::resetHints, - ), - ) - - private fun getThirdRecyclerViewData(): List = - listOf( - ItemsViewModel( - image = R.drawable.shield_lock, - text = ItemsViewModel.Text(R.string.app_about_legal_privacy_policy), - image2 = R.drawable.right_arrow, - url = null, - activity = null, - action = ({ loadOtherFragment(PrivacyPolicyFragment(), null) }), - ), - ItemsViewModel( - image = R.drawable.license_icon, - text = ItemsViewModel.Text(R.string.app_about_legal_third_party), - image2 = R.drawable.right_arrow, - url = null, - activity = null, - action = ({ loadOtherFragment(ThirdPartyFragment(), null) }), - ), - ) - private fun resetHints() { HintUtils.resetHints(requireContext()) (activity as MainActivity).showHint("hint_shown_about", R.string.app_about_app_hint) diff --git a/app/src/main/java/be/scri/ui/common/components/AboutPageItemComp.kt b/app/src/main/java/be/scri/ui/common/components/AboutPageItemComp.kt new file mode 100644 index 00000000..7fbad0fe --- /dev/null +++ b/app/src/main/java/be/scri/ui/common/components/AboutPageItemComp.kt @@ -0,0 +1,73 @@ +package be.scri.ui.common.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +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.Color +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import be.scri.R + +@Composable +fun AboutPageItemComp( + title: String, + leadingIcon: Int, + trailingIcon: Int, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + Row( + modifier = + modifier + .fillMaxWidth() + .padding( + start = 12.dp, + end = 20.dp, + top = 10.dp, + bottom = 10.dp, + ).clip(RoundedCornerShape(12.dp)) + .clickable(onClick = onClick), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + painter = painterResource(leadingIcon), + modifier = + Modifier + .padding(start = 2.dp) + .size(22.dp), + tint = colorResource(R.color.app_text_color), + contentDescription = "Right Arrow", + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = title, + modifier = Modifier.weight(1f).padding(start = 4.dp), + fontSize = 16.sp, + color = colorResource(R.color.app_text_color), + style = MaterialTheme.typography.bodyMedium, + ) + Icon( + painter = painterResource(trailingIcon), + modifier = + Modifier + .padding(start = 6.dp) + .size(24.dp), + contentDescription = "Right Arrow", + tint = Color.Gray, + ) + } +} diff --git a/app/src/main/java/be/scri/ui/common/components/ItemCardContainer.kt b/app/src/main/java/be/scri/ui/common/components/ItemCardContainer.kt index f83176a5..20cea17c 100644 --- a/app/src/main/java/be/scri/ui/common/components/ItemCardContainer.kt +++ b/app/src/main/java/be/scri/ui/common/components/ItemCardContainer.kt @@ -27,7 +27,7 @@ fun ItemsCardContainer( Column( modifier = Modifier - .padding(vertical = 4.dp, horizontal = 4.dp), + .padding(vertical = 10.dp, horizontal = 4.dp), ) { cardItemsList.items.forEach { item -> when (item) { @@ -52,6 +52,12 @@ fun ItemsCardContainer( } is ScribeItem.ExternalLinkItem -> { + AboutPageItemComp( + title = item.title, + leadingIcon = item.leadingIcon, + trailingIcon = item.trailingIcon, + onClick = item.onClick, + ) } } @@ -60,7 +66,7 @@ fun ItemsCardContainer( cardItemsList.items.indexOf(item) != cardItemsList.items.lastIndex ) { HorizontalDivider( - color = Color.Gray.copy(alpha = 0.25f), + color = Color.Gray.copy(alpha = 0.3f), thickness = 1.dp, modifier = Modifier.padding( diff --git a/app/src/main/java/be/scri/ui/models/ScribeItem.kt b/app/src/main/java/be/scri/ui/models/ScribeItem.kt index c55d4aba..cd2e91e9 100644 --- a/app/src/main/java/be/scri/ui/models/ScribeItem.kt +++ b/app/src/main/java/be/scri/ui/models/ScribeItem.kt @@ -1,5 +1,7 @@ package be.scri.ui.models +import androidx.annotation.DrawableRes + sealed class ScribeItem( open val title: String, open val desc: String?, @@ -19,9 +21,11 @@ sealed class ScribeItem( data class ExternalLinkItem( override val title: String, - override val desc: String, - val url: String, - val onClick: (String) -> Unit, + override val desc: String? = null, + @DrawableRes val leadingIcon: Int, + @DrawableRes val trailingIcon: Int, + val url: String?, + val onClick: () -> Unit, ) : ScribeItem(title, desc) data class CustomItem( diff --git a/app/src/main/java/be/scri/ui/screens/AboutScreen.kt b/app/src/main/java/be/scri/ui/screens/AboutScreen.kt new file mode 100644 index 00000000..695db230 --- /dev/null +++ b/app/src/main/java/be/scri/ui/screens/AboutScreen.kt @@ -0,0 +1,267 @@ +package be.scri.ui.screens + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.net.Uri +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import be.scri.BuildConfig +import be.scri.R +import be.scri.ui.common.components.ItemCardContainerWithTitle +import be.scri.ui.models.ScribeItem +import be.scri.ui.models.ScribeItemList + +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") +@Composable +fun AboutScreen( + onWikimediaAndScribeClick: () -> Unit, + onShareScribeClick: () -> Unit, + onPrivacyPolicyClick: () -> Unit, + onThirdPartyLicensesClick: () -> Unit, + onRateScribeClick: () -> Unit, + onMailClick: () -> Unit, + onResetHintsClick: () -> Unit, + context: Context, + modifier: Modifier = Modifier, +) { + val scrollState = rememberScrollState() + + val communityList = + ScribeItemList( + items = + getCommunityList( + onWikimediaAndScribeClick = onWikimediaAndScribeClick, + onShareScribeClick = onShareScribeClick, + context = context, + ), + ) + + val feedbackAndSupportList = + ScribeItemList( + items = + getFeedbackAndSupportList( + onRateScribeClick = onRateScribeClick, + onMailClick = onMailClick, + onResetHintsClick = onResetHintsClick, + context = context, + ), + ) + + val legalItemsList = + ScribeItemList( + items = + getLegalListItems( + onPrivacyPolicyClick = onPrivacyPolicyClick, + onThirdPartyLicensesClick = onThirdPartyLicensesClick, + ), + ) + + Scaffold( + modifier = + modifier + .background(color = MaterialTheme.colorScheme.background), + ) { + Column( + modifier = + Modifier + .fillMaxSize() + .verticalScroll(scrollState), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + ItemCardContainerWithTitle( + title = stringResource(R.string.community_title), + cardItemsList = communityList, + isDivider = true, + ) + + ItemCardContainerWithTitle( + title = stringResource(R.string.app_about_feedback_title), + cardItemsList = feedbackAndSupportList, + isDivider = true, + ) + + ItemCardContainerWithTitle( + title = stringResource(R.string.app_about_legal_title), + cardItemsList = legalItemsList, + isDivider = true, + ) + + Spacer(modifier = Modifier.height(80.dp)) + } + } +} + +@Composable +fun getCommunityList( + onWikimediaAndScribeClick: () -> Unit, + onShareScribeClick: () -> Unit, + context: Context, +): List = + listOf( + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.github_logo, + title = stringResource(R.string.app_about_community_github), + trailingIcon = R.drawable.external_link, + url = "https://github.com/scribe-org/Scribe-Android", + onClick = { + val intent = + Intent( + Intent.ACTION_VIEW, + Uri.parse( + "https://github.com/scribe-org/Scribe-Android", + ), + ) + context.startActivity(intent) + }, + ), + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.matrix_icon, + title = stringResource(R.string.app_about_community_matrix), + trailingIcon = R.drawable.external_link, + url = "https://matrix.to/%23/%23scribe_community:matrix.org", + onClick = { + val intent = + Intent( + Intent.ACTION_VIEW, + Uri.parse( + "https://matrix.to/%23/%23scribe_community:matrix.org", + ), + ) + context.startActivity(intent) + }, + ), + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.mastodon_svg_icon, + title = stringResource(R.string.app_about_community_mastodon), + trailingIcon = R.drawable.external_link, + url = "https://wikis.world/@scribe", + onClick = { + val intent = + Intent( + Intent.ACTION_VIEW, + Uri.parse( + "https://wikis.world/@scribe", + ), + ) + context.startActivity(intent) + }, + ), + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.share_icon, + title = stringResource(R.string.app_about_community_share_scribe), + trailingIcon = R.drawable.external_link, + url = null, + onClick = { + onShareScribeClick() + }, + ), + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.wikimedia_logo_black, + title = stringResource(R.string.app_about_community_wikimedia), + trailingIcon = R.drawable.right_arrow, + url = null, + onClick = { + onWikimediaAndScribeClick() + }, + ), + ) + +@Composable +fun getFeedbackAndSupportList( + onRateScribeClick: () -> Unit, + onMailClick: () -> Unit, + onResetHintsClick: () -> Unit, + context: Context, +): List = + listOf( + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.star, + title = stringResource(R.string.app_about_feedback_rate_scribe), + trailingIcon = R.drawable.external_link, + url = null, + onClick = { + onRateScribeClick() + }, + ), + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.bug_report_icon, + title = stringResource(R.string.app_about_feedback_bug_report), + trailingIcon = R.drawable.external_link, + url = "https://github.com/scribe-org/Scribe-Android/issues", + onClick = { + val intent = + Intent( + Intent.ACTION_VIEW, + Uri.parse( + "https://github.com/scribe-org/Scribe-Android/issues", + ), + ) + context.startActivity(intent) + }, + ), + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.mail_icon, + title = stringResource(R.string.app_about_feedback_email), + trailingIcon = R.drawable.external_link, + url = null, + onClick = { onMailClick() }, + ), + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.bookmark_icon, + title = stringResource(R.string.app_about_feedback_version, BuildConfig.VERSION_NAME), + trailingIcon = R.drawable.external_link, + url = "https://github.com/scribe-org/Scribe-Android/releases/", + onClick = { + val intent = + Intent( + Intent.ACTION_VIEW, + Uri.parse( + "https://github.com/scribe-org/Scribe-Android/releases/", + ), + ) + context.startActivity(intent) + }, + ), + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.light_bulb_icon, + title = stringResource(R.string.app_about_feedback_app_hints), + trailingIcon = R.drawable.counter_clockwise_icon, + url = null, + onClick = { onResetHintsClick() }, + ), + ) + +@Composable +fun getLegalListItems( + onPrivacyPolicyClick: () -> Unit, + onThirdPartyLicensesClick: () -> Unit, +): List = + listOf( + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.shield_lock, + title = stringResource(R.string.app_about_legal_privacy_policy), + trailingIcon = R.drawable.right_arrow, + url = null, + onClick = { onPrivacyPolicyClick() }, + ), + ScribeItem.ExternalLinkItem( + leadingIcon = R.drawable.license_icon, + title = stringResource(R.string.app_about_legal_third_party), + trailingIcon = R.drawable.right_arrow, + url = null, + onClick = { onThirdPartyLicensesClick() }, + ), + )