diff --git a/app/src/main/java/eu/m724/pojavbackup/core/backup/BackupWorker.kt b/app/src/main/java/eu/m724/pojavbackup/core/backup/BackupWorker.kt index 965acf1..196b394 100644 --- a/app/src/main/java/eu/m724/pojavbackup/core/backup/BackupWorker.kt +++ b/app/src/main/java/eu/m724/pojavbackup/core/backup/BackupWorker.kt @@ -18,7 +18,6 @@ import eu.m724.pojavbackup.core.backup.Backup.BackupStatus import eu.m724.pojavbackup.core.data.GameDataRepository import eu.m724.pojavbackup.core.datastore.SettingsRepository import eu.m724.pojavbackup.notification.NotificationChannels -import kotlinx.coroutines.delay import org.apache.commons.compress.compressors.CompressorStreamFactory import java.time.LocalDate import java.time.format.DateTimeFormatter @@ -50,8 +49,6 @@ class BackupWorker @AssistedInject constructor( updateStatus("Initializing") - delay(10000) - val settings = settingsRepository.getSettings() val worldIds = settingsRepository.getIncludedWorldIds(settings.worldOrder) diff --git a/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt b/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt index 4e69b51..a05bd5d 100644 --- a/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt +++ b/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt @@ -30,7 +30,9 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource +import androidx.core.content.ContextCompat.startActivity import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.lifecycleScope import androidx.navigation.NavController import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.compose.NavHost @@ -43,8 +45,8 @@ import eu.m724.pojavbackup.home.screen.HomeScreen import eu.m724.pojavbackup.home.screen.dashboard.DashboardScreen import eu.m724.pojavbackup.home.screen.history.HistoryScreen import eu.m724.pojavbackup.settings.SettingsActivity -import eu.m724.pojavbackup.setup.SetupActivity import eu.m724.pojavbackup.ui.theme.PojavBackupTheme +import kotlinx.coroutines.launch @AndroidEntryPoint class HomeActivity : ComponentActivity() { @@ -62,8 +64,8 @@ class HomeActivity : ComponentActivity() { super.onCreate(savedInstanceState) viewModel.load( - onSetupNeeded = { - setupResult.launch(Intent(applicationContext, SetupActivity::class.java)) + onSetupRequired = { + setupResult.launch(it) } ) diff --git a/app/src/main/java/eu/m724/pojavbackup/home/HomeViewModel.kt b/app/src/main/java/eu/m724/pojavbackup/home/HomeViewModel.kt index 38b2afc..47b2445 100644 --- a/app/src/main/java/eu/m724/pojavbackup/home/HomeViewModel.kt +++ b/app/src/main/java/eu/m724/pojavbackup/home/HomeViewModel.kt @@ -1,9 +1,13 @@ package eu.m724.pojavbackup.home +import android.Manifest import android.app.NotificationManager import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager import android.net.Uri import android.util.Log +import androidx.core.content.ContextCompat import androidx.documentfile.provider.DocumentFile import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -12,6 +16,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext import eu.m724.pojavbackup.core.data.GameDataRepository import eu.m724.pojavbackup.core.datastore.SettingsRepository import eu.m724.pojavbackup.notification.NotificationChannels +import eu.m724.pojavbackup.setup.SetupActivity import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -38,14 +43,20 @@ class HomeViewModel @Inject constructor( } fun load( - onSetupNeeded: () -> Unit + onSetupRequired: (Intent) -> Unit ) { viewModelScope.launch { val uri = settingsRepository.getSource() - if (uri == null || !checkForStoragePermission(uri)) { - // TODO there could be that only one or two permissions are missing - onSetupNeeded() + val storagePermission = uri?.let { checkForStoragePermission(uri) } == true + val notificationPermission = checkForNotificationPermission() + + if (!storagePermission || !notificationPermission) { + val intent = Intent(appContext, SetupActivity::class.java) + .putExtra("storagePermissionGranted", storagePermission) + .putExtra("notificationPermissionGranted", notificationPermission) + + onSetupRequired(intent) } else { _uiState.update { it.copy(loading = false) } } @@ -75,4 +86,9 @@ class HomeViewModel @Inject constructor( return true } + + private fun checkForNotificationPermission(): Boolean { + // TODO check if rejected + return ContextCompat.checkSelfPermission(appContext, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED + } } \ No newline at end of file diff --git a/app/src/main/java/eu/m724/pojavbackup/setup/SetupActivity.kt b/app/src/main/java/eu/m724/pojavbackup/setup/SetupActivity.kt index 2e23632..bbb352c 100644 --- a/app/src/main/java/eu/m724/pojavbackup/setup/SetupActivity.kt +++ b/app/src/main/java/eu/m724/pojavbackup/setup/SetupActivity.kt @@ -1,5 +1,6 @@ package eu.m724.pojavbackup.setup +import android.Manifest import android.content.Intent import android.os.Bundle import android.widget.Toast @@ -37,7 +38,7 @@ class SetupActivity : ComponentActivity() { private val viewModel: SetupViewModel by viewModels() private val openDocumentTree = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { - viewModel.onOpenDocumentTree(applicationContext, it) { success -> + viewModel.onOpenDocumentTree(it) { success -> if (success) { onComplete() } else { @@ -51,16 +52,18 @@ class SetupActivity : ComponentActivity() { } } - private val notificationGrant = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> - if (isGranted) { - onComplete() - } else { - // TODO instead red text? - Toast.makeText( - applicationContext, - "This is not a PojavLauncher directory.", - Toast.LENGTH_SHORT - ).show() + private val notificationGrant = registerForActivityResult(ActivityResultContracts.RequestPermission()) { + viewModel.onNotificationGrant(it) { success -> + if (success) { + onComplete() + } else { + // TODO instead red text? + Toast.makeText( + applicationContext, + "This is not a PojavLauncher directory.", + Toast.LENGTH_SHORT + ).show() + } } } @@ -95,7 +98,7 @@ class SetupActivity : ComponentActivity() { openDocumentTree.launch(defaultUri) }, onNotificationPermissionGrantClick = { - openDocumentTree.launch(defaultUri) + notificationGrant.launch(Manifest.permission.POST_NOTIFICATIONS) } ) } @@ -134,7 +137,7 @@ fun SetupScreen( GrantCard( title = "Notification permission", description = "It's needed to notify you about backup status.", - granted = uiState.storagePermissionGranted, + granted = uiState.notificationPermissionGranted, onClick = onNotificationPermissionGrantClick ) } diff --git a/app/src/main/java/eu/m724/pojavbackup/setup/SetupViewModel.kt b/app/src/main/java/eu/m724/pojavbackup/setup/SetupViewModel.kt index c38d32e..c363596 100644 --- a/app/src/main/java/eu/m724/pojavbackup/setup/SetupViewModel.kt +++ b/app/src/main/java/eu/m724/pojavbackup/setup/SetupViewModel.kt @@ -2,7 +2,6 @@ package eu.m724.pojavbackup.setup import android.content.Context import android.content.Intent -import android.content.pm.PackageManager import android.content.pm.PackageManager.NameNotFoundException import android.net.Uri import android.util.Log @@ -10,6 +9,7 @@ import androidx.documentfile.provider.DocumentFile import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import eu.m724.pojavbackup.core.datastore.SettingsRepository import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -20,6 +20,7 @@ import javax.inject.Inject @HiltViewModel class SetupViewModel @Inject constructor( + @ApplicationContext private val appContext: Context, private val settingsRepository: SettingsRepository ) : ViewModel() { private val TAG: String = javaClass.name @@ -51,16 +52,16 @@ class SetupViewModel @Inject constructor( } // TODO we could make the check call separate and not pass context here - fun onOpenDocumentTree(context: Context, uri: Uri?, result: (Boolean) -> Unit) { + fun onOpenDocumentTree(uri: Uri?, result: (Boolean) -> Unit) { if (uri != null) { Log.i(TAG, "Got URI: $uri") - context.contentResolver.takePersistableUriPermission( + appContext.contentResolver.takePersistableUriPermission( uri, Intent.FLAG_GRANT_READ_URI_PERMISSION ) - val hasPermission = checkForStoragePermission(context, uri) + val hasPermission = checkForStoragePermission(uri) viewModelScope.launch { if (hasPermission) { @@ -72,11 +73,21 @@ class SetupViewModel @Inject constructor( } } - fun checkForStoragePermission(context: Context, uri: Uri): Boolean { + fun onNotificationGrant(isGranted: Boolean, result: (Boolean) -> Unit) { + if (isGranted) { + _uiState.update { + it.copy(notificationPermissionGranted = true) + } + } + + result(isGranted) + } + + fun checkForStoragePermission(uri: Uri): Boolean { Log.i(TAG, "Checking for storage permission...") // TODO Is this the right way? This isn't in https://developer.android.com/training/data-storage/shared/documents-files - val directory = DocumentFile.fromTreeUri(context, uri) + val directory = DocumentFile.fromTreeUri(appContext, uri) if (directory == null || !directory.isDirectory) { Log.i(TAG, "No permission or not a directory") @@ -100,7 +111,9 @@ class SetupViewModel @Inject constructor( return true } - fun detectInstalledLauncherPackage(packageManager: PackageManager): List { + fun detectInstalledLauncherPackage(): List { + val packageManager = appContext.packageManager + return POJAV_PACKAGES.filter { try { packageManager.getPackageInfo(it, 0)