Skip to content

Commit d14f5c8

Browse files
WIP
1 parent 775b55f commit d14f5c8

File tree

10 files changed

+331
-581
lines changed

10 files changed

+331
-581
lines changed

app/build.gradle.kts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import com.android.build.gradle.internal.tasks.factory.dependsOn
33
plugins {
44
id("com.android.application")
55
id("org.jetbrains.kotlin.android")
6+
id("org.jetbrains.kotlin.plugin.compose") version "2.1.21"
67
}
78

89
kotlin {
@@ -46,6 +47,7 @@ android {
4647

4748
buildFeatures {
4849
buildConfig = true
50+
compose = true
4951
viewBinding = true
5052
}
5153

@@ -109,6 +111,7 @@ android {
109111

110112
dependencies {
111113
// AndroidX
114+
implementation("androidx.activity:activity-compose:1.10.1")
112115
implementation("androidx.appcompat:appcompat:1.7.0")
113116
implementation("androidx.constraintlayout:constraintlayout:2.2.1")
114117
implementation("androidx.core:core-ktx:1.16.0")
@@ -119,6 +122,15 @@ dependencies {
119122
implementation("com.google.android.material:material:1.12.0")
120123
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
121124

125+
// Compose
126+
val composeBom = platform("androidx.compose:compose-bom:2025.05.01")
127+
implementation(composeBom)
128+
testImplementation(composeBom)
129+
androidTestImplementation(composeBom)
130+
implementation("androidx.compose.foundation:foundation")
131+
implementation("androidx.compose.material3:material3")
132+
implementation("androidx.compose.ui:ui-tooling-preview-android")
133+
122134
// Third-party
123135
implementation("com.journeyapps:zxing-android-embedded:4.3.0@aar")
124136
implementation("com.github.yalantis:ucrop:2.2.10")
Lines changed: 136 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,149 +1,155 @@
11
package protect.card_locker
22

33
import android.os.Bundle
4-
import android.text.Spanned
5-
import android.view.MenuItem
6-
import android.view.View
7-
import android.widget.ScrollView
8-
import android.widget.TextView
9-
10-
import androidx.annotation.StringRes
11-
import androidx.core.view.isVisible
12-
13-
import com.google.android.material.dialog.MaterialAlertDialogBuilder
14-
15-
import protect.card_locker.databinding.AboutActivityBinding
16-
17-
class AboutActivity : CatimaAppCompatActivity() {
18-
private companion object {
19-
private const val TAG = "Catima"
20-
}
21-
22-
private lateinit var binding: AboutActivityBinding
4+
import androidx.activity.ComponentActivity
5+
import androidx.activity.compose.setContent
6+
import androidx.compose.foundation.layout.Column
7+
import androidx.compose.foundation.layout.padding
8+
import androidx.compose.foundation.rememberScrollState
9+
import androidx.compose.foundation.verticalScroll
10+
import androidx.compose.material3.ExperimentalMaterial3Api
11+
import androidx.compose.material3.MaterialTheme
12+
13+
import androidx.compose.material3.Scaffold
14+
import androidx.compose.runtime.Composable
15+
import androidx.compose.ui.Modifier
16+
import androidx.compose.ui.res.stringResource
17+
import androidx.compose.ui.text.AnnotatedString
18+
import androidx.compose.ui.text.SpanStyle
19+
import androidx.compose.ui.text.TextLinkStyles
20+
import androidx.compose.ui.text.fromHtml
21+
import androidx.compose.ui.text.style.TextDecoration
22+
import androidx.compose.ui.tooling.preview.Preview
23+
24+
import protect.card_locker.compose.CatimaAboutSection
25+
import protect.card_locker.compose.CatimaTopAppBar
26+
import protect.card_locker.compose.theme.CatimaTheme
27+
28+
29+
class AboutActivity : ComponentActivity() {
2330
private lateinit var content: AboutContent
2431

32+
@OptIn(ExperimentalMaterial3Api::class)
2533
override fun onCreate(savedInstanceState: Bundle?) {
2634
super.onCreate(savedInstanceState)
27-
binding = AboutActivityBinding.inflate(layoutInflater)
2835
content = AboutContent(this)
2936
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"
4637

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
38+
setContent {
39+
ScreenContent(
40+
showDonate = BuildConfig.showDonate,
41+
showRateOnGooglePlay = BuildConfig.showRateOnGooglePlay
42+
)
5143
}
52-
53-
bindClickListeners()
5444
}
5545

56-
override fun onOptionsItemSelected(item: MenuItem): Boolean {
57-
return when (item.itemId) {
58-
android.R.id.home -> {
59-
finish()
60-
true
46+
@Composable
47+
fun ScreenContent(
48+
showDonate: Boolean,
49+
showRateOnGooglePlay: Boolean
50+
) {
51+
CatimaTheme {
52+
Scaffold(
53+
topBar = { CatimaTopAppBar(title.toString(), onBackPressedDispatcher) }
54+
) { innerPadding ->
55+
Column(
56+
modifier = Modifier.padding(innerPadding).verticalScroll(rememberScrollState())
57+
) {
58+
CatimaAboutSection(
59+
stringResource(R.string.version_history),
60+
content.versionHistory,
61+
onClickUrl = "https://catima.app/changelog/",
62+
onClickDialogText = AnnotatedString.fromHtml(
63+
htmlString = content.historyHtml,
64+
linkStyles = TextLinkStyles(
65+
style = SpanStyle(
66+
textDecoration = TextDecoration.Underline,
67+
color = MaterialTheme.colorScheme.primary
68+
)
69+
)
70+
)
71+
)
72+
CatimaAboutSection(
73+
stringResource(R.string.credits),
74+
content.copyrightShort,
75+
onClickDialogText = AnnotatedString.fromHtml(
76+
htmlString = content.contributorInfoHtml,
77+
linkStyles = TextLinkStyles(
78+
style = SpanStyle(
79+
textDecoration = TextDecoration.Underline,
80+
color = MaterialTheme.colorScheme.primary
81+
)
82+
)
83+
)
84+
)
85+
CatimaAboutSection(
86+
stringResource(R.string.help_translate_this_app),
87+
stringResource(R.string.translate_platform),
88+
onClickUrl = "https://hosted.weblate.org/engage/catima/"
89+
)
90+
CatimaAboutSection(
91+
stringResource(R.string.license),
92+
stringResource(R.string.app_license),
93+
onClickUrl = "https://github.com/CatimaLoyalty/Android/blob/main/LICENSE",
94+
onClickDialogText = AnnotatedString.fromHtml(
95+
htmlString = content.licenseHtml,
96+
linkStyles = TextLinkStyles(
97+
style = SpanStyle(
98+
textDecoration = TextDecoration.Underline,
99+
color = MaterialTheme.colorScheme.primary
100+
)
101+
)
102+
)
103+
)
104+
CatimaAboutSection(
105+
stringResource(R.string.source_repository),
106+
stringResource(R.string.on_github),
107+
onClickUrl = "https://github.com/CatimaLoyalty/Android/"
108+
)
109+
CatimaAboutSection(
110+
stringResource(R.string.privacy_policy),
111+
stringResource(R.string.and_data_usage),
112+
onClickUrl = "https://catima.app/privacy-policy/",
113+
onClickDialogText = AnnotatedString.fromHtml(
114+
htmlString = content.privacyHtml,
115+
linkStyles = TextLinkStyles(
116+
style = SpanStyle(
117+
textDecoration = TextDecoration.Underline,
118+
color = MaterialTheme.colorScheme.primary
119+
)
120+
)
121+
)
122+
)
123+
if (showDonate) {
124+
CatimaAboutSection(
125+
stringResource(R.string.donate),
126+
"",
127+
onClickUrl = "https://catima.app/donate"
128+
)
129+
}
130+
if (showRateOnGooglePlay) {
131+
CatimaAboutSection(
132+
stringResource(R.string.rate_this_app),
133+
stringResource(R.string.on_google_play),
134+
onClickUrl = "https://play.google.com/store/apps/details?id=me.hackerchick.catima"
135+
)
136+
}
137+
CatimaAboutSection(
138+
stringResource(R.string.report_error),
139+
stringResource(R.string.on_github),
140+
onClickUrl = "https://github.com/CatimaLoyalty/Android/issues"
141+
)
142+
}
61143
}
62-
63-
else -> super.onOptionsItemSelected(item)
64144
}
65145
}
66146

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?) {
118-
val dialogContentPadding = resources.getDimensionPixelSize(R.dimen.alert_dialog_content_padding)
119-
val textView = TextView(this).apply {
120-
setText(text)
121-
Utils.makeTextViewLinksClickable(this, text)
122-
}
123-
124-
val scrollView = ScrollView(this).apply {
125-
addView(textView)
126-
setPadding(dialogContentPadding, dialogContentPadding / 2, dialogContentPadding, 0)
127-
}
128-
129-
MaterialAlertDialogBuilder(this).apply {
130-
setTitle(title)
131-
setView(scrollView)
132-
setPositiveButton(R.string.ok, null)
133-
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) }
137-
}
138-
139-
show()
140-
}
141-
}
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-
}
147+
@Preview
148+
@Composable
149+
fun AboutActivityPreview() {
150+
ScreenContent(
151+
showDonate = true,
152+
showRateOnGooglePlay = true
153+
)
148154
}
149155
}

0 commit comments

Comments
 (0)