Remove internet permission and add standalone APK notice

This commit is contained in:
Aleksandras Kostarevas 2024-06-01 01:31:44 +03:00
parent f2e42384bd
commit a1e6d414f2
8 changed files with 126 additions and 38 deletions

View File

@ -23,6 +23,11 @@ build:
script:
- gradle bundlePlaystoreRelease -s
- gradle assembleStableRelease -s
- if grep -q "android.permission.INTERNET" build/intermediates/merged_manifests/playstoreRelease/AndroidManifest.xml; then echo "Internet permission check failed for play store"; exit 1; fi
- if grep -q "android.permission.INTERNET" build/intermediates/merged_manifests/stableRelease/AndroidManifest.xml; then echo "Internet permission check failed for stable"; exit 1; fi
- echo "All checks OK"
- echo "Standalone permissions" && grep "uses-permission" build/intermediates/merged_manifests/stableRelease/AndroidManifest.xml
- echo "Play Store permissions" && grep "uses-permission" build/intermediates/merged_manifests/playstoreRelease/AndroidManifest.xml
- mv build/outputs/apk/stable/release/latinime-stable-release.apk ./keyboard-$VERSION_NAME.apk
- mv build/outputs/bundle/playstoreRelease/latinime-playstore-release.aab ./keyboard-playstore-$VERSION_NAME.aab
- touch VERSION_CODE_$VERSION_CODE.txt

View File

@ -220,7 +220,7 @@ dependencies {
implementation 'androidx.datastore:datastore-preferences:1.0.0'
implementation 'androidx.autofill:autofill:1.1.0'
stableImplementation 'ch.acra:acra-http:5.11.1' // TODO: Remove upon release
//stableImplementation 'ch.acra:acra-http:5.11.1' // TODO: Remove upon release
stableImplementation 'ch.acra:acra-mail:5.11.1'
stableImplementation 'ch.acra:acra-dialog:5.11.1'

View File

@ -27,6 +27,7 @@ import org.futo.inputmethod.latin.uix.settings.SettingToggleDataStore
import org.futo.inputmethod.latin.uix.settings.SettingToggleRaw
import org.futo.inputmethod.latin.uix.settings.useDataStore
import org.futo.inputmethod.updates.DISABLE_UPDATE_REMINDER
import org.futo.inputmethod.updates.dismissedMigrateUpdateNotice
val IS_DEVELOPER = SettingsKey(booleanPreferencesKey("isDeveloperMode"), false)
@ -52,6 +53,8 @@ fun DeveloperScreen(navController: NavHostController = rememberNavController())
setting = HiddenKeysSetting
)
SettingToggleDataStore(title = "Dismissed migration notice", setting = dismissedMigrateUpdateNotice)
NavigationItem(
title = "Crash the app",
style = NavigationItemStyle.MiscNoArrow,

View File

@ -30,6 +30,7 @@ import org.futo.inputmethod.latin.uix.settings.NavigationItemStyle
import org.futo.inputmethod.latin.uix.settings.ScreenTitle
import org.futo.inputmethod.latin.uix.settings.useDataStoreValueBlocking
import org.futo.inputmethod.latin.uix.theme.Typography
import org.futo.inputmethod.updates.ConditionalMigrateUpdateNotice
import org.futo.inputmethod.updates.ConditionalUpdate
@Preview(showBackground = true)
@ -51,6 +52,7 @@ fun HomeScreen(navController: NavHostController = rememberNavController()) {
Spacer(modifier = Modifier.height(24.dp))
ScreenTitle("FUTO Keyboard Settings")
ConditionalMigrateUpdateNotice()
ConditionalUpdate(navController)
ConditionalUnpaidNoticeWithNav(navController)
@ -90,15 +92,12 @@ fun HomeScreen(navController: NavHostController = rememberNavController()) {
icon = painterResource(id = R.drawable.eye)
)
UnpaidNoticeCondition(showOnlyIfReminder = true) {
NavigationItem(
title = stringResource(R.string.payment),
style = NavigationItemStyle.HomePrimary,
navigate = { navController.navigate("payment") },
icon = painterResource(R.drawable.dollar_sign)
)
}
NavigationItem(
title = stringResource(R.string.payment),
style = NavigationItemStyle.HomePrimary,
navigate = { navController.navigate("payment") },
icon = painterResource(R.drawable.dollar_sign)
)
NavigationItem(
title = "Help & Feedback",

View File

@ -66,6 +66,7 @@ import org.futo.inputmethod.latin.uix.settings.ScrollableList
import org.futo.inputmethod.latin.uix.settings.useDataStore
import org.futo.inputmethod.latin.uix.settings.useDataStoreValueBlocking
import org.futo.inputmethod.latin.uix.theme.Typography
import org.futo.inputmethod.updates.dismissedMigrateUpdateNotice
import org.futo.inputmethod.updates.openURI
import kotlin.math.absoluteValue
@ -159,7 +160,6 @@ const val TRIAL_PERIOD_DAYS = 30
@Composable
fun UnpaidNoticeCondition(
force: Boolean = LocalInspectionMode.current,
showOnlyIfReminder: Boolean = false,
inner: @Composable () -> Unit
) {
val paymentUrl = useDataStoreValueBlocking(TMP_PAYMENT_URL)
@ -171,19 +171,20 @@ fun UnpaidNoticeCondition(
val pushReminderTime = useDataStoreValueBlocking(NOTICE_REMINDER_TIME)
val currentTime = System.currentTimeMillis() / 1000L
val isDisplayingMigrationNotice = !useDataStoreValueBlocking(dismissedMigrateUpdateNotice)
val reminderTimeIsUp = (currentTime >= pushReminderTime)
val displayCondition = if(showOnlyIfReminder) {
// Either the reminder time is not up, or we're not past the trial period
(!isAlreadyPaid) && ((!reminderTimeIsUp) || (!forceShowNotice && numDaysInstalled.intValue < TRIAL_PERIOD_DAYS))
} else {
val displayCondition =
// The trial period time is over
(forceShowNotice || (numDaysInstalled.intValue >= TRIAL_PERIOD_DAYS))
// and the current time is past the reminder time
&& reminderTimeIsUp
// and we have not already paid
&& (!isAlreadyPaid)
}
// and not overridden by migration notice
&& !isDisplayingMigrationNotice
if (force || displayCondition) {
inner()
}

View File

@ -5,23 +5,42 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.widget.Toast
import androidx.compose.foundation.layout.Box
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.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowForward
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import org.futo.inputmethod.latin.BuildConfig
import org.futo.inputmethod.latin.uix.SettingsKey
import org.futo.inputmethod.latin.uix.getSetting
import org.futo.inputmethod.latin.uix.setSetting
import org.futo.inputmethod.latin.uix.settings.SettingItem
import org.futo.inputmethod.latin.uix.settings.pages.ParagraphText
import org.futo.inputmethod.latin.uix.settings.useDataStore
import org.futo.inputmethod.latin.uix.theme.Typography
val LAST_UPDATE_CHECK_RESULT = stringPreferencesKey("last_update_check_result")
val LAST_UPDATE_CHECK_FAILED = booleanPreferencesKey("last_update_check_failed")
@ -78,7 +97,7 @@ fun Context.openManualUpdateCheck() {
@Composable
@Preview
fun ConditionalUpdate(navController: NavHostController) {
fun ConditionalUpdate(navController: NavHostController = rememberNavController()) {
if(!BuildConfig.UPDATE_CHECKING) return
val (updateInfo, _) = useDataStore(key = LAST_UPDATE_CHECK_RESULT, default = "")
@ -104,8 +123,7 @@ fun ConditionalUpdate(navController: NavHostController) {
}
} else if(lastFailed) {
SettingItem(
title = "Unable to check online for updates",
subtitle = "Please tap to check manually",
title = "Check for updates manually",
onClick = {
context.openManualUpdateCheck()
}
@ -114,3 +132,67 @@ fun ConditionalUpdate(navController: NavHostController) {
}
}
}
val dismissedMigrateUpdateNotice = SettingsKey(
key = booleanPreferencesKey("dismissedMigrateFdroidObtainiumNotice"),
default = BuildConfig.IS_PLAYSTORE_BUILD
)
@Composable
@Preview
fun ConditionalMigrateUpdateNotice() {
val context = LocalContext.current
val value = useDataStore(dismissedMigrateUpdateNotice)
if(!value.value) {
Surface(
color = MaterialTheme.colorScheme.surfaceVariant, modifier = Modifier
.fillMaxWidth()
.padding(24.dp, 8.dp), shape = RoundedCornerShape(24.dp)
) {
Column(modifier = Modifier.padding(8.dp, 0.dp)) {
Spacer(modifier = Modifier.height(8.dp))
Text(
"Use F-Droid or Obtainium",
modifier = Modifier.padding(8.dp),
style = Typography.titleMedium,
color = MaterialTheme.colorScheme.onBackground
)
ParagraphText("The standalone APK has been updated to remove the network permission.")
ParagraphText("As a consequence, it can no longer offer automatic updates.")
ParagraphText("If you are still using the apk, we recommend downloading the app from F-Droid, Obtainium or Play Store so that you receive updates.")
ParagraphText("Visit keyboard.futo.org for download options.")
Row(
modifier = Modifier
.padding(8.dp)
.align(Alignment.CenterHorizontally)
) {
Box(modifier = Modifier.weight(1.0f)) {
Button(onClick = {
context.openURI("https://keyboard.futo.org/#downloads")
}, modifier = Modifier.align(Alignment.Center)) {
Text("Visit")
}
}
Box(modifier = Modifier.weight(1.0f)) {
Button(
onClick = { value.setValue(true) },
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondary,
contentColor = MaterialTheme.colorScheme.onSecondary
), modifier = Modifier.align(Alignment.Center)
) {
Text("Dismiss")
}
}
}
}
}
}
}

View File

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.INTERNET" />
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service

View File

@ -5,11 +5,11 @@ import android.content.Context
import androidx.datastore.preferences.core.Preferences
import org.acra.ACRA
import org.acra.config.dialog
import org.acra.config.httpSender
//import org.acra.config.httpSender
//import org.acra.sender.HttpSender
import org.acra.config.mailSender
import org.acra.data.StringFormat
import org.acra.ktx.initAcra
import org.acra.sender.HttpSender
class CrashLoggingApplication : Application() {
override fun attachBaseContext(base: Context?) {
@ -20,11 +20,11 @@ class CrashLoggingApplication : Application() {
dialog {
text = getString(
if(BuildConfig.ENABLE_ACRA) {
R.string.crashed_text
} else {
//if(BuildConfig.ENABLE_ACRA) {
// R.string.crashed_text
//} else {
R.string.crashed_text_email
}
//}
)
title = getString(R.string.crashed_title)
positiveButtonText = getString(R.string.crash_report_accept)
@ -32,14 +32,15 @@ class CrashLoggingApplication : Application() {
resTheme = android.R.style.Theme_DeviceDefault_Dialog
}
if(BuildConfig.ENABLE_ACRA) {
httpSender {
uri = BuildConfig.ACRA_URL
basicAuthLogin = BuildConfig.ACRA_USER
basicAuthPassword = BuildConfig.ACRA_PASSWORD
httpMethod = HttpSender.Method.POST
}
} else {
//if(BuildConfig.ENABLE_ACRA) {
// httpSender {
// uri = BuildConfig.ACRA_URL
// basicAuthLogin = BuildConfig.ACRA_USER
// basicAuthPassword = BuildConfig.ACRA_PASSWORD
// httpMethod = HttpSender.Method.POST
// }
//} else {
mailSender {
mailTo = "keyboard@futo.org"
reportAsFile = true
@ -48,7 +49,7 @@ class CrashLoggingApplication : Application() {
body =
"I experienced this crash. My version: ${BuildConfig.VERSION_NAME}.\n\n(Enter details here if necessary)"
}
}
//}
}
}