mirror of
https://github.com/ActivityLauncher/ActivityLauncher.git
synced 2026-08-11 09:53:25 +00:00
fix: crash when shortcut name is empty
This commit is contained in:
parent
0c9ff66f48
commit
ee054da5b9
4 changed files with 137 additions and 1 deletions
|
|
@ -6,6 +6,7 @@ import android.content.Intent
|
|||
import androidx.core.content.pm.ShortcutInfoCompat
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import de.szalkowski.activitylauncher.R
|
||||
import de.szalkowski.activitylauncher.domain.launcher.IntentSigner
|
||||
import de.szalkowski.activitylauncher.domain.launcher.ShortcutCreator
|
||||
import de.szalkowski.activitylauncher.domain.model.ShortcutRequest
|
||||
|
|
@ -39,8 +40,9 @@ class ShortcutCreatorImpl @Inject constructor(
|
|||
intent.putExtra(ShortcutCreator.INTENT_EXTRA_LAUNCH_PLUGIN, it.flattenToString())
|
||||
}
|
||||
|
||||
val label = request.name.ifBlank { context.getString(R.string.app_name) }
|
||||
val shortcut = ShortcutInfoCompat.Builder(context, UUID.randomUUID().toString())
|
||||
.setShortLabel(request.name)
|
||||
.setShortLabel(label)
|
||||
.setIcon(request.icon)
|
||||
.setIntent(intent)
|
||||
.build()
|
||||
|
|
|
|||
|
|
@ -81,6 +81,10 @@ class ActivityDetailsFragment : Fragment() {
|
|||
} else {
|
||||
favoriteItem.setIcon(R.drawable.ic_favorite_border)
|
||||
}
|
||||
favoriteItem.isEnabled = viewModel.canFavorite.value
|
||||
|
||||
val shareItem = menu.findItem(R.id.action_share)
|
||||
shareItem.isEnabled = viewModel.canShare.value
|
||||
}
|
||||
|
||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||
|
|
@ -135,6 +139,30 @@ class ActivityDetailsFragment : Fragment() {
|
|||
binding.btCreateShortcutChooser.isVisible = isVisible
|
||||
}
|
||||
}
|
||||
launch {
|
||||
viewModel.canLaunch.collect { isEnabled ->
|
||||
binding.btLaunch.isEnabled = isEnabled
|
||||
binding.btLaunchChooser.isEnabled = isEnabled
|
||||
}
|
||||
}
|
||||
launch {
|
||||
viewModel.canCreateShortcut.collect { isEnabled ->
|
||||
binding.btCreateShortcut.isEnabled = isEnabled
|
||||
binding.btCreateShortcutChooser.isEnabled = isEnabled
|
||||
}
|
||||
}
|
||||
launch {
|
||||
viewModel.canShare.collect { isEnabled ->
|
||||
binding.btShareShortcut.isEnabled = isEnabled
|
||||
activity?.invalidateOptionsMenu()
|
||||
}
|
||||
}
|
||||
launch {
|
||||
viewModel.canFavorite.collect { isEnabled ->
|
||||
binding.btFavorite.isEnabled = isEnabled
|
||||
activity?.invalidateOptionsMenu()
|
||||
}
|
||||
}
|
||||
launch {
|
||||
viewModel.errorMessage.collect { resId ->
|
||||
Toast.makeText(requireContext(), resId, Toast.LENGTH_SHORT).show()
|
||||
|
|
|
|||
|
|
@ -26,12 +26,15 @@ import de.szalkowski.activitylauncher.domain.usecase.launcher.LaunchActivityUseC
|
|||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -70,6 +73,24 @@ class ActivityDetailsViewModel @Inject constructor(
|
|||
private val _editedIconResourceName = MutableStateFlow("")
|
||||
val editedIconResourceName: StateFlow<String> = _editedIconResourceName.asStateFlow()
|
||||
|
||||
val canLaunch: StateFlow<Boolean> = combine(_editedPackage, _editedClass) { pkg, cls ->
|
||||
pkg.isNotBlank() && cls.isNotBlank()
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false)
|
||||
|
||||
val canCreateShortcut: StateFlow<Boolean> =
|
||||
combine(_editedName, _editedPackage, _editedClass) { name, pkg, cls ->
|
||||
name.isNotBlank() && pkg.isNotBlank() && cls.isNotBlank()
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false)
|
||||
|
||||
val canShare: StateFlow<Boolean> = combine(_editedPackage, _editedClass) { pkg, cls ->
|
||||
pkg.isNotBlank() && cls.isNotBlank()
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false)
|
||||
|
||||
val canFavorite: StateFlow<Boolean> =
|
||||
combine(_editedName, _editedPackage, _editedClass) { name, pkg, cls ->
|
||||
name.isNotBlank() && pkg.isNotBlank() && cls.isNotBlank()
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false)
|
||||
|
||||
private val _editedIcon = MutableStateFlow<IconCompat?>(null)
|
||||
val editedIcon: StateFlow<IconCompat?> = _editedIcon.asStateFlow()
|
||||
|
||||
|
|
|
|||
|
|
@ -361,4 +361,89 @@ class ActivityDetailsViewModelTest {
|
|||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should update canLaunch state based on package and class`() = runTest {
|
||||
val values = mutableListOf<Boolean>()
|
||||
val job = launch(UnconfinedTestDispatcher(testScheduler)) {
|
||||
viewModel.canLaunch.collect { values.add(it) }
|
||||
}
|
||||
|
||||
viewModel.updatePackage("")
|
||||
viewModel.updateClass("Class")
|
||||
assertFalse(viewModel.canLaunch.value)
|
||||
|
||||
viewModel.updatePackage("pkg")
|
||||
viewModel.updateClass("")
|
||||
assertFalse(viewModel.canLaunch.value)
|
||||
|
||||
viewModel.updatePackage("pkg")
|
||||
viewModel.updateClass("Class")
|
||||
assertTrue(viewModel.canLaunch.value)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should update canCreateShortcut state based on name package and class`() = runTest {
|
||||
val values = mutableListOf<Boolean>()
|
||||
val job = launch(UnconfinedTestDispatcher(testScheduler)) {
|
||||
viewModel.canCreateShortcut.collect { values.add(it) }
|
||||
}
|
||||
|
||||
viewModel.updateName("")
|
||||
viewModel.updatePackage("pkg")
|
||||
viewModel.updateClass("Class")
|
||||
assertFalse(viewModel.canCreateShortcut.value)
|
||||
|
||||
viewModel.updateName("Name")
|
||||
viewModel.updatePackage("")
|
||||
viewModel.updateClass("Class")
|
||||
assertFalse(viewModel.canCreateShortcut.value)
|
||||
|
||||
viewModel.updateName("Name")
|
||||
viewModel.updatePackage("pkg")
|
||||
viewModel.updateClass("Class")
|
||||
assertTrue(viewModel.canCreateShortcut.value)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should update canShare state based on package and class`() = runTest {
|
||||
val values = mutableListOf<Boolean>()
|
||||
val job = launch(UnconfinedTestDispatcher(testScheduler)) {
|
||||
viewModel.canShare.collect { values.add(it) }
|
||||
}
|
||||
|
||||
viewModel.updatePackage("")
|
||||
viewModel.updateClass("Class")
|
||||
assertFalse(viewModel.canShare.value)
|
||||
|
||||
viewModel.updatePackage("pkg")
|
||||
viewModel.updateClass("Class")
|
||||
assertTrue(viewModel.canShare.value)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should update canFavorite state based on name package and class`() = runTest {
|
||||
val values = mutableListOf<Boolean>()
|
||||
val job = launch(UnconfinedTestDispatcher(testScheduler)) {
|
||||
viewModel.canFavorite.collect { values.add(it) }
|
||||
}
|
||||
|
||||
viewModel.updateName("")
|
||||
viewModel.updatePackage("pkg")
|
||||
viewModel.updateClass("Class")
|
||||
assertFalse(viewModel.canFavorite.value)
|
||||
|
||||
viewModel.updateName("Name")
|
||||
viewModel.updatePackage("pkg")
|
||||
viewModel.updateClass("Class")
|
||||
assertTrue(viewModel.canFavorite.value)
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue