Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit eb0dde67 authored by Arnau Mora's avatar Arnau Mora Committed by GitHub
Browse files

Jetpack Compose - Phase I (#140)



* Completed Phase I

Signed-off-by: default avatarArnau Mora <arnyminer.z@gmail.com>

* Upgraded Kotlin to `1.8.10`

Signed-off-by: default avatarArnau Mora <arnyminer.z@gmail.com>

* Migrated `Transformations.map`

Signed-off-by: default avatarArnau Mora <arnyminer.z@gmail.com>

* Made `useDarkTheme` nullable

Signed-off-by: default avatarArnau Mora <arnyminer.z@gmail.com>

* Moved version check

Signed-off-by: default avatarArnau Mora <arnyminer.z@gmail.com>

* Removed custom theme

Signed-off-by: default avatarArnau Mora Gras <arnyminerz@proton.me>

* Optimized and updated dependencies

Signed-off-by: default avatarArnau Mora Gras <arnyminerz@proton.me>

* Using Compose-based AboutLibraries

Signed-off-by: default avatarArnau Mora Gras <arnyminerz@proton.me>

* Added header

Signed-off-by: default avatarArnau Mora Gras <arnyminerz@proton.me>

* Updated compose compiler

Signed-off-by: default avatarArnau Mora Gras <arnyminerz@proton.me>

* Moved info header to its own function

Signed-off-by: default avatarArnau Mora Gras <arnyminerz@proton.me>

* Simplified layout

Signed-off-by: default avatarArnau Mora Gras <arnyminerz@proton.me>

* Increased logo padding

Signed-off-by: default avatarArnau Mora Gras <arnyminerz@proton.me>

* Use ComponentActivity; small layout changes

---------

Signed-off-by: default avatarArnau Mora <arnyminer.z@gmail.com>
Signed-off-by: default avatarArnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: default avatarRicki Hirner <hirner@bitfire.at>
parent 3576da12
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -39,6 +39,13 @@ android {
        buildConfig = true
        viewBinding = true
        dataBinding = true
        compose = true
    }

    composeOptions {
        // Keep this in sync with Kotlin version:
        // https://developer.android.com/jetpack/androidx/releases/compose-kotlin
        kotlinCompilerExtensionVersion = "${versions.compose}"
    }

    flavorDimensions "distribution"
@@ -85,6 +92,7 @@ dependencies {
    implementation project(':cert4android')
    implementation project(':ical4android')

    implementation 'androidx.activity:activity-compose:1.7.1'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'androidx.cardview:cardview:1.0.0'
    implementation 'androidx.core:core-ktx:1.10.0'
@@ -93,10 +101,19 @@ dependencies {
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
    implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
    implementation 'androidx.work:work-runtime-ktx:2.8.1'
    implementation 'com.google.android.material:material:1.8.0'
    implementation 'com.google.android.material:material:1.9.0'

    // Jetpack Compose
    def composeBom = platform("androidx.compose:compose-bom:${versions.composeBom}")
    implementation composeBom
    androidTestImplementation composeBom
    implementation 'androidx.compose.material:material'
    debugImplementation "androidx.compose.ui:ui-tooling"
    implementation "androidx.compose.ui:ui-tooling-preview"
    implementation 'com.google.accompanist:accompanist-themeadapter-material:0.30.1'

    implementation 'com.jaredrummler:colorpicker:1.1.0'
    implementation "com.mikepenz:aboutlibraries:${versions.aboutLibs}"
    implementation "com.mikepenz:aboutlibraries-compose:${versions.aboutLibs}"
    implementation "com.squareup.okhttp3:okhttp:${versions.okhttp}"
    implementation "com.squareup.okhttp3:okhttp-brotli:${versions.okhttp}"
    implementation "com.squareup.okhttp3:okhttp-coroutines:${versions.okhttp}"
@@ -122,3 +139,8 @@ dependencies {

    testImplementation 'junit:junit:4.13.2'
}

aboutLibraries {
    duplicationMode = com.mikepenz.aboutlibraries.plugin.DuplicateMode.MERGE
    includePlatform = false
}
 No newline at end of file
+180 −39
Original line number Diff line number Diff line
@@ -9,57 +9,67 @@ import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import android.widget.TextView
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.StringRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.AlertDialog
import androidx.compose.material.ContentAlpha
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedButton
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalContext
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.compose.ui.viewinterop.AndroidView
import androidx.core.graphics.drawable.toBitmap
import androidx.core.text.HtmlCompat
import at.bitfire.icsdroid.BuildConfig
import at.bitfire.icsdroid.Constants
import at.bitfire.icsdroid.R
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.LibsBuilder
import com.google.accompanist.themeadapter.material.MdcTheme
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer

class InfoActivity: AppCompatActivity() {
class InfoActivity: ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (savedInstanceState == null) {
            val builder = LibsBuilder()
                .withAboutIconShown(true)
                .withAboutAppName(getString(R.string.app_name))
                .withAboutDescription(getString(R.string.app_info_description))
                .withAboutVersionShownName(true)
                .withAboutVersionString(getString(R.string.app_info_version, BuildConfig.VERSION_NAME, BuildConfig.FLAVOR))
                .withAboutSpecial1(getString(R.string.app_info_gplv3))
                .withAboutSpecial1Description(getString(R.string.app_info_gplv3_note))
                .withLicenseShown(true)

                .withFields(R.string::class.java.fields)
                .withLibraryModification("org_brotli__dec", Libs.LibraryFields.LIBRARY_NAME, "Brotli")
                .withLibraryModification("org_brotli__dec", Libs.LibraryFields.AUTHOR_NAME, "Google")

            if (BuildConfig.FLAVOR != "gplay") {
                builder
                    .withAboutSpecial2(getString(R.string.app_info_donate))
                    .withAboutSpecial2Description(getString(R.string.donate_message))
            }

            supportFragmentManager.beginTransaction()
                .replace(android.R.id.content, builder.supportFragment())
                .commit()
        setContent {
            MainLayout()
        }
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.app_info_activity, menu)
        return true
    }

    fun showWebSite(item: MenuItem) {
    fun showWebSite() {
        launchUri(Uri.parse("https://icsx5.bitfire.at/?pk_campaign=icsx5-app&pk_kwd=info-activity"))
    }

    fun showTwitter(item: MenuItem) {
    fun showTwitter() {
        launchUri(Uri.parse("https://twitter.com/icsx5app"))
    }

@@ -68,8 +78,139 @@ class InfoActivity: AppCompatActivity() {
        try {
            startActivity(intent)
        } catch (e: ActivityNotFoundException) {
            Log.w(Constants.TAG, "No browser installed")
            Toast.makeText(this, getString(R.string.no_browser), Toast.LENGTH_LONG).show()
            Log.w(Constants.TAG, "No browser to view $uri")
        }
    }


    @Composable
    @Preview
    fun MainLayout() {
        MdcTheme {
            Scaffold(
                topBar = {
                    TopAppBar(
                        navigationIcon = {
                            IconButton({ onNavigateUp() }) {
                                Icon(
                                    imageVector = Icons.Filled.ArrowBack,
                                    contentDescription = null
                                )
                            }
                        },
                        title = {
                            Text(
                                stringResource(R.string.app_name)
                            )
                        },
                        actions = {
                            IconButton({ showWebSite() }) {
                                Icon(
                                    painter = painterResource(R.drawable.ic_public),
                                    contentDescription = stringResource(R.string.app_info_web_site)
                                )
                            }
                            IconButton({ showTwitter() }) {
                                Icon(
                                    painter = painterResource(R.drawable.twitter_white),
                                    contentDescription = stringResource(R.string.app_info_web_site)
                                )
                            }
                        }
                    )
                }
            ) { contentPadding ->
                Column(Modifier.padding(contentPadding)) {
                    Header()
                    License()
                    LibrariesContainer()
                }
            }
        }
    }

    @Composable
    fun Header() {
        Column(
            modifier = Modifier.fillMaxWidth(),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            val context = LocalContext.current

            Image(
                bitmap = context.applicationInfo
                    .loadIcon(context.packageManager)
                    .toBitmap()
                    .asImageBitmap(),
                contentDescription = null,
                modifier = Modifier
                    .padding(vertical = 12.dp)
                    .size(72.dp)
            )
            Text(
                text = stringResource(R.string.app_name),
                style = MaterialTheme.typography.h5,
                color = MaterialTheme.colors.onBackground
            )
            Text(
                text = stringResource(
                    R.string.app_info_version,
                    BuildConfig.VERSION_NAME,
                    BuildConfig.FLAVOR
                ),
                style = MaterialTheme.typography.subtitle1,
                color = MaterialTheme.colors.onBackground,
                modifier = Modifier.alpha(ContentAlpha.medium)
            )
        }
    }

    @Composable
    fun License() {
        val showLicenseDialog = rememberSaveable { mutableStateOf(false) }
        if (showLicenseDialog.value)
            TextDialog(R.string.app_info_gplv3_note, showLicenseDialog)

        val showDonateDialog = rememberSaveable { mutableStateOf(false) }
        if (showDonateDialog.value)
            TextDialog(R.string.donate_message, showDonateDialog)

        Row {
            OutlinedButton(
                onClick = { showLicenseDialog.value = true },
                modifier = Modifier
                    .weight(1f)
                    .padding(horizontal = 4.dp)
            ) {
                Text(stringResource(R.string.app_info_gplv3))
            }
            OutlinedButton(
                onClick = { showDonateDialog.value = true },
                modifier = Modifier
                    .weight(1f)
                    .padding(horizontal = 4.dp)
            ) {
                Text(stringResource(R.string.app_info_donate))
            }
        }
    }

    @Composable
    fun TextDialog(@StringRes text: Int, state: MutableState<Boolean>, buttons: @Composable () -> Unit = {}) {
        AlertDialog(
            text = {
                AndroidView({ context ->
                   TextView(context).also {
                       it.text = HtmlCompat.fromHtml(
                           getString(text).replace("\n", "<br/>"),
                           HtmlCompat.FROM_HTML_MODE_COMPACT)
                   }
                }, modifier = Modifier.verticalScroll(rememberScrollState()))
            },
            buttons = buttons,
            onDismissRequest = { state.value = false }
        )
    }

}
 No newline at end of file
+0 −15
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">

    <item app:showAsAction="ifRoom"
          android:icon="@drawable/ic_public"
          android:onClick="showWebSite"
          android:title="@string/app_info_web_site" />

    <item app:showAsAction="ifRoom"
          android:icon="@drawable/twitter_white"
          android:onClick="showTwitter"
          android:title="@string/app_info_twitter"/>

</menu>
 No newline at end of file
+3 −2
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
    <string name="calendar_permissions_required">Calendar permissions required</string>
    <string name="notification_permissions_required">Notification permissions required</string>
    <string name="could_not_load_calendar">Couldn\'t load calendar</string>
    <string name="no_browser">No browser installed</string>
    <string name="notification_channel_sync_problem">Sync problems</string>
    <string name="permissions_required">Permissions required</string>
    <string name="permissions_grant">Grant</string>
@@ -104,7 +105,7 @@
    <string name="activity_app_info">App info</string>
    <string name="app_info_version">Version %1$s-%2$s</string>
    <string name="app_info_gplv3" translatable="false">GPLv3</string>
    <string name="app_info_gplv3_note"><![CDATA[
    <string name="app_info_gplv3_note"><![CDATA["
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
@@ -117,7 +118,7 @@ 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 <a href="https://www.gnu.org/licenses/">https://www.gnu.org/licenses/</a>.
    ]]></string>
    "]]></string>
    <string name="app_info_donate">Donate</string>
    <string name="app_info_description">Subscribe to Webcal feeds</string>
    <string name="app_info_twitter">News &amp; updates</string>
+5 −3
Original line number Diff line number Diff line
buildscript {
    ext.versions = [
        aboutLibs: '8.9.4',
        aboutLibs: '10.6.2',
        kotlin: '1.8.20',
        okhttp: '5.0.0-alpha.11',
        ksp: '1.0.10',
        room: '2.5.1'
        ksp: '1.0.11',
        room: '2.5.1',
        compose: '1.4.6',
        composeBom: '2023.04.01'        // https://developer.android.com/jetpack/compose/bom
    ]

    repositories {