From c7ba399b53218c68aefbb327db1d295460de6255 Mon Sep 17 00:00:00 2001 From: Iamlooker Date: Wed, 29 Jun 2022 19:31:53 +0530 Subject: [PATCH] Cleanup and optimize RepositoryList --- .../settings/repository/RepositoryPage.kt | 40 +++++++++ .../ui/fragments/PrefsRepositoriesFragment.kt | 87 +++---------------- .../ui/viewmodels/RepositoriesViewModelX.kt | 46 ++++++++-- 3 files changed, 92 insertions(+), 81 deletions(-) create mode 100644 src/main/kotlin/com/looker/droidify/ui/compose/pages/settings/repository/RepositoryPage.kt diff --git a/src/main/kotlin/com/looker/droidify/ui/compose/pages/settings/repository/RepositoryPage.kt b/src/main/kotlin/com/looker/droidify/ui/compose/pages/settings/repository/RepositoryPage.kt new file mode 100644 index 00000000..a137fdcc --- /dev/null +++ b/src/main/kotlin/com/looker/droidify/ui/compose/pages/settings/repository/RepositoryPage.kt @@ -0,0 +1,40 @@ +package com.looker.droidify.ui.compose.pages.settings.repository + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Add +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExtendedFloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import com.looker.droidify.ui.compose.RepositoriesRecycler +import com.looker.droidify.ui.viewmodels.RepositoriesViewModelX + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun RepositoryPage(viewModel: RepositoriesViewModelX) { + val repos by viewModel.repositories.collectAsState() + Scaffold( + modifier = Modifier.fillMaxSize(), + floatingActionButton = { + ExtendedFloatingActionButton(onClick = { viewModel.addRepository() }) { + Icon(imageVector = Icons.Rounded.Add, contentDescription = "Add Repository") + Text(text = "Add Repository") + } + } + ) { + val sortedRepoList = remember { repos.sortedBy { !it.enabled } } + RepositoriesRecycler( + repositoriesList = sortedRepoList, + onClick = { viewModel.toggleRepository(it, it.enabled) }, + onLongClick = { viewModel.showRepositorySheet(it.id) } + ) + + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/looker/droidify/ui/fragments/PrefsRepositoriesFragment.kt b/src/main/kotlin/com/looker/droidify/ui/fragments/PrefsRepositoriesFragment.kt index cf306812..f25a2403 100644 --- a/src/main/kotlin/com/looker/droidify/ui/fragments/PrefsRepositoriesFragment.kt +++ b/src/main/kotlin/com/looker/droidify/ui/fragments/PrefsRepositoriesFragment.kt @@ -5,64 +5,47 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedButton -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.livedata.observeAsState -import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp import androidx.fragment.app.viewModels -import com.looker.droidify.R +import androidx.lifecycle.lifecycleScope import com.looker.droidify.content.Preferences -import com.looker.droidify.service.Connection -import com.looker.droidify.service.SyncService import com.looker.droidify.ui.activities.PrefsActivityX -import com.looker.droidify.ui.compose.RepositoriesRecycler +import com.looker.droidify.ui.compose.pages.settings.repository.RepositoryPage import com.looker.droidify.ui.compose.theme.AppTheme import com.looker.droidify.ui.viewmodels.RepositoriesViewModelX import com.looker.droidify.utility.isDarkTheme -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.collectLatest class PrefsRepositoriesFragment : BaseNavFragment() { val viewModel: RepositoriesViewModelX by viewModels { - RepositoriesViewModelX.Factory(prefsActivityX.db) + RepositoriesViewModelX.Factory(prefsActivityX.db.repositoryDao) } private val prefsActivityX: PrefsActivityX get() = requireActivity() as PrefsActivityX - private val syncConnection = Connection(SyncService::class.java) - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View { super.onCreate(savedInstanceState) + lifecycleScope.launchWhenCreated { + viewModel.showSheet.collectLatest { + it?.let { + RepositorySheetX(it).showNow(childFragmentManager, "Repository $it") + } + } + } return ComposeView(requireContext()).apply { setContent { ReposPage() } } } override fun setupLayout() { - syncConnection.bind(requireContext()) + viewModel.bindConnection(requireContext()) viewModel.toLaunch.observe(viewLifecycleOwner) { if (it?.first == true) { EditRepositorySheetX(it.second) @@ -74,14 +57,11 @@ class PrefsRepositoriesFragment : BaseNavFragment() { override fun onDestroyView() { super.onDestroyView() - syncConnection.unbind(requireContext()) + viewModel.syncConnection.unbind(requireContext()) } - @OptIn(ExperimentalMaterial3Api::class) @Composable fun ReposPage() { - val repos by viewModel.repositories.observeAsState(null) - AppTheme( darkTheme = when (Preferences[Preferences.Key.Theme]) { is Preferences.Theme.System -> isSystemInDarkTheme() @@ -89,46 +69,7 @@ class PrefsRepositoriesFragment : BaseNavFragment() { else -> isDarkTheme } ) { - Scaffold { padding -> - Column( - modifier = Modifier.padding(padding) - ) { - OutlinedButton( - modifier = Modifier - .padding(8.dp) - .fillMaxWidth(), - contentPadding = PaddingValues(12.dp), - colors = ButtonDefaults.outlinedButtonColors( - contentColor = MaterialTheme.colorScheme.primary, - containerColor = MaterialTheme.colorScheme.background - ), - onClick = { viewModel.addRepository() } - ) { - Text( - modifier = Modifier.weight(1f), - text = stringResource(id = R.string.add_repository), - textAlign = TextAlign.Center, - style = MaterialTheme.typography.titleSmall - ) - Icon( - painter = painterResource(id = R.drawable.ic_add), - contentDescription = stringResource(id = R.string.add_repository) - ) - } - - RepositoriesRecycler( - repositoriesList = repos?.sortedBy { repo -> !repo.enabled }, - onClick = { repo -> - GlobalScope.launch(Dispatchers.IO) { - syncConnection.binder?.setEnabled(repo, repo.enabled) - } - }, - onLongClick = { repo -> - RepositorySheetX(repo.id) - .showNow(parentFragmentManager, "Repository ${repo.id}") - }) - } - } + RepositoryPage(viewModel = viewModel) } } } diff --git a/src/main/kotlin/com/looker/droidify/ui/viewmodels/RepositoriesViewModelX.kt b/src/main/kotlin/com/looker/droidify/ui/viewmodels/RepositoriesViewModelX.kt index b5d124c2..9a1ab55e 100644 --- a/src/main/kotlin/com/looker/droidify/ui/viewmodels/RepositoriesViewModelX.kt +++ b/src/main/kotlin/com/looker/droidify/ui/viewmodels/RepositoriesViewModelX.kt @@ -1,26 +1,56 @@ package com.looker.droidify.ui.viewmodels +import android.content.Context import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import com.looker.droidify.database.DatabaseX +import com.looker.droidify.database.dao.RepositoryDao import com.looker.droidify.database.entity.Repository import com.looker.droidify.database.entity.Repository.Companion.newRepository +import com.looker.droidify.service.Connection +import com.looker.droidify.service.SyncService import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -class RepositoriesViewModelX(val db: DatabaseX) : ViewModel() { +class RepositoriesViewModelX(val repositoryDao: RepositoryDao) : ViewModel() { - val repositories: MediatorLiveData> = MediatorLiveData() val toLaunch: MediatorLiveData?> = MediatorLiveData() + val syncConnection = Connection(SyncService::class.java) + + private val _showSheet = MutableStateFlow(null) + val showSheet = _showSheet.asStateFlow() + + private val _repositories = MutableStateFlow>(emptyList()) + val repositories = _repositories.asStateFlow() + init { - repositories.addSource(db.repositoryDao.allLive, repositories::setValue) + viewModelScope.launch(Dispatchers.IO) { + _repositories.emit(repositoryDao.all) + } toLaunch.value = null } + fun bindConnection(context: Context) { + viewModelScope.launch { syncConnection.bind(context) } + } + + fun showRepositorySheet(repositoryId: Long) { + viewModelScope.launch { + _showSheet.emit(repositoryId) + } + } + + fun toggleRepository(repository: Repository, isEnabled: Boolean) { + viewModelScope.launch(Dispatchers.IO) { + syncConnection.binder?.setEnabled(repository, isEnabled) + } + } + fun addRepository() { viewModelScope.launch { toLaunch.value = Pair(true, addNewRepository()) @@ -28,19 +58,19 @@ class RepositoriesViewModelX(val db: DatabaseX) : ViewModel() { } private suspend fun addNewRepository(): Long = withContext(Dispatchers.IO) { - db.repositoryDao.insert(newRepository(address = "new.Repository")) - db.repositoryDao.latestAddedId() + repositoryDao.insert(newRepository()) + repositoryDao.latestAddedId() } fun emptyToLaunch() { toLaunch.value = null } - class Factory(val db: DatabaseX) : ViewModelProvider.Factory { + class Factory(private val repoDao: RepositoryDao) : ViewModelProvider.Factory { @Suppress("unchecked_cast") override fun create(modelClass: Class): T { if (modelClass.isAssignableFrom(RepositoriesViewModelX::class.java)) { - return RepositoriesViewModelX(db) as T + return RepositoriesViewModelX(repoDao) as T } throw IllegalArgumentException("Unknown ViewModel class") }