mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 10:46:53 -04:00
kiwix#4159 migrated Help Fragment to jetpack Compose
This commit is contained in:
parent
d5a69757ec
commit
00330273d2
@ -22,6 +22,9 @@ import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.help.HelpFragment
|
||||
|
||||
class KiwixHelpFragment : HelpFragment() {
|
||||
override val navHostFragmentId: Int
|
||||
get() = org.kiwix.kiwixmobile.R.id.nav_host_fragment
|
||||
|
||||
override fun rawTitleDescriptionMap() =
|
||||
if (sharedPreferenceUtil.isPlayStoreBuildWithAndroid11OrAbove()) {
|
||||
listOf(
|
||||
|
@ -13,6 +13,8 @@ buildscript {
|
||||
}
|
||||
plugins {
|
||||
`android-library`
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("org.jetbrains.kotlin.plugin.compose") version Versions.org_jetbrains_kotlin_plugin_compose
|
||||
}
|
||||
plugins.apply(KiwixConfigurationPlugin::class)
|
||||
apply(plugin = "io.objectbox")
|
||||
@ -26,6 +28,12 @@ android {
|
||||
isMinifyEnabled = false
|
||||
}
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = Versions.kotlin_compiler_extension_version
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldUseLocalVersion() = File(projectDir, "libs").exists()
|
||||
@ -63,4 +71,17 @@ dependencies {
|
||||
implementation(Libs.kotlinx_coroutines_android)
|
||||
implementation(Libs.kotlinx_coroutines_rx3)
|
||||
implementation(Libs.zxing)
|
||||
|
||||
implementation(Libs.androidx_compose_material3)
|
||||
implementation(Libs.androidx_activity_compose)
|
||||
|
||||
implementation(Libs.androidx_compose_ui)
|
||||
implementation(platform(Libs.androidx_compose_bom))
|
||||
implementation(Libs.androidx_compose_ui_tooling)
|
||||
implementation(Libs.androidx_compose_runtime_livedata)
|
||||
implementation(Libs.androidx_compose_runtime_rxjava2)
|
||||
|
||||
// For Compose UI Testing
|
||||
androidTestImplementation(Libs.androidx_compose_ui_test_junit4)
|
||||
debugImplementation(Libs.androidx_compose_ui_tooling)
|
||||
}
|
||||
|
@ -17,19 +17,18 @@
|
||||
*/
|
||||
package org.kiwix.kiwixmobile.core.help
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.widget.Toolbar
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.navigation.Navigation
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.base.BaseActivity
|
||||
import org.kiwix.kiwixmobile.core.base.BaseFragment
|
||||
import org.kiwix.kiwixmobile.core.databinding.FragmentHelpBinding
|
||||
import org.kiwix.kiwixmobile.core.error.DiagnosticReportActivity
|
||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.start
|
||||
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||
import javax.inject.Inject
|
||||
@ -38,64 +37,71 @@ import javax.inject.Inject
|
||||
abstract class HelpFragment : BaseFragment() {
|
||||
@Inject
|
||||
lateinit var sharedPreferenceUtil: SharedPreferenceUtil
|
||||
private var fragmentHelpBinding: FragmentHelpBinding? = null
|
||||
protected open fun rawTitleDescriptionMap(): List<Pair<Int, Any>> = emptyList()
|
||||
override val fragmentToolbar: Toolbar? by lazy {
|
||||
fragmentHelpBinding?.root?.findViewById(R.id.toolbar)
|
||||
}
|
||||
override val fragmentTitle: String? by lazy { getString(R.string.menu_help) }
|
||||
|
||||
private val titleDescriptionMap by lazy {
|
||||
rawTitleDescriptionMap().associate { (title, description) ->
|
||||
val descriptionValue =
|
||||
when (description) {
|
||||
is String -> description
|
||||
is Int -> resources.getStringArray(description).joinToString(separator = "\n")
|
||||
else -> {
|
||||
throw IllegalArgumentException("Invalid description resource type for title: $title")
|
||||
}
|
||||
}
|
||||
protected abstract val navHostFragmentId: Int
|
||||
|
||||
getString(title) to descriptionValue
|
||||
// Instead of keeping the XML binding, we now directly return a ComposeView.
|
||||
protected open fun createFragmentView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?
|
||||
): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
// Create the helpScreen data using your rawTitleDescriptionMap.
|
||||
val helpScreenData = transformToHelpScreenData(
|
||||
requireContext(),
|
||||
rawTitleDescriptionMap()
|
||||
)
|
||||
// Retrieve the NavController if your composable needs it.
|
||||
val navController = Navigation.findNavController(requireActivity(), navHostFragmentId)
|
||||
// Call your HelpScreen composable.
|
||||
HelpScreen(data = helpScreenData, navController = navController)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Each subclass is responsible for providing its own raw data.
|
||||
protected open fun rawTitleDescriptionMap(): List<Pair<Int, Any>> = emptyList()
|
||||
|
||||
// The following properties are now optional – if no longer use an XML toolbar or title,
|
||||
// we can remove or update these accordingly.
|
||||
override val fragmentToolbar: Toolbar? by lazy {
|
||||
// Already Applied ad TopAppBAr in scaffold in composable
|
||||
null
|
||||
}
|
||||
override val fragmentTitle: String? by lazy { getString(R.string.menu_help) }
|
||||
|
||||
override fun inject(baseActivity: BaseActivity) {
|
||||
(baseActivity as CoreMainActivity).cachedComponent.inject(this)
|
||||
}
|
||||
|
||||
// Remove or adjust onViewCreated if you no longer need to manipulate XML-based views.
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val activity = requireActivity() as AppCompatActivity
|
||||
fragmentHelpBinding?.activityHelpDiagnosticImageView?.setOnClickListener {
|
||||
sendDiagnosticReport()
|
||||
}
|
||||
fragmentHelpBinding?.activityHelpDiagnosticTextView?.setOnClickListener {
|
||||
sendDiagnosticReport()
|
||||
}
|
||||
fragmentHelpBinding?.activityHelpRecyclerView?.addItemDecoration(
|
||||
DividerItemDecoration(activity, DividerItemDecoration.VERTICAL)
|
||||
)
|
||||
fragmentHelpBinding?.activityHelpRecyclerView?.adapter = HelpAdapter(titleDescriptionMap)
|
||||
// Any additional logic that is independent of the XML layout can be kept here.
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
fragmentHelpBinding =
|
||||
FragmentHelpBinding.inflate(inflater, container, false)
|
||||
return fragmentHelpBinding?.root
|
||||
}
|
||||
): View? = createFragmentView(inflater, container)
|
||||
}
|
||||
|
||||
private fun sendDiagnosticReport() {
|
||||
requireActivity().start<DiagnosticReportActivity>()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
fragmentHelpBinding?.root?.removeAllViews()
|
||||
fragmentHelpBinding = null
|
||||
// Util function to modify the data accordingly
|
||||
fun transformToHelpScreenData(
|
||||
context: Context,
|
||||
rawTitleDescriptionMap: List<Pair<Int, Any>>
|
||||
): List<HelpScreenItemDataClass> {
|
||||
return rawTitleDescriptionMap.map { (titleResId, description) ->
|
||||
val title = context.getString(titleResId)
|
||||
val descriptionValue = when (description) {
|
||||
is String -> description
|
||||
is Int -> context.resources.getStringArray(description).joinToString(separator = "\n")
|
||||
else -> {
|
||||
throw IllegalArgumentException("Invalid description resource type for title: $titleResId")
|
||||
}
|
||||
}
|
||||
HelpScreenItemDataClass(title, descriptionValue)
|
||||
}
|
||||
}
|
||||
|
152
core/src/main/java/org/kiwix/kiwixmobile/core/help/HelpScreen.kt
Normal file
152
core/src/main/java/org/kiwix/kiwixmobile/core/help/HelpScreen.kt
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile.core.help
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
import androidx.navigation.NavController
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.error.DiagnosticReportActivity
|
||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.start
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun HelpScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
data: List<HelpScreenItemDataClass>,
|
||||
navController: NavController
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val isDarkTheme = isSystemInDarkTheme()
|
||||
|
||||
val backgroundColor =
|
||||
if (isDarkTheme) colorResource(id = R.color.mine_shaft_gray900) else Color.White
|
||||
val dividerColor =
|
||||
if (isDarkTheme) colorResource(id = R.color.mine_shaft_gray600) else colorResource(
|
||||
id = R.color.mine_shaft_gray350
|
||||
)
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
modifier = modifier.padding(start = 16.dp),
|
||||
text = stringResource(id = R.string.menu_help),
|
||||
color = Color.White // Set title text color to white
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = navController::popBackStack) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.ArrowBack,
|
||||
contentDescription = "Back",
|
||||
tint = Color.White // Set navigation icon color to white
|
||||
)
|
||||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = Color.Black // Set top app bar background color to black
|
||||
)
|
||||
)
|
||||
},
|
||||
containerColor = backgroundColor
|
||||
) {
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(it)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
(context as? Activity)?.start<DiagnosticReportActivity>()
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Start
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.ic_feedback_orange_24dp),
|
||||
contentDescription = "Feedback",
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.send_report),
|
||||
color = if (isDarkTheme) Color.LightGray else Color.DarkGray,
|
||||
fontSize = 18.sp
|
||||
)
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
itemsIndexed(data, key = { _, item -> item.title }) { index, item ->
|
||||
HorizontalDivider(
|
||||
color = dividerColor
|
||||
)
|
||||
HelpScreenItem(data = item)
|
||||
}
|
||||
item {
|
||||
HorizontalDivider(
|
||||
color = dividerColor
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile.core.help
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
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
|
||||
|
||||
@Composable
|
||||
fun HelpScreenItem(
|
||||
modifier: Modifier = Modifier,
|
||||
data: HelpScreenItemDataClass,
|
||||
initiallyOpened: Boolean = false
|
||||
) {
|
||||
var isOpen by remember { mutableStateOf(initiallyOpened) }
|
||||
val isDarkTheme = isSystemInDarkTheme()
|
||||
val itemColor = if (isDarkTheme) Color.White else Color.Black
|
||||
val arrowRotation by animateFloatAsState(
|
||||
targetValue = if (isOpen) 180f else 0f,
|
||||
animationSpec = tween(300),
|
||||
label = "arrowRotation"
|
||||
)
|
||||
|
||||
val interactionSource = remember(::MutableInteractionSource)
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(interactionSource = interactionSource, indication = null, onClick = {
|
||||
isOpen = !isOpen
|
||||
})
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = data.title,
|
||||
fontSize = 18.sp,
|
||||
color = itemColor,
|
||||
fontWeight = FontWeight.SemiBold
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.Default.KeyboardArrowDown,
|
||||
contentDescription = "Open or Close DropDown",
|
||||
modifier = Modifier
|
||||
.graphicsLayer {
|
||||
rotationZ = arrowRotation
|
||||
}
|
||||
.size(46.dp),
|
||||
tint = itemColor
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
AnimatedVisibility(visible = isOpen) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, end = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = data.description,
|
||||
fontSize = 16.sp,
|
||||
textAlign = TextAlign.Left,
|
||||
color = itemColor,
|
||||
modifier = Modifier.padding(bottom = 8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile.core.help
|
||||
|
||||
//same as HelpItem data class in HelpAdapter.kt
|
||||
data class HelpScreenItemDataClass(val title: String, val description: String)
|
Loading…
x
Reference in New Issue
Block a user