Skip to content

Commit

Permalink
Backup bugfixes + Remove Toasts in data packages
Browse files Browse the repository at this point in the history
  • Loading branch information
Loïc Teyssier committed Jan 23, 2024
1 parent a010e53 commit c950b7b
Show file tree
Hide file tree
Showing 30 changed files with 351 additions and 457 deletions.
18 changes: 3 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

## Target platforms :

API 16 or later
API 23 or later

## Features :

Expand All @@ -31,18 +31,6 @@ API 16 or later

## Donations :

[<img src="https://image.flaticon.com/icons/svg/931/931949.svg?sanitize=true"
[<img src="https://upload.wikimedia.org/wikipedia/commons/7/76/577-beer-mug.svg?sanitize=true"
alt="Beer"
height="20"> Buy me a beer](https://www.paypal.me/loicteyssier/5)

[<img src="https://image.flaticon.com/icons/svg/1404/1404894.svg?sanitize=true"
alt="Beer"
height="20"> Buy me a pizza](https://www.paypal.me/loicteyssier/10)

[<img src="https://image.flaticon.com/icons/svg/2424/2424721.svg?sanitize=true"
alt="Beer"
height="20"> Buy me a meal](https://www.paypal.me/loicteyssier/20)

[<img src="https://image.flaticon.com/icons/svg/535/535183.svg?sanitize=true"
alt="Beer"
height="20"> Buy me whatever you want](https://www.paypal.me/loicteyssier)
height="20"> Buy me a beer](https://www.paypal.com/donate/?business=Z32JPDRAJV2ZQ&no_recurring=0&item_name=1List+App&currency_code=EUR)
30 changes: 9 additions & 21 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ android {
compileSdk 34
minSdkVersion 23
targetSdkVersion 34
versionCode 14
versionName "1.4.1"
versionCode 17
versionName "1.4.0"
vectorDrawables.useSupportLibrary = true
}

Expand All @@ -25,16 +25,16 @@ android {

buildFeatures {
viewBinding true
buildConfig = true
}

signingConfigs {
release {
storeFile file('C:\\Users\\Loic\\Dropbox (Personal)\\.keys\\keystores\\android.jks')
storePassword '7c3c1779c148a6ff3d5ee87e7ef70f81'
keyAlias 'OneListKey'
keyPassword '97220be66f2b279723c09f770ab45089'
storeFile = file(System.getenv("ONELIST_KEYSTORE_PATH"))
storePassword = System.getenv("ONELIST_KEYSTORE_PASSWORD")
keyAlias = System.getenv("ONELIST_KEYSTORE_ALIAS")
keyPassword = System.getenv("ONELIST_KEYSTORE_ALIAS_PASSWORD")
}
release
}

buildTypes {
Expand Down Expand Up @@ -68,6 +68,8 @@ repositories {
}

dependencies {
def room_version = "2.6.1"

implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
implementation 'androidx.appcompat:appcompat:1.6.1'
Expand All @@ -92,21 +94,7 @@ dependencies {
implementation "io.insert-koin:koin-android:3.5.0"
implementation "io.insert-koin:koin-androidx-navigation:3.5.0"

def room_version = "2.6.1"
implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-ktx:$room_version"
ksp "androidx.room:room-compiler:$room_version"

}

def props = new Properties()
if (rootProject.file("release.properties").exists()) {
props.load(new FileInputStream(rootProject.file("release.properties")))
android.signingConfigs.release.storeFile file(props.keyStore)
android.signingConfigs.release.storePassword props.keyStorePassword
android.signingConfigs.release.keyAlias props.keyAlias
android.signingConfigs.release.keyPassword props.keyAliasPassword
} else {
project.logger.info('INFO: Set the values storeFile, storePassword, keyAlias, and keyPassword in release.properties to sign the release.')
android.buildTypes.release.signingConfig = null
}
23 changes: 23 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-dontwarn com.fasterxml.jackson.core.**
-dontwarn com.google.common.annotations.**
-dontwarn javax.ws.rs.**
-dontwarn org.immutables.value.**

# R8 GSON special rules :
# https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md => Troubleshooting
# For data classes used for serialization all fields that are used in the serialization must be kept by the configuration. R8 can decide to replace instances of types that are never instantiated with null. So if instances of a given class are only created through deserialization from JSON, R8 will not see that class as instantiated leaving it as always null.
# If the @SerializedName annotation is not used the following conservative rule can be used for each data class :

-keepclassmembers class com.lolo.io.onelist.core.model.ItemList {
!transient <fields>;
}
-keepclassmembers class com.lolo.io.onelist.core.model.Item {
!transient <fields>;
}

# GSON uses type tokens to serialize and deserialize generic types.
# The anonymous class will have a generic signature argument of List<String> to the super type TypeToken that is reflective read for serialization. It is therefore necessary to keep both the Signature attribute, the com.google.gson.reflect.TypeToken class and all sub-types.

-keep class com.google.gson.reflect.TypeToken
-keep class * extends com.google.gson.reflect.TypeToken
-keep public class * implements java.lang.reflect.Type
1 change: 1 addition & 0 deletions app/src/main/java/com/lolo/io/onelist/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.koin.androidx.fragment.koin.fragmentFactory
import org.koin.core.context.startKoin

class App : Application() {

override fun onCreate() {
super.onCreate()
startKoin {
Expand Down
68 changes: 3 additions & 65 deletions app/src/main/java/com/lolo/io/onelist/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package com.lolo.io.onelist

import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.view.MotionEvent
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import com.anggrayudi.storage.SimpleStorageHelper
import com.lolo.io.onelist.core.data.shared_preferences.SharedPreferencesHelper
import com.lolo.io.onelist.core.ui.Config
import com.lolo.io.onelist.core.ui.REQUEST_CODE_OPEN_DOCUMENT
import com.lolo.io.onelist.core.ui.REQUEST_CODE_OPEN_DOCUMENT_TREE
import com.lolo.io.onelist.feature.lists.OneListFragment
import com.lolo.io.onelist.feature.lists.utils.StorageHelperHolder
import org.koin.android.ext.android.inject
Expand All @@ -21,18 +17,7 @@ class MainActivity : AppCompatActivity(), StorageHelperHolder {

override val storageHelper = SimpleStorageHelper(this)

val persistence by inject<SharedPreferencesHelper>()

// On some devices, displaying storage chooser fragment before activity is resumed leads to a crash.
// This is a workaround.
var whenResumed = {}
set(value) {
if (this.isResumed) value()
else field = value
}
private var isResumed = false

var onPathChosenActivityResult: (String) -> Any? = {}
private val preferences by inject<SharedPreferencesHelper>()

override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.AppTheme)
Expand Down Expand Up @@ -63,18 +48,6 @@ class MainActivity : AppCompatActivity(), StorageHelperHolder {
.replace(R.id.fragmentContainer, fragment, "OneListFragment")
.commit()


//supportFragmentManager.beginTransaction().add<SettingsFragment>(R.id.fragmentContainer).commit()


/* todo migrate whatsnew to a normal fragment
// WORKAROUND FOR WHATSNEW LIB NOT HANDLING WELL CONFIG CHANGES
if (savedInstanceState != null) {
supportFragmentManager.findFragmentByTag(WhatsNew.TAG)
?.let { supportFragmentManager.beginTransaction().remove(it).commit() }
?.let { WhatsNew.releasesNotes.entries.last().value().show(this) }
}
*/
}

override fun onRequestPermissionsResult(
Expand All @@ -93,19 +66,6 @@ class MainActivity : AppCompatActivity(), StorageHelperHolder {
return super.dispatchTouchEvent(ev)
}

override fun onResume() {
super.onResume()

whenResumed()
whenResumed = {}
isResumed = true
}

override fun onPause() {
super.onPause()
isResumed = false
}

interface OnDispatchTouchEvent {
fun onDispatchTouchEvent(ev: MotionEvent)
}
Expand All @@ -115,30 +75,14 @@ class MainActivity : AppCompatActivity(), StorageHelperHolder {
return true
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

if (requestCode == REQUEST_CODE_OPEN_DOCUMENT_TREE || requestCode == REQUEST_CODE_OPEN_DOCUMENT)
data?.data?.let { uri ->
contentResolver.takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
onPathChosenActivityResult(uri.toString())
onPathChosenActivityResult = { }
}
}
}

override fun attachBaseContext(newBase: Context) {
val context: Context = updateThemeConfiguration(newBase)
super.attachBaseContext(context)
}

private fun updateThemeConfiguration(context: Context): Context {
var mode = context.resources.configuration.uiMode
when (persistence.theme) {
when (preferences.theme) {
"light" -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
mode = Configuration.UI_MODE_NIGHT_NO;
Expand All @@ -154,12 +98,6 @@ class MainActivity : AppCompatActivity(), StorageHelperHolder {

val config = Configuration(context.resources.configuration)
config.uiMode = mode
var ctx = context
if (Build.VERSION.SDK_INT >= 17) {
ctx = context.createConfigurationContext(config)
} else {
context.resources.updateConfiguration(config, context.resources.displayMetrics)
}
return ctx
return context.createConfigurationContext(config)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import android.widget.Toast
import androidx.documentfile.provider.DocumentFile
import com.anggrayudi.storage.file.DocumentFileCompat
import com.anggrayudi.storage.file.getAbsolutePath
import com.anggrayudi.storage.file.isTreeDocumentFile
import com.anggrayudi.storage.file.makeFile
import com.google.gson.Gson
import com.google.gson.JsonIOException
Expand All @@ -19,6 +20,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.supervisorScope
import kotlinx.coroutines.withContext
import java.io.FileNotFoundException
import java.io.IOException
Expand All @@ -34,12 +36,8 @@ class FileAccess(
get() =
DocumentFileCompat.fromUri(app, this)?.canWrite() == true

private fun Uri.isIntoBackupFolder(backupUri: Uri): Boolean =
DocumentFileCompat.fromUri(app, this)?.getAbsolutePath(app)
?.startsWith(
DocumentFileCompat.fromUri(app, backupUri)?.getAbsolutePath(app)
?: throw IllegalArgumentException("Backup uri could not be parsed")
) == true
private fun Uri.isIntoBackupFolder(): Boolean =
DocumentFileCompat.fromUri(app, this)?.isTreeDocumentFile == true

private val Uri.fileExists
get() =
Expand All @@ -52,14 +50,14 @@ class FileAccess(
SecurityException::class
)
suspend fun getListFromLocalFile(list: ItemList): ItemList {
Log.d("1LogD", list.title)
return coroutineIOScope.async(SupervisorJob()) {
val listFromFile = list.uri?.let { uri ->
app.contentResolver.openInputStream(uri).use {
gson.fromJson(it?.reader(), ItemList::class.java)
}
} ?: list
listFromFile.apply {
id = list.id
uri = list.uri
}
}.await()
Expand All @@ -73,9 +71,10 @@ class FileAccess(
): ItemList {
if (backupUri != null) {
list.uri.let {
if (it == null
if (
it == null
|| !it.fileExists
|| !it.isIntoBackupFolder(Uri.parse(backupUri))
|| !it.isIntoBackupFolder()
|| !it.canWrite
) {
val uri = createListFile(backupUri, list)?.uri
Expand All @@ -91,16 +90,8 @@ class FileAccess(
)
}
} catch (e: Exception) {
coroutineIOScope.launch {
Toast.makeText(
app,
app.getString(
R.string.error_saving_to_path,
list.title
), // todo change to path to just error while saving list
Toast.LENGTH_SHORT
).show()
}
// Just don't save list in file. error has been toasted before normally.
// Should be handled better
}
}
}
Expand All @@ -118,28 +109,20 @@ class FileAccess(
}


// TODO Toasts should not be here !
fun deleteListBackupFile(list: ItemList) {
coroutineIOScope.launch {
@kotlin.jvm.Throws
fun deleteListBackupFile(
list: ItemList,
onFileDeleted: () -> Unit,
) {
coroutineIOScope.run {
list.uri?.let { uri ->
try {
if (
DocumentFile.fromSingleUri(app, uri)?.delete()
withContext(Dispatchers.Main) {
Toast.makeText(
app,
app.getString(R.string.file_deleted),
Toast.LENGTH_LONG
).show()
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
Toast.makeText(
app,
app.getString(R.string.error_deleting_list_file),
Toast.LENGTH_SHORT
).show()
}
!= true
) {
throw IOException("Could not delete file")
}
onFileDeleted()
}
}
}
Expand All @@ -156,8 +139,10 @@ class FileAccess(
.use { iss -> iss?.bufferedReader()?.use { it.readText() } }
// return :
gson.fromJson(content, ItemList::class.java).also {
it.uri = uri
onListCreated(it)
}

} catch (e: IllegalArgumentException) {
throw e
} catch (e: Exception) {
Expand Down
Loading

0 comments on commit c950b7b

Please sign in to comment.