Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ libxposed
.cxx
/out
/.idea
# Output of the Eclipse/JDT language server, which several modules trigger
bin/
3 changes: 2 additions & 1 deletion manager/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@

<activity
android:name=".ui.activity.MainActivity"
android:exported="true">
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand Down
2 changes: 2 additions & 0 deletions manager/src/main/java/org/lsposed/lspatch/Patcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ object Patcher {
.usesCleartextTraffic(if (usesCleartextTraffic) true else null)
.permissions(addedPermissions)
.injectDocumentsProvider(injectDocumentsProvider)
.gmsReplacementPackage(gmsReplacementPackage)
.declareFakeSignature(declareFakeSignature)
.build()
)
.keystore(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ data class PatchRequest(
// Inject a DocumentsProvider exposing the app's private data. Recorded in the config for the same
// reason as the permissions above.
val injectDocumentsProvider: Boolean = false,
// The replacement to redirect Google Play services to, or null to leave it alone. A package name
// rather than a flag because the patch bakes that name into the manifest. Recorded for the same reason.
val gmsReplacementPackage: String? = null,
// Declare the original signature as fake-signature for ROM signature spoofing. Recorded for the same reason.
val declareFakeSignature: Boolean = false,
val origin: PatchOrigin = PatchOrigin.New,
) {
val packageName: String get() = target.packageName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ object PatchReport {
"Added perms ${if (request.addedPermissions.isEmpty()) "none" else request.addedPermissions.joinToString(", ")}"
)
add("Docs provider ${request.injectDocumentsProvider}")
add("GMS target ${request.gmsReplacementPackage ?: "none"}")
add("Fake sig ${request.declareFakeSignature}")
add("Keystore ${if (MyKeyStore.useDefault) "built-in" else "custom (${MyKeyStore.file.name})"}")
add("Verbose ${Configs.detailPatchLogs}")
add("")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.lsposed.lspatch.ui.component

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import org.matrix.vector.ui.LocalDialogLocalizer

/**
* The body of a modal bottom sheet.
*
* Three things every sheet needs and none of them got by default, kept in one place so the next sheet does not
* have to remember them:
*
* - **The reader's language.** A sheet is its own window, and a new window takes a fresh set of Android
* composition locals from that window's context, dropping the in-app language override on the way in.
* - **Room for the keyboard.** A sheet is laid out against the window, not against the inset, so a text field in
* one sits under the keyboard the moment it is focused -- along with whatever the field was going to say about
* what was typed.
* - **Somewhere to scroll.** A sheet tall enough to need it, or shortened by the keyboard to need it, otherwise
* just loses its lower half with no way to reach it.
*
* Not for a sheet whose content scrolls itself: nesting a scrollable in another of the same direction is an
* error, so such a sheet applies [androidx.compose.foundation.layout.imePadding] on its own.
*/
@Composable
fun SheetBody(content: @Composable ColumnScope.() -> Unit) {
LocalDialogLocalizer.current {
Column(
Modifier.imePadding().verticalScroll(rememberScrollState()).navigationBarsPadding(),
content = content,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package org.lsposed.lspatch.ui.component.settings

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.CheckCircle
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp

/**
* One choice on a settings sheet, as a selectable card that carries its own explanation.
*
* Shared by every sheet that offers a small set of alternatives, so they read alike and a reader who has
* learned one has learned them all.
*/
@Composable
fun ChoiceCard(
selected: Boolean,
icon: ImageVector,
title: String,
subtitle: String,
onClick: () -> Unit,
role: Role = Role.RadioButton,
) {
val colors = MaterialTheme.colorScheme
Row(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(18.dp))
.background(if (selected) colors.primaryContainer else colors.surfaceContainerHigh)
.selectable(selected = selected, role = role, onClick = onClick)
.padding(horizontal = 16.dp, vertical = 14.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
icon,
contentDescription = null,
tint = if (selected) colors.primary else colors.onSurfaceVariant,
modifier = Modifier.size(24.dp),
)
Spacer(Modifier.width(14.dp))
Column(Modifier.weight(1f)) {
Text(
text = title,
style = MaterialTheme.typography.titleSmall,
fontWeight = FontWeight.SemiBold,
color = if (selected) colors.onPrimaryContainer else colors.onSurface,
)
Text(
text = subtitle,
style = MaterialTheme.typography.bodySmall,
color = if (selected) colors.onPrimaryContainer.copy(alpha = 0.8f)
else colors.onSurfaceVariant,
)
}
if (selected) {
Spacer(Modifier.width(10.dp))
Icon(
Icons.Rounded.CheckCircle,
contentDescription = null,
tint = colors.primary,
modifier = Modifier.size(20.dp),
)
}
}
}
Loading
Loading