mirror of
https://github.com/bitfireAT/davx5-ose
synced 2024-10-15 15:59:18 +00:00
Rewrite OpenSourceFragment
to Compose (#581)
* Migrated to Jetpack Compose Signed-off-by: Arnau Mora <arnyminerz@proton.me> * Removed layout file Signed-off-by: Arnau Mora <arnyminerz@proton.me> * Adapt paddings and font size * Added check for non-available browsers Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me> * Add SafeAndroidUriHandler --------- Signed-off-by: Arnau Mora <arnyminerz@proton.me> Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me> Co-authored-by: Ricki Hirner <hirner@bitfire.at>
This commit is contained in:
parent
af00ff0c4c
commit
f6ac4e02d6
|
@ -85,6 +85,7 @@ object UiUtils {
|
|||
* @return true on success, false if the Intent could not be resolved (for instance, because
|
||||
* there is no user agent installed)
|
||||
*/
|
||||
@Deprecated("Use SafeAndroidUriHandler (Compose) instead")
|
||||
fun launchUri(context: Context, uri: Uri, action: String = Intent.ACTION_VIEW, toastInstallBrowser: Boolean = true): Boolean {
|
||||
val intent = Intent(action, uri)
|
||||
try {
|
||||
|
|
|
@ -9,16 +9,47 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Checkbox
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.OutlinedButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
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.layout.ContentScale
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.databinding.ObservableBoolean
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.ViewModel
|
||||
import at.bitfire.davdroid.App
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.databinding.IntroOpenSourceBinding
|
||||
import at.bitfire.davdroid.settings.SettingsManager
|
||||
import at.bitfire.davdroid.ui.UiUtils
|
||||
import at.bitfire.davdroid.ui.intro.OpenSourceFragment.Model.Companion.SETTING_NEXT_DONATION_POPUP
|
||||
import at.bitfire.davdroid.ui.widget.CardWithImage
|
||||
import at.bitfire.davdroid.ui.widget.SafeAndroidUriHandler
|
||||
import com.google.accompanist.themeadapter.material.MdcTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
@ -30,18 +61,83 @@ class OpenSourceFragment: Fragment() {
|
|||
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
val binding = IntroOpenSourceBinding.inflate(inflater, container, false)
|
||||
binding.lifecycleOwner = viewLifecycleOwner
|
||||
binding.model = model
|
||||
return ComposeView(requireContext()).apply {
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||
setContent {
|
||||
MdcTheme {
|
||||
var dontShow by remember { mutableStateOf(model.dontShow.get()) }
|
||||
|
||||
binding.text.text = getString(R.string.intro_open_source_text, getString(R.string.app_name))
|
||||
binding.moreInfo.setOnClickListener {
|
||||
UiUtils.launchUri(requireActivity(), App.homepageUrl(requireActivity()).buildUpon()
|
||||
.appendPath("donate")
|
||||
.build())
|
||||
val uriHandler = SafeAndroidUriHandler(LocalContext.current)
|
||||
CompositionLocalProvider(LocalUriHandler provides uriHandler) {
|
||||
FragmentContent(
|
||||
dontShow = dontShow,
|
||||
onChangeDontShow = {
|
||||
model.dontShow.set(it)
|
||||
dontShow = it
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return binding.root
|
||||
|
||||
@Preview(
|
||||
showBackground = true,
|
||||
showSystemUi = true
|
||||
)
|
||||
@Composable
|
||||
fun FragmentContent(
|
||||
dontShow: Boolean = false,
|
||||
onChangeDontShow: (Boolean) -> Unit = {}
|
||||
) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(8.dp)
|
||||
) {
|
||||
CardWithImage(
|
||||
title = stringResource(R.string.intro_open_source_title),
|
||||
image = painterResource(R.drawable.intro_open_source),
|
||||
imageContentScale = ContentScale.Inside,
|
||||
message = stringResource(
|
||||
R.string.intro_open_source_text,
|
||||
stringResource(R.string.app_name)
|
||||
)
|
||||
) {
|
||||
OutlinedButton(
|
||||
onClick = {
|
||||
uriHandler.openUri(
|
||||
App.homepageUrl(requireActivity())
|
||||
.buildUpon()
|
||||
.appendPath("donate")
|
||||
.build()
|
||||
.toString()
|
||||
)
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.intro_open_source_details))
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Checkbox(
|
||||
checked = dontShow,
|
||||
onCheckedChange = onChangeDontShow
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.intro_battery_dont_show),
|
||||
style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.clickable { onChangeDontShow(!dontShow) }
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(90.dp))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
@ -38,14 +37,13 @@ fun CardWithImage(
|
|||
image: Painter? = null,
|
||||
imageContentDescription: String? = null,
|
||||
imageAlignment: Alignment = Alignment.Center,
|
||||
imageContentScale: ContentScale = ContentScale.Crop,
|
||||
message: String? = null,
|
||||
subtitle: String? = null,
|
||||
icon: ImageVector? = null,
|
||||
iconContentDescription: String? = null,
|
||||
content: @Composable ColumnScope.() -> Unit = {}
|
||||
) {
|
||||
val configuration = LocalConfiguration.current
|
||||
|
||||
Card(modifier) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
|
@ -57,7 +55,7 @@ fun CardWithImage(
|
|||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(max = dimensionResource(R.dimen.card_theme_max_height)),
|
||||
contentScale = ContentScale.Crop,
|
||||
contentScale = imageContentScale,
|
||||
alignment = imageAlignment
|
||||
)
|
||||
}
|
||||
|
@ -70,7 +68,7 @@ fun CardWithImage(
|
|||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp),
|
||||
.padding(top = 8.dp, bottom = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
icon?.let {
|
||||
|
@ -103,7 +101,7 @@ fun CardWithImage(
|
|||
text = it,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 12.dp),
|
||||
.padding(vertical = 4.dp),
|
||||
style = MaterialTheme.typography.body1
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package at.bitfire.davdroid.ui.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.compose.ui.platform.AndroidUriHandler
|
||||
import androidx.compose.ui.platform.UriHandler
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import java.util.logging.Level
|
||||
|
||||
class SafeAndroidUriHandler(
|
||||
val context: Context
|
||||
): UriHandler {
|
||||
|
||||
override fun openUri(uri: String) {
|
||||
try {
|
||||
AndroidUriHandler(context).openUri(uri)
|
||||
} catch (e: Exception) {
|
||||
Logger.log.log(Level.WARNING, "No browser available", e)
|
||||
// no browser available
|
||||
Toast.makeText(context, R.string.install_browser, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<data>
|
||||
<variable name="model" type="at.bitfire.davdroid.ui.intro.OpenSourceFragment.Model"/>
|
||||
</data>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/appintro2_bottombar_height"
|
||||
android:background="?android:attr/colorBackground">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/activity_margin">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<at.bitfire.davdroid.ui.widget.CropImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxHeight="@dimen/card_theme_max_height"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/heading"
|
||||
android:adjustViewBounds="true"
|
||||
app:verticalOffsetPercent=".45"
|
||||
app:srcCompat="@drawable/intro_open_source"/>
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_begin="@dimen/card_padding" />
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/end"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_end="@dimen/card_padding" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/heading"
|
||||
style="@style/TextAppearance.MaterialComponents.Headline6"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/card_margin_title_text"
|
||||
android:text="@string/intro_open_source_title"
|
||||
android:textAlignment="viewStart"
|
||||
app:layout_constraintBottom_toTopOf="@id/text"
|
||||
app:layout_constraintEnd_toStartOf="@id/end"
|
||||
app:layout_constraintStart_toEndOf="@id/start"
|
||||
app:layout_constraintTop_toBottomOf="@id/image" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
style="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/card_margin_title_text"
|
||||
android:text="@string/intro_open_source_text"
|
||||
android:textAlignment="viewStart"
|
||||
app:layout_constraintBottom_toTopOf="@id/moreInfo"
|
||||
app:layout_constraintEnd_toStartOf="@id/end"
|
||||
app:layout_constraintStart_toEndOf="@id/start"
|
||||
app:layout_constraintTop_toBottomOf="@id/heading" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/moreInfo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@id/text"
|
||||
app:layout_constraintBottom_toTopOf="@id/dontShow"
|
||||
app:layout_constraintStart_toEndOf="@id/start"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_gravity="center"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:text="@string/intro_open_source_details" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/dontShow"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="@={model.dontShow}"
|
||||
android:text="@string/intro_open_source_dont_show"
|
||||
android:textAlignment="viewStart"
|
||||
app:layout_constraintEnd_toStartOf="@id/end"
|
||||
app:layout_constraintStart_toEndOf="@id/start"
|
||||
app:layout_constraintTop_toBottomOf="@id/moreInfo" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</layout>
|
Loading…
Reference in a new issue