Skip to content

Commit 1a3d213

Browse files
committed
Add Jetpack Compose support and refactor MainActivity: integrate Compose dependencies, enable build features, and replace XML layout with a Compose UI implementation. Update AndroidManifest and remove obsolete layout file.
1 parent ca1b3e8 commit 1a3d213

File tree

11 files changed

+328
-269
lines changed

11 files changed

+328
-269
lines changed

app/build.gradle.kts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
plugins {
22
alias(libs.plugins.android.application)
33
alias(libs.plugins.kotlin.android)
4+
alias(libs.plugins.kotlin.compose)
45
id("dev.vyp.stringcare.plugin")
56
}
67

@@ -54,6 +55,14 @@ android {
5455
jvmTarget = "17"
5556
}
5657

58+
buildFeatures {
59+
compose = true
60+
}
61+
62+
androidResources {
63+
noCompress += "json"
64+
}
65+
5766
packaging {
5867
resources {
5968
excludes += "/META-INF/{AL2.0,LGPL2.1}"
@@ -67,6 +76,15 @@ dependencies {
6776
exclude(group = "com.android.support", module = "support-annotations")
6877
}
6978
implementation(libs.androidx.appcompat)
79+
implementation(libs.androidx.core)
80+
implementation(libs.androidx.lifecycle.runtime.ktx)
81+
implementation(libs.androidx.activity.compose)
82+
implementation(platform(libs.androidx.compose.bom))
83+
implementation(libs.androidx.compose.ui)
84+
implementation(libs.androidx.compose.ui.graphics)
85+
implementation(libs.androidx.compose.ui.tooling.preview)
86+
implementation(libs.androidx.compose.material3)
87+
debugImplementation("androidx.compose.ui:ui-tooling")
7088
testImplementation("junit:junit:4.13.2")
7189
implementation("org.jetbrains.kotlin:kotlin-stdlib:${libs.versions.kotlin.get()}")
7290
implementation("commons-io:commons-io:2.15.1")

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3-
package="com.efraespada.stringobfuscator">
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
43

54
<application
5+
android:name=".StringCareApp"
66
android:allowBackup="true"
77
android:icon="@mipmap/ic_launcher"
88
android:roundIcon="@mipmap/ic_launcher_round"
Lines changed: 239 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,252 @@
11
package com.efraespada.stringobfuscator
22

33
import android.os.Bundle
4-
import android.view.View
5-
import android.widget.TextView
6-
import androidx.appcompat.app.AppCompatActivity
7-
import dev.vyp.stringcare.library.*
8-
import dev.vyp.stringcare.library.SC.Companion.init
9-
import dev.vyp.stringcare.library.SC.Companion.reveal
10-
11-
class MainActivity : AppCompatActivity() {
4+
import android.view.LayoutInflater
5+
import androidx.activity.ComponentActivity
6+
import androidx.activity.compose.setContent
7+
import androidx.activity.enableEdgeToEdge
8+
import androidx.compose.foundation.layout.Arrangement
9+
import androidx.compose.foundation.layout.Column
10+
import androidx.compose.foundation.layout.Row
11+
import androidx.compose.foundation.layout.fillMaxSize
12+
import androidx.compose.foundation.layout.fillMaxWidth
13+
import androidx.compose.foundation.layout.padding
14+
import androidx.compose.foundation.rememberScrollState
15+
import androidx.compose.foundation.verticalScroll
16+
import androidx.compose.material3.Card
17+
import androidx.compose.material3.CardDefaults
18+
import androidx.compose.material3.HorizontalDivider
19+
import androidx.compose.material3.MaterialTheme
20+
import androidx.compose.material3.Scaffold
21+
import androidx.compose.material3.Text
22+
import androidx.compose.material3.TextButton
23+
import androidx.compose.runtime.Composable
24+
import androidx.compose.runtime.mutableStateOf
25+
import androidx.compose.runtime.remember
26+
import androidx.compose.ui.Modifier
27+
import androidx.compose.ui.graphics.Color
28+
import androidx.compose.ui.platform.LocalContext
29+
import androidx.compose.ui.text.font.FontWeight
30+
import androidx.compose.ui.unit.dp
31+
import androidx.compose.ui.viewinterop.AndroidView
32+
import com.efraespada.stringobfuscator.ui.theme.StringObfuscatorSampleTheme
33+
import dev.vyp.stringcare.library.SCTextView
34+
import dev.vyp.stringcare.library.Version
35+
import dev.vyp.stringcare.library.bytes
36+
import dev.vyp.stringcare.library.json
37+
import dev.vyp.stringcare.library.jsonArray
38+
import dev.vyp.stringcare.library.reveal
39+
40+
class MainActivity : ComponentActivity() {
1241
override fun onCreate(savedInstanceState: Bundle?) {
1342
super.onCreate(savedInstanceState)
14-
setContentView(R.layout.activity_main)
15-
init(applicationContext)
16-
val password = getString(R.string.snake_msg_hidden)
17-
val original = reveal(password, Version.V3)
18-
val message = "Snake, the password is $password$original"
19-
(findViewById<View>(R.id.programmatically_obfuscation) as TextView).text = message
20-
val numbers =
21-
getString(R.string.pattern, "hi", 3) + " is " + reveal(R.string.pattern, "hi", 3)
22-
(findViewById<View>(R.id.pattern) as TextView).text = numbers
23-
val tvAuto = findViewById<SCTextView>(R.id.auto_tv)
24-
findViewById<View>(R.id.btn_change).setOnClickListener { v: View? ->
25-
if (tvAuto.isHtmlEnabled) {
26-
tvAuto.setHtmlSupport(!tvAuto.isHtmlEnabled)
27-
} else if (tvAuto.isRevealingValue) {
28-
tvAuto.setRevealed(!tvAuto.isRevealingValue)
29-
} else if (!tvAuto.isRevealingValue) {
30-
tvAuto.setRevealed(!tvAuto.isRevealingValue)
31-
tvAuto.setHtmlSupport(!tvAuto.isHtmlEnabled)
43+
enableEdgeToEdge()
44+
setContent {
45+
StringObfuscatorSampleTheme {
46+
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
47+
StringCareSampleScreen(
48+
modifier =
49+
Modifier
50+
.fillMaxSize()
51+
.padding(innerPadding),
52+
)
53+
}
3254
}
3355
}
34-
val equals = reveal(R.string.hello_world_b) == getString(R.string.hello_world_a)
35-
val areEquals = "Same result: $equals"
36-
(findViewById<View>(R.id.same_value) as TextView).text = areEquals
37-
val jsonObjectName = R.string.asset_json_file.reveal()
56+
}
57+
}
3858

59+
@Composable
60+
private fun StringCareSampleScreen(modifier: Modifier = Modifier) {
61+
val context = LocalContext.current
3962

40-
findViewById<TextView>(R.id.json_object).text = jsonObjectName.json().toString()
41-
findViewById<TextView>(R.id.json_object_original).text =
42-
String(jsonObjectName.bytes { false })
63+
val snakePassword = remember { context.getString(R.string.snake_msg_hidden) }
64+
val snakeOriginal = remember {
65+
runCatching { dev.vyp.stringcare.library.SC.reveal(snakePassword, Version.V3) }
66+
.getOrDefault("error")
67+
}
68+
val programmaticMessage =
69+
remember {
70+
"Snake, the password is $snakePassword$snakeOriginal"
71+
}
4372

73+
val patternDemo =
74+
remember {
75+
context.getString(R.string.pattern, "hi", 3) +
76+
" is " +
77+
runCatching { R.string.pattern.reveal("hi", 3) }.getOrDefault("error")
78+
}
4479

45-
val jsonArrayName = R.string.asset_json_raw_file.reveal()
46-
findViewById<TextView>(R.id.json_array).text = jsonArrayName.jsonArray().toString()
47-
findViewById<TextView>(R.id.json_array_original).text =
48-
jsonArrayName.bytes { false }.toString()
80+
val sameHello =
81+
remember {
82+
runCatching { R.string.hello_world_b.reveal() == context.getString(R.string.hello_world_a) }
83+
.getOrDefault(false)
84+
}
85+
86+
val jsonObjectPath = remember { runCatching { R.string.asset_json_file.reveal() }.getOrDefault("") }
87+
val jsonObjectPretty =
88+
remember(jsonObjectPath) {
89+
runCatching { jsonObjectPath.json().toString(2) }.getOrDefault("error")
90+
}
91+
val jsonObjectRaw =
92+
remember(jsonObjectPath) {
93+
runCatching { String(jsonObjectPath.bytes { false }) }.getOrDefault("error")
94+
}
95+
96+
val jsonArrayPath =
97+
remember { runCatching { R.string.asset_json_raw_file.reveal() }.getOrDefault("") }
98+
val jsonArrayPretty =
99+
remember(jsonArrayPath) {
100+
runCatching { jsonArrayPath.jsonArray().toString(2) }.getOrDefault("error")
101+
}
102+
val jsonArrayRaw =
103+
remember(jsonArrayPath) {
104+
runCatching { jsonArrayPath.bytes { false }.toString() }.getOrDefault("error")
105+
}
106+
107+
val helloTvHolder = remember { mutableStateOf<SCTextView?>(null) }
108+
109+
Column(
110+
modifier =
111+
modifier
112+
.verticalScroll(rememberScrollState())
113+
.padding(16.dp),
114+
verticalArrangement = Arrangement.spacedBy(12.dp),
115+
) {
116+
Text(
117+
text = context.getString(R.string.app_name),
118+
style = MaterialTheme.typography.headlineSmall,
119+
fontWeight = FontWeight.Bold,
120+
)
121+
Text(
122+
text = "StringCare sample (Compose): reveals, patterns, assets, and SCTextView.",
123+
style = MaterialTheme.typography.bodyMedium,
124+
)
125+
126+
DemoCard(title = context.getString(R.string.html_treatment), color = Color(0xFFE3F2FD)) {
127+
AndroidView(
128+
modifier = Modifier.fillMaxWidth(),
129+
factory = { ctx ->
130+
LayoutInflater.from(ctx).inflate(R.layout.sc_text_hello, null, false) as SCTextView
131+
},
132+
update = { tv -> helloTvHolder.value = tv },
133+
)
134+
TextButton(
135+
onClick = {
136+
val tvAuto = helloTvHolder.value ?: return@TextButton
137+
if (tvAuto.isHtmlEnabled) {
138+
tvAuto.setHtmlSupport(!tvAuto.isHtmlEnabled)
139+
} else if (tvAuto.isRevealingValue) {
140+
tvAuto.setRevealed(!tvAuto.isRevealingValue)
141+
} else if (!tvAuto.isRevealingValue) {
142+
tvAuto.setRevealed(!tvAuto.isRevealingValue)
143+
tvAuto.setHtmlSupport(!tvAuto.isHtmlEnabled)
144+
}
145+
},
146+
modifier = Modifier.fillMaxWidth(),
147+
) {
148+
Text(text = "Change")
149+
}
150+
}
151+
152+
DemoCard(
153+
title = context.getString(R.string.programmatically_obfuscation),
154+
color = Color(0xFFFFF3E0),
155+
) {
156+
DemoRow(label = "Message", value = programmaticMessage)
157+
}
158+
159+
DemoCard(title = context.getString(R.string.patterns), color = Color(0xFFF3E5F5)) {
160+
DemoRow(label = "Pattern demo", value = patternDemo)
161+
}
162+
163+
DemoCard(title = context.getString(R.string.long_new_line_comparison), color = Color(0xFFE8F5E9)) {
164+
DemoRow(label = "Same result", value = sameHello.toString())
165+
HorizontalDivider(Modifier.padding(vertical = 8.dp))
166+
Text(
167+
text = context.getString(R.string.hello_world_a),
168+
style = MaterialTheme.typography.bodySmall,
169+
color = MaterialTheme.colorScheme.onSurfaceVariant,
170+
)
171+
AndroidView(
172+
modifier = Modifier.fillMaxWidth(),
173+
factory = { ctx ->
174+
LayoutInflater.from(ctx).inflate(R.layout.sc_text_hello_world_b, null, false) as SCTextView
175+
},
176+
)
177+
}
178+
179+
DemoCard(title = context.getString(R.string.string_resource_disabling_android_treatment), color = Color(0xFFFFEBEE)) {
180+
AndroidView(
181+
modifier = Modifier.fillMaxWidth(),
182+
factory = { ctx ->
183+
LayoutInflater.from(ctx).inflate(R.layout.sc_text_hello_world_c, null, false) as SCTextView
184+
},
185+
)
186+
}
187+
188+
DemoCard(title = context.getString(R.string.json_object_asset), color = Color(0xFFE0F7FA)) {
189+
DemoRow(label = "Path (revealed)", value = jsonObjectPath)
190+
HorizontalDivider(Modifier.padding(vertical = 6.dp))
191+
DemoRow(label = "JSON", value = jsonObjectPretty)
192+
DemoRow(label = "Raw bytes as String", value = jsonObjectRaw)
193+
}
194+
195+
DemoCard(title = context.getString(R.string.json_array_asset), color = Color(0xFFF1F8E9)) {
196+
DemoRow(label = "Path (revealed)", value = jsonArrayPath)
197+
HorizontalDivider(Modifier.padding(vertical = 6.dp))
198+
DemoRow(label = "JSONArray", value = jsonArrayPretty)
199+
DemoRow(label = "Raw bytes", value = jsonArrayRaw)
200+
}
201+
}
202+
}
203+
204+
@Composable
205+
private fun DemoCard(
206+
title: String,
207+
color: Color,
208+
content: @Composable () -> Unit,
209+
) {
210+
Card(
211+
modifier = Modifier.fillMaxWidth(),
212+
colors = CardDefaults.cardColors(containerColor = color),
213+
) {
214+
Column(
215+
modifier =
216+
Modifier
217+
.fillMaxWidth()
218+
.padding(12.dp),
219+
verticalArrangement = Arrangement.spacedBy(8.dp),
220+
) {
221+
Text(
222+
text = title,
223+
style = MaterialTheme.typography.titleMedium,
224+
fontWeight = FontWeight.SemiBold,
225+
)
226+
content()
227+
}
228+
}
229+
}
49230

231+
@Composable
232+
private fun DemoRow(
233+
label: String,
234+
value: String,
235+
) {
236+
Row(
237+
modifier = Modifier.fillMaxWidth(),
238+
horizontalArrangement = Arrangement.spacedBy(8.dp),
239+
) {
240+
Text(
241+
text = "$label:",
242+
modifier = Modifier.weight(1f),
243+
style = MaterialTheme.typography.bodyMedium,
244+
fontWeight = FontWeight.Medium,
245+
)
246+
Text(
247+
text = value,
248+
modifier = Modifier.weight(2f),
249+
style = MaterialTheme.typography.bodySmall,
250+
)
50251
}
51-
}
252+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.efraespada.stringobfuscator
2+
3+
import android.app.Application
4+
import dev.vyp.stringcare.library.SC
5+
6+
class StringCareApp : Application() {
7+
override fun onCreate() {
8+
super.onCreate()
9+
SC.init { applicationContext }
10+
}
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.efraespada.stringobfuscator.ui.theme
2+
3+
import androidx.compose.material3.MaterialTheme
4+
import androidx.compose.material3.lightColorScheme
5+
import androidx.compose.runtime.Composable
6+
7+
@Composable
8+
fun StringObfuscatorSampleTheme(content: @Composable () -> Unit) {
9+
MaterialTheme(
10+
colorScheme = lightColorScheme(),
11+
content = content,
12+
)
13+
}

0 commit comments

Comments
 (0)