Skip to content

Commit d3f7549

Browse files
WIP
1 parent 18a2c3d commit d3f7549

File tree

9 files changed

+253
-525
lines changed

9 files changed

+253
-525
lines changed

app/build.gradle.kts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ plugins {
55
id("com.android.application")
66
id("com.github.spotbugs")
77
id("org.jetbrains.kotlin.android")
8+
id("org.jetbrains.kotlin.plugin.compose") version "2.1.20"
89
}
910

1011
spotbugs {
@@ -51,6 +52,7 @@ android {
5152

5253
buildFeatures {
5354
buildConfig = true
55+
compose = true
5456
viewBinding = true
5557
}
5658

@@ -110,6 +112,7 @@ android {
110112

111113
dependencies {
112114
// AndroidX
115+
implementation("androidx.activity:activity-compose:1.10.1")
113116
implementation("androidx.appcompat:appcompat:1.7.0")
114117
implementation("androidx.constraintlayout:constraintlayout:2.2.1")
115118
implementation("androidx.core:core-ktx:1.16.0")
@@ -120,6 +123,14 @@ dependencies {
120123
implementation("com.google.android.material:material:1.12.0")
121124
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
122125

126+
// Compose
127+
val composeBom = platform("androidx.compose:compose-bom:2025.04.01")
128+
implementation(composeBom)
129+
androidTestImplementation(composeBom)
130+
implementation("androidx.compose.material3:material3")
131+
implementation("androidx.compose.ui:ui-tooling-preview")
132+
debugImplementation("androidx.compose.ui:ui-tooling")
133+
123134
// Third-party
124135
implementation("com.journeyapps:zxing-android-embedded:4.3.0@aar")
125136
implementation("com.github.yalantis:ucrop:2.2.10")

app/src/main/java/protect/card_locker/AboutActivity.kt

Lines changed: 127 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -2,119 +2,151 @@ package protect.card_locker
22

33
import android.os.Bundle
44
import android.text.Spanned
5-
import android.view.MenuItem
6-
import android.view.View
75
import android.widget.ScrollView
86
import android.widget.TextView
9-
10-
import androidx.annotation.StringRes
11-
import androidx.core.view.isVisible
7+
import androidx.activity.ComponentActivity
8+
import androidx.activity.compose.setContent
9+
import androidx.compose.foundation.layout.Column
10+
import androidx.compose.foundation.layout.padding
11+
import androidx.compose.foundation.rememberScrollState
12+
import androidx.compose.foundation.verticalScroll
13+
import androidx.compose.material3.ExperimentalMaterial3Api
14+
15+
import androidx.compose.material3.MaterialTheme
16+
import androidx.compose.material3.Scaffold
17+
import androidx.compose.ui.Modifier
18+
import androidx.compose.ui.res.stringResource
1219

1320
import com.google.android.material.dialog.MaterialAlertDialogBuilder
21+
import protect.card_locker.compose.CatimaAboutSection
22+
import protect.card_locker.compose.CatimaTopAppBar
23+
import protect.card_locker.compose.theme.CatimaTheme
1424

15-
import protect.card_locker.databinding.AboutActivityBinding
1625

17-
class AboutActivity : CatimaAppCompatActivity() {
26+
class AboutActivity : ComponentActivity() {
1827
private companion object {
1928
private const val TAG = "Catima"
2029
}
2130

22-
private lateinit var binding: AboutActivityBinding
2331
private lateinit var content: AboutContent
2432

33+
@OptIn(ExperimentalMaterial3Api::class)
2534
override fun onCreate(savedInstanceState: Bundle?) {
2635
super.onCreate(savedInstanceState)
27-
binding = AboutActivityBinding.inflate(layoutInflater)
2836
content = AboutContent(this)
2937
title = content.pageTitle
30-
setContentView(binding.root)
31-
setSupportActionBar(binding.toolbar)
32-
enableToolbarBackButton()
33-
34-
binding.apply {
35-
creditsSub.text = content.copyrightShort
36-
versionHistorySub.text = content.versionHistory
37-
38-
versionHistory.tag = "https://catima.app/changelog/"
39-
translate.tag = "https://hosted.weblate.org/engage/catima/"
40-
license.tag = "https://github.com/CatimaLoyalty/Android/blob/main/LICENSE"
41-
repo.tag = "https://github.com/CatimaLoyalty/Android/"
42-
privacy.tag = "https://catima.app/privacy-policy/"
43-
reportError.tag = "https://github.com/CatimaLoyalty/Android/issues"
44-
rate.tag = "https://play.google.com/store/apps/details?id=me.hackerchick.catima"
45-
donate.tag = "https://catima.app/donate"
46-
47-
// Hide Google Play rate button if not on Google Play
48-
rate.isVisible = BuildConfig.showRateOnGooglePlay
49-
// Hide donate button on Google Play (Google Play doesn't allow donation links)
50-
donate.isVisible = BuildConfig.showDonate
51-
}
52-
53-
bindClickListeners()
54-
}
5538

56-
override fun onOptionsItemSelected(item: MenuItem): Boolean {
57-
return when (item.itemId) {
58-
android.R.id.home -> {
59-
finish()
60-
true
39+
setContent {
40+
CatimaTheme {
41+
Scaffold(
42+
topBar = { CatimaTopAppBar(title.toString(), onBackPressedDispatcher) }
43+
) { innerPadding ->
44+
Column(modifier = Modifier.padding(innerPadding).verticalScroll(rememberScrollState())) {
45+
CatimaAboutSection(
46+
stringResource(R.string.version_history),
47+
content.versionHistory,
48+
{
49+
showHTML(
50+
stringResource(R.string.version_history),
51+
content.historyInfo,
52+
this as ComponentActivity,
53+
"https://catima.app/changelog/"
54+
)
55+
}
56+
)
57+
CatimaAboutSection(
58+
stringResource(R.string.credits),
59+
content.copyrightShort,
60+
{
61+
showHTML(
62+
stringResource(R.string.credits),
63+
content.contributorInfo,
64+
this as ComponentActivity,
65+
null
66+
)
67+
}
68+
)
69+
CatimaAboutSection(
70+
stringResource(R.string.help_translate_this_app),
71+
stringResource(R.string.translate_platform),
72+
{
73+
OpenWebLinkHandler().openBrowser(
74+
this as ComponentActivity?,
75+
"https://hosted.weblate.org/engage/catima/"
76+
)
77+
}
78+
)
79+
CatimaAboutSection(
80+
stringResource(R.string.license),
81+
stringResource(R.string.app_license),
82+
{
83+
showHTML(
84+
stringResource(R.string.license),
85+
content.licenseInfo,
86+
this as ComponentActivity,
87+
"https://github.com/CatimaLoyalty/Android/blob/main/LICENSE"
88+
)
89+
}
90+
)
91+
CatimaAboutSection(
92+
stringResource(R.string.source_repository),
93+
stringResource(R.string.on_github),
94+
{
95+
OpenWebLinkHandler().openBrowser(
96+
this as ComponentActivity?,
97+
"https://github.com/CatimaLoyalty/Android/"
98+
)
99+
}
100+
)
101+
CatimaAboutSection(
102+
stringResource(R.string.privacy_policy),
103+
stringResource(R.string.and_data_usage),
104+
{
105+
showHTML(
106+
stringResource(R.string.privacy_policy),
107+
content.privacyInfo,
108+
this as ComponentActivity,
109+
"https://catima.app/privacy-policy/"
110+
)
111+
}
112+
)
113+
CatimaAboutSection(
114+
stringResource(R.string.donate),
115+
"",
116+
{
117+
OpenWebLinkHandler().openBrowser(
118+
this as ComponentActivity?,
119+
"https://catima.app/donate"
120+
)
121+
}
122+
)
123+
CatimaAboutSection(
124+
stringResource(R.string.rate_this_app),
125+
stringResource(R.string.on_google_play),
126+
{
127+
OpenWebLinkHandler().openBrowser(
128+
this as ComponentActivity?,
129+
"https://play.google.com/store/apps/details?id=me.hackerchick.catima"
130+
)
131+
}
132+
)
133+
CatimaAboutSection(
134+
stringResource(R.string.report_error),
135+
stringResource(R.string.on_github),
136+
{
137+
OpenWebLinkHandler().openBrowser(
138+
this as ComponentActivity?,
139+
"https://github.com/CatimaLoyalty/Android/issues"
140+
)
141+
}
142+
)
143+
}
144+
}
61145
}
62-
63-
else -> super.onOptionsItemSelected(item)
64146
}
65147
}
66148

67-
override fun onDestroy() {
68-
super.onDestroy()
69-
content.destroy()
70-
clearClickListeners()
71-
}
72-
73-
private fun bindClickListeners() {
74-
binding.apply {
75-
versionHistory.setOnClickListener { showHistory(it) }
76-
translate.setOnClickListener { openExternalBrowser(it) }
77-
license.setOnClickListener { showLicense(it) }
78-
repo.setOnClickListener { openExternalBrowser(it) }
79-
privacy.setOnClickListener { showPrivacy(it) }
80-
reportError.setOnClickListener { openExternalBrowser(it) }
81-
rate.setOnClickListener { openExternalBrowser(it) }
82-
donate.setOnClickListener { openExternalBrowser(it) }
83-
credits.setOnClickListener { showCredits() }
84-
}
85-
}
86-
87-
private fun clearClickListeners() {
88-
binding.apply {
89-
versionHistory.setOnClickListener(null)
90-
translate.setOnClickListener(null)
91-
license.setOnClickListener(null)
92-
repo.setOnClickListener(null)
93-
privacy.setOnClickListener(null)
94-
reportError.setOnClickListener(null)
95-
rate.setOnClickListener(null)
96-
donate.setOnClickListener(null)
97-
credits.setOnClickListener(null)
98-
}
99-
}
100-
101-
private fun showCredits() {
102-
showHTML(R.string.credits, content.contributorInfo, null)
103-
}
104-
105-
private fun showHistory(view: View) {
106-
showHTML(R.string.version_history, content.historyInfo, view)
107-
}
108-
109-
private fun showLicense(view: View) {
110-
showHTML(R.string.license, content.licenseInfo, view)
111-
}
112-
113-
private fun showPrivacy(view: View) {
114-
showHTML(R.string.privacy_policy, content.privacyInfo, view)
115-
}
116-
117-
private fun showHTML(@StringRes title: Int, text: Spanned, view: View?) {
149+
private fun showHTML(title: String, text: Spanned, activity: ComponentActivity, url: String?) {
118150
val dialogContentPadding = resources.getDimensionPixelSize(R.dimen.alert_dialog_content_padding)
119151
val textView = TextView(this).apply {
120152
setText(text)
@@ -131,19 +163,12 @@ class AboutActivity : CatimaAppCompatActivity() {
131163
setView(scrollView)
132164
setPositiveButton(R.string.ok, null)
133165

134-
// Add View online button if an URL is linked to this view
135-
view?.tag?.let {
136-
setNeutralButton(R.string.view_online) { _, _ -> openExternalBrowser(view) }
166+
// Add View online button if an URL is given
167+
url?.let {
168+
setNeutralButton(R.string.view_online) { _, _ -> OpenWebLinkHandler().openBrowser(activity, url) }
137169
}
138170

139171
show()
140172
}
141173
}
142-
143-
private fun openExternalBrowser(view: View) {
144-
val tag = view.tag
145-
if (tag is String && tag.startsWith("https://")) {
146-
OpenWebLinkHandler().openBrowser(this, tag)
147-
}
148-
}
149174
}

app/src/main/java/protect/card_locker/OpenWebLinkHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
import android.util.Log;
77
import android.widget.Toast;
88

9+
import androidx.activity.ComponentActivity;
910
import androidx.appcompat.app.AppCompatActivity;
1011

1112
public class OpenWebLinkHandler {
1213

1314
private static final String TAG = "Catima";
1415

15-
public void openBrowser(AppCompatActivity activity, String url) {
16+
public void openBrowser(ComponentActivity activity, String url) {
1617
if (url == null) {
1718
return;
1819
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package protect.card_locker.compose
2+
3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.Row
6+
import androidx.compose.foundation.layout.padding
7+
import androidx.compose.material3.MaterialTheme
8+
import androidx.compose.material3.Text
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.ui.Alignment
11+
import androidx.compose.ui.Modifier
12+
import androidx.compose.ui.unit.dp
13+
14+
@Composable
15+
fun CatimaAboutSection(title: String, message: String, onClick: () -> Unit) {
16+
Column(
17+
modifier = Modifier
18+
.padding(8.dp)
19+
.clickable(onClick = onClick)
20+
) {
21+
Row {
22+
Column(modifier = Modifier.weight(1F)) {
23+
Text(
24+
text = title,
25+
style = MaterialTheme.typography.titleLarge
26+
)
27+
Text(text = message)
28+
}
29+
Text(modifier = Modifier.align(Alignment.CenterVertically),
30+
text = ">",
31+
style = MaterialTheme.typography.titleMedium
32+
)
33+
}
34+
}
35+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package protect.card_locker.compose
2+
3+
import androidx.activity.OnBackPressedDispatcher
4+
import androidx.compose.material.icons.Icons
5+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
6+
import androidx.compose.material3.ExperimentalMaterial3Api
7+
import androidx.compose.material3.Icon
8+
import androidx.compose.material3.IconButton
9+
import androidx.compose.material3.Text
10+
import androidx.compose.material3.TopAppBar
11+
import androidx.compose.runtime.Composable
12+
import androidx.compose.ui.res.stringResource
13+
import protect.card_locker.R
14+
15+
@OptIn(ExperimentalMaterial3Api::class)
16+
@Composable
17+
fun CatimaTopAppBar(title: String, onBackPressedDispatcher: OnBackPressedDispatcher?) {
18+
TopAppBar(
19+
title = {
20+
Text(text = title)
21+
},
22+
navigationIcon = { if (onBackPressedDispatcher != null) {
23+
IconButton(onClick = { onBackPressedDispatcher.onBackPressed() }) {
24+
Icon(
25+
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
26+
contentDescription = stringResource(R.string.back)
27+
)
28+
}
29+
} else null }
30+
)
31+
}

0 commit comments

Comments
 (0)