mirror of
https://github.com/Aviortheking/Neo-Store.git
synced 2025-06-07 16:29:55 +00:00
Remove: Main Fragments
This commit is contained in:
parent
217c4e8997
commit
5e676f257f
@ -194,6 +194,95 @@ class DonateType(donate: Donate, context: Context) : LinkType(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum class Source(val sections: Boolean, val order: Boolean) {
|
||||||
|
AVAILABLE(true, true),
|
||||||
|
INSTALLED(false, true),
|
||||||
|
UPDATES(false, false),
|
||||||
|
UPDATED(false, true),
|
||||||
|
NEW(false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class Request {
|
||||||
|
internal abstract val id: Int
|
||||||
|
internal abstract val installed: Boolean
|
||||||
|
internal abstract val updates: Boolean
|
||||||
|
internal abstract val searchQuery: String
|
||||||
|
internal abstract val section: Section
|
||||||
|
internal abstract val order: Order
|
||||||
|
internal abstract val updateCategory: UpdateCategory
|
||||||
|
internal open val numberOfItems: Int = 0
|
||||||
|
|
||||||
|
data class ProductsAll(
|
||||||
|
override val searchQuery: String, override val section: Section,
|
||||||
|
override val order: Order,
|
||||||
|
) : Request() {
|
||||||
|
override val id: Int
|
||||||
|
get() = 1
|
||||||
|
override val installed: Boolean
|
||||||
|
get() = false
|
||||||
|
override val updates: Boolean
|
||||||
|
get() = false
|
||||||
|
override val updateCategory: UpdateCategory
|
||||||
|
get() = UpdateCategory.ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ProductsInstalled(
|
||||||
|
override val searchQuery: String, override val section: Section,
|
||||||
|
override val order: Order,
|
||||||
|
) : Request() {
|
||||||
|
override val id: Int
|
||||||
|
get() = 2
|
||||||
|
override val installed: Boolean
|
||||||
|
get() = true
|
||||||
|
override val updates: Boolean
|
||||||
|
get() = false
|
||||||
|
override val updateCategory: UpdateCategory
|
||||||
|
get() = UpdateCategory.ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ProductsUpdates(
|
||||||
|
override val searchQuery: String, override val section: Section,
|
||||||
|
override val order: Order,
|
||||||
|
) : Request() {
|
||||||
|
override val id: Int
|
||||||
|
get() = 3
|
||||||
|
override val installed: Boolean
|
||||||
|
get() = true
|
||||||
|
override val updates: Boolean
|
||||||
|
get() = true
|
||||||
|
override val updateCategory: UpdateCategory
|
||||||
|
get() = UpdateCategory.ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ProductsUpdated(
|
||||||
|
override val searchQuery: String, override val section: Section,
|
||||||
|
override val order: Order, override val numberOfItems: Int,
|
||||||
|
) : Request() {
|
||||||
|
override val id: Int
|
||||||
|
get() = 4
|
||||||
|
override val installed: Boolean
|
||||||
|
get() = false
|
||||||
|
override val updates: Boolean
|
||||||
|
get() = false
|
||||||
|
override val updateCategory: UpdateCategory
|
||||||
|
get() = UpdateCategory.UPDATED
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ProductsNew(
|
||||||
|
override val searchQuery: String, override val section: Section,
|
||||||
|
override val order: Order, override val numberOfItems: Int,
|
||||||
|
) : Request() {
|
||||||
|
override val id: Int
|
||||||
|
get() = 5
|
||||||
|
override val installed: Boolean
|
||||||
|
get() = false
|
||||||
|
override val updates: Boolean
|
||||||
|
get() = false
|
||||||
|
override val updateCategory: UpdateCategory
|
||||||
|
get() = UpdateCategory.NEW
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PermissionsType(
|
class PermissionsType(
|
||||||
val group: PermissionGroupInfo?,
|
val group: PermissionGroupInfo?,
|
||||||
val permissions: List<PermissionInfo>,
|
val permissions: List<PermissionInfo>,
|
||||||
|
@ -1,161 +0,0 @@
|
|||||||
package com.machiav3lli.fdroid.ui.fragments
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.rounded.Settings
|
|
||||||
import androidx.compose.material.icons.rounded.Sync
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
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.stringResource
|
|
||||||
import com.machiav3lli.fdroid.R
|
|
||||||
import com.machiav3lli.fdroid.content.Preferences
|
|
||||||
import com.machiav3lli.fdroid.database.entity.Repository
|
|
||||||
import com.machiav3lli.fdroid.entity.Section
|
|
||||||
import com.machiav3lli.fdroid.service.SyncService
|
|
||||||
import com.machiav3lli.fdroid.ui.activities.PrefsActivityX
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.ProductsVerticalRecycler
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.components.ExpandableSearchAction
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.components.TopBar
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.components.TopBarAction
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.components.CategoryChipList
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.theme.AppTheme
|
|
||||||
import com.machiav3lli.fdroid.utility.isDarkTheme
|
|
||||||
import com.machiav3lli.fdroid.utility.onLaunchClick
|
|
||||||
|
|
||||||
class ExploreFragment : MainNavFragmentX() {
|
|
||||||
|
|
||||||
override val primarySource = Source.AVAILABLE
|
|
||||||
override val secondarySource = Source.AVAILABLE
|
|
||||||
|
|
||||||
private var repositories: Map<Long, Repository> = mapOf()
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?,
|
|
||||||
): View {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
return ComposeView(requireContext()).apply {
|
|
||||||
setContent { ExplorePage() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupLayout() {
|
|
||||||
viewModel.repositories.observe(viewLifecycleOwner) {
|
|
||||||
repositories = it.associateBy { repo -> repo.id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
private fun ExplorePage() {
|
|
||||||
val products by viewModel.primaryProducts.observeAsState(null)
|
|
||||||
val categories by viewModel.categories.observeAsState(emptyList())
|
|
||||||
val installedList by viewModel.installed.observeAsState(null)
|
|
||||||
val searchQuery by viewModel.searchQuery.observeAsState("")
|
|
||||||
val favorites by mainActivityX.db.extrasDao.favoritesLive.observeAsState(emptyArray())
|
|
||||||
|
|
||||||
/*val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(
|
|
||||||
rememberTopAppBarState()
|
|
||||||
) { true }*/
|
|
||||||
|
|
||||||
AppTheme(
|
|
||||||
darkTheme = when (Preferences[Preferences.Key.Theme]) {
|
|
||||||
is Preferences.Theme.System -> isSystemInDarkTheme()
|
|
||||||
is Preferences.Theme.SystemBlack -> isSystemInDarkTheme()
|
|
||||||
else -> isDarkTheme
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Scaffold(
|
|
||||||
// TODO add the topBar to the activity instead of the fragments
|
|
||||||
//modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
|
||||||
topBar = {
|
|
||||||
TopBar(
|
|
||||||
title = stringResource(id = R.string.application_name),
|
|
||||||
//scrollBehavior = scrollBehavior
|
|
||||||
) {
|
|
||||||
ExpandableSearchAction(
|
|
||||||
query = searchQuery.orEmpty(),
|
|
||||||
onClose = {
|
|
||||||
viewModel.searchQuery.postValue("")
|
|
||||||
},
|
|
||||||
onQueryChanged = { query ->
|
|
||||||
if (isResumed && query != searchQuery)
|
|
||||||
viewModel.searchQuery.postValue(query)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
TopBarAction(icon = Icons.Rounded.Sync) {
|
|
||||||
mainActivityX.syncConnection.binder?.sync(SyncService.SyncRequest.MANUAL)
|
|
||||||
}
|
|
||||||
TopBarAction(icon = Icons.Rounded.Settings) {
|
|
||||||
startActivity(Intent(context, PrefsActivityX::class.java))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) { padding ->
|
|
||||||
Column(
|
|
||||||
Modifier
|
|
||||||
.padding(padding)
|
|
||||||
.background(MaterialTheme.colorScheme.background)
|
|
||||||
.fillMaxSize()
|
|
||||||
) {
|
|
||||||
CategoryChipList(
|
|
||||||
list = listOf(
|
|
||||||
stringResource(id = R.string.all_applications),
|
|
||||||
stringResource(id = R.string.favorite_applications),
|
|
||||||
*categories.sorted().toTypedArray()
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
viewModel.sections.postValue(
|
|
||||||
when (it) {
|
|
||||||
getString(R.string.all_applications) -> Section.All
|
|
||||||
getString(R.string.favorite_applications) -> Section.FAVORITE
|
|
||||||
else -> Section.Category(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ProductsVerticalRecycler(
|
|
||||||
productsList = products,
|
|
||||||
repositories = repositories,
|
|
||||||
favorites = favorites,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.weight(1f),
|
|
||||||
onUserClick = { item ->
|
|
||||||
mainActivityX.navigateProduct(item.packageName)
|
|
||||||
},
|
|
||||||
onFavouriteClick = { item ->
|
|
||||||
viewModel.setFavorite(
|
|
||||||
item.packageName,
|
|
||||||
!favorites.contains(item.packageName)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
getInstalled = { installedList?.get(it.packageName) }
|
|
||||||
) { item ->
|
|
||||||
val installed = installedList?.get(item.packageName)
|
|
||||||
if (installed != null && installed.launcherActivities.isNotEmpty())
|
|
||||||
requireContext().onLaunchClick(installed, childFragmentManager)
|
|
||||||
else
|
|
||||||
mainActivityX.syncConnection.binder?.installApps(listOf(item))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,253 +0,0 @@
|
|||||||
package com.machiav3lli.fdroid.ui.fragments
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.rounded.Settings
|
|
||||||
import androidx.compose.material.icons.rounded.Sync
|
|
||||||
import androidx.compose.material3.ButtonDefaults
|
|
||||||
import androidx.compose.material3.ElevatedButton
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.SuggestionChip
|
|
||||||
import androidx.compose.material3.SuggestionChipDefaults
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
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 com.machiav3lli.fdroid.R
|
|
||||||
import com.machiav3lli.fdroid.content.Preferences
|
|
||||||
import com.machiav3lli.fdroid.database.entity.Product
|
|
||||||
import com.machiav3lli.fdroid.database.entity.Repository
|
|
||||||
import com.machiav3lli.fdroid.service.SyncService
|
|
||||||
import com.machiav3lli.fdroid.ui.activities.PrefsActivityX
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.ProductsHorizontalRecycler
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.ProductsVerticalRecycler
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.components.ExpandableSearchAction
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.components.TopBar
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.components.TopBarAction
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.theme.AppTheme
|
|
||||||
import com.machiav3lli.fdroid.utility.isDarkTheme
|
|
||||||
import com.machiav3lli.fdroid.utility.onLaunchClick
|
|
||||||
|
|
||||||
class InstalledFragment : MainNavFragmentX() {
|
|
||||||
|
|
||||||
override val primarySource = Source.INSTALLED
|
|
||||||
override val secondarySource = Source.UPDATES
|
|
||||||
|
|
||||||
private var repositories: Map<Long, Repository> = mapOf()
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?,
|
|
||||||
): View {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
return ComposeView(requireContext()).apply {
|
|
||||||
setContent { InstalledPage() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupLayout() {
|
|
||||||
viewModel.repositories.observe(viewLifecycleOwner) {
|
|
||||||
repositories = it.associateBy { repo -> repo.id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
private fun InstalledPage() {
|
|
||||||
val primaryList by viewModel.primaryProducts.observeAsState(null)
|
|
||||||
val secondaryList by viewModel.secondaryProducts.observeAsState(null)
|
|
||||||
val installedList by viewModel.installed.observeAsState(null)
|
|
||||||
val searchQuery by viewModel.searchQuery.observeAsState("")
|
|
||||||
val favorites by mainActivityX.db.extrasDao.favoritesLive.observeAsState(emptyArray())
|
|
||||||
|
|
||||||
/*val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(
|
|
||||||
rememberTopAppBarState()
|
|
||||||
) { true }*/
|
|
||||||
|
|
||||||
AppTheme(
|
|
||||||
darkTheme = when (Preferences[Preferences.Key.Theme]) {
|
|
||||||
is Preferences.Theme.System -> isSystemInDarkTheme()
|
|
||||||
is Preferences.Theme.SystemBlack -> isSystemInDarkTheme()
|
|
||||||
else -> isDarkTheme
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Scaffold(
|
|
||||||
// TODO add the topBar to the activity instead of the fragments
|
|
||||||
//modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
|
||||||
topBar = {
|
|
||||||
TopBar(
|
|
||||||
title = stringResource(id = R.string.application_name),
|
|
||||||
//scrollBehavior = scrollBehavior
|
|
||||||
) {
|
|
||||||
ExpandableSearchAction(
|
|
||||||
query = searchQuery.orEmpty(),
|
|
||||||
onClose = {
|
|
||||||
viewModel.searchQuery.postValue("")
|
|
||||||
},
|
|
||||||
onQueryChanged = { query ->
|
|
||||||
if (isResumed && query != searchQuery)
|
|
||||||
viewModel.searchQuery.postValue(query)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
TopBarAction(icon = Icons.Rounded.Sync) {
|
|
||||||
mainActivityX.syncConnection.binder?.sync(SyncService.SyncRequest.MANUAL)
|
|
||||||
}
|
|
||||||
TopBarAction(icon = Icons.Rounded.Settings) {
|
|
||||||
startActivity(Intent(context, PrefsActivityX::class.java))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) { padding ->
|
|
||||||
var updatesVisible by remember(secondaryList) { mutableStateOf(true) }
|
|
||||||
|
|
||||||
Column(
|
|
||||||
Modifier
|
|
||||||
.padding(padding)
|
|
||||||
.background(MaterialTheme.colorScheme.background)
|
|
||||||
.fillMaxSize()
|
|
||||||
) {
|
|
||||||
AnimatedVisibility(visible = secondaryList.orEmpty().isNotEmpty()) {
|
|
||||||
Column {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
ElevatedButton(
|
|
||||||
colors = ButtonDefaults.elevatedButtonColors(
|
|
||||||
contentColor = MaterialTheme.colorScheme.primary
|
|
||||||
),
|
|
||||||
onClick = { updatesVisible = !updatesVisible }
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(start = 4.dp),
|
|
||||||
text = stringResource(id = R.string.updates),
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
style = MaterialTheme.typography.titleSmall
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier.size(18.dp),
|
|
||||||
painter = painterResource(id = if (updatesVisible) R.drawable.ic_arrow_up else R.drawable.ic_arrow_down),
|
|
||||||
contentDescription = stringResource(id = R.string.updates)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
SuggestionChip(
|
|
||||||
shape = MaterialTheme.shapes.medium,
|
|
||||||
colors = SuggestionChipDefaults.suggestionChipColors(
|
|
||||||
containerColor = MaterialTheme.colorScheme.surface,
|
|
||||||
labelColor = MaterialTheme.colorScheme.onSurface,
|
|
||||||
),
|
|
||||||
onClick = {
|
|
||||||
secondaryList?.let {
|
|
||||||
mainActivityX.syncConnection.binder?.updateApps(
|
|
||||||
it.map(
|
|
||||||
Product::toItem
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
icon = {
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier.size(18.dp),
|
|
||||||
painter = painterResource(id = R.drawable.ic_download),
|
|
||||||
contentDescription = stringResource(id = R.string.update_all)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
label = {
|
|
||||||
Text(text = stringResource(id = R.string.update_all))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
AnimatedVisibility(visible = updatesVisible) {
|
|
||||||
ProductsHorizontalRecycler(secondaryList, repositories) { item ->
|
|
||||||
mainActivityX.navigateProduct(item.packageName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.installed_applications),
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
)
|
|
||||||
/*SuggestionChip(
|
|
||||||
shape = MaterialTheme.shapes.medium,
|
|
||||||
colors = SuggestionChipDefaults.suggestionChipColors(
|
|
||||||
containerColor = MaterialTheme.colorScheme.surface,
|
|
||||||
labelColor = MaterialTheme.colorScheme.onSurface,
|
|
||||||
),
|
|
||||||
onClick = { }, // TODO add sort & filter
|
|
||||||
icon = {
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier.size(18.dp),
|
|
||||||
painter = painterResource(id = R.drawable.ic_sort),
|
|
||||||
contentDescription = stringResource(id = R.string.sort_filter)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
label = {
|
|
||||||
Text(text = stringResource(id = R.string.sort_filter))
|
|
||||||
}
|
|
||||||
)*/
|
|
||||||
}
|
|
||||||
ProductsVerticalRecycler(
|
|
||||||
productsList = primaryList?.sortedBy { it.label.lowercase() },
|
|
||||||
repositories = repositories,
|
|
||||||
favorites = favorites,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.weight(1f),
|
|
||||||
onUserClick = { item ->
|
|
||||||
mainActivityX.navigateProduct(item.packageName)
|
|
||||||
},
|
|
||||||
onFavouriteClick = { item ->
|
|
||||||
viewModel.setFavorite(
|
|
||||||
item.packageName,
|
|
||||||
!favorites.contains(item.packageName)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
getInstalled = { installedList?.get(it.packageName) }
|
|
||||||
) { item ->
|
|
||||||
val installed = installedList?.get(item.packageName)
|
|
||||||
if (installed != null && installed.launcherActivities.isNotEmpty())
|
|
||||||
requireContext().onLaunchClick(installed, childFragmentManager)
|
|
||||||
else
|
|
||||||
mainActivityX.syncConnection.binder?.installApps(listOf(item))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,187 +0,0 @@
|
|||||||
package com.machiav3lli.fdroid.ui.fragments
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.rounded.Settings
|
|
||||||
import androidx.compose.material.icons.rounded.Sync
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
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.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.platform.ComposeView
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import com.machiav3lli.fdroid.R
|
|
||||||
import com.machiav3lli.fdroid.content.Preferences
|
|
||||||
import com.machiav3lli.fdroid.database.entity.Repository
|
|
||||||
import com.machiav3lli.fdroid.service.SyncService
|
|
||||||
import com.machiav3lli.fdroid.ui.activities.PrefsActivityX
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.ProductsHorizontalRecycler
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.components.ExpandableSearchAction
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.components.ProductsListItem
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.components.TopBar
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.components.TopBarAction
|
|
||||||
import com.machiav3lli.fdroid.ui.compose.theme.AppTheme
|
|
||||||
import com.machiav3lli.fdroid.utility.isDarkTheme
|
|
||||||
import com.machiav3lli.fdroid.utility.onLaunchClick
|
|
||||||
|
|
||||||
class LatestFragment : MainNavFragmentX() {
|
|
||||||
|
|
||||||
override val primarySource = Source.UPDATED
|
|
||||||
override val secondarySource = Source.NEW
|
|
||||||
|
|
||||||
private var repositories: Map<Long, Repository> = mapOf()
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?,
|
|
||||||
): View {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
return ComposeView(requireContext()).apply {
|
|
||||||
setContent { LatestPage() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupLayout() {
|
|
||||||
viewModel.repositories.observe(viewLifecycleOwner) {
|
|
||||||
repositories = it.associateBy { repo -> repo.id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
private fun LatestPage() {
|
|
||||||
val primaryList by viewModel.primaryProducts.observeAsState(null)
|
|
||||||
val secondaryList by viewModel.secondaryProducts.observeAsState(null)
|
|
||||||
val installedList by viewModel.installed.observeAsState(null)
|
|
||||||
val searchQuery by viewModel.searchQuery.observeAsState("")
|
|
||||||
val favorites by mainActivityX.db.extrasDao.favoritesLive.observeAsState(emptyArray())
|
|
||||||
|
|
||||||
/*val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(
|
|
||||||
rememberTopAppBarState()
|
|
||||||
) { true }*/
|
|
||||||
|
|
||||||
AppTheme(
|
|
||||||
darkTheme = when (Preferences[Preferences.Key.Theme]) {
|
|
||||||
is Preferences.Theme.System -> isSystemInDarkTheme()
|
|
||||||
is Preferences.Theme.SystemBlack -> isSystemInDarkTheme()
|
|
||||||
else -> isDarkTheme
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Scaffold(
|
|
||||||
// TODO add the topBar to the activity instead of the fragments
|
|
||||||
//modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
|
||||||
topBar = {
|
|
||||||
TopBar(
|
|
||||||
title = stringResource(id = R.string.application_name),
|
|
||||||
//scrollBehavior = scrollBehavior
|
|
||||||
) {
|
|
||||||
ExpandableSearchAction(
|
|
||||||
query = searchQuery.orEmpty(),
|
|
||||||
onClose = {
|
|
||||||
viewModel.searchQuery.postValue("")
|
|
||||||
},
|
|
||||||
onQueryChanged = { query ->
|
|
||||||
if (isResumed && query != searchQuery)
|
|
||||||
viewModel.searchQuery.postValue(query)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
TopBarAction(icon = Icons.Rounded.Sync) {
|
|
||||||
mainActivityX.syncConnection.binder?.sync(SyncService.SyncRequest.MANUAL)
|
|
||||||
}
|
|
||||||
TopBarAction(icon = Icons.Rounded.Settings) {
|
|
||||||
startActivity(Intent(context, PrefsActivityX::class.java))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) { padding ->
|
|
||||||
LazyColumn(
|
|
||||||
Modifier
|
|
||||||
.padding(padding)
|
|
||||||
.background(MaterialTheme.colorScheme.background)
|
|
||||||
.fillMaxSize(),
|
|
||||||
) {
|
|
||||||
item {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.new_applications),
|
|
||||||
modifier = Modifier.padding(8.dp)
|
|
||||||
)
|
|
||||||
ProductsHorizontalRecycler(secondaryList, repositories) { item ->
|
|
||||||
mainActivityX.navigateProduct(item.packageName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.recently_updated),
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
)
|
|
||||||
/*SuggestionChip(
|
|
||||||
shape = MaterialTheme.shapes.medium,
|
|
||||||
colors = SuggestionChipDefaults.suggestionChipColors(
|
|
||||||
containerColor = MaterialTheme.colorScheme.surface,
|
|
||||||
labelColor = MaterialTheme.colorScheme.onSurface,
|
|
||||||
),
|
|
||||||
onClick = { }, // TODO add sort & filter
|
|
||||||
icon = {
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier.size(18.dp),
|
|
||||||
painter = painterResource(id = R.drawable.ic_sort),
|
|
||||||
contentDescription = stringResource(id = R.string.sort_filter)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
label = {
|
|
||||||
Text(text = stringResource(id = R.string.sort_filter))
|
|
||||||
}
|
|
||||||
)*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
items(
|
|
||||||
items = primaryList?.map { it.toItem() } ?: emptyList(),
|
|
||||||
) { item ->
|
|
||||||
ProductsListItem(
|
|
||||||
item = item,
|
|
||||||
repo = repositories[item.repositoryId],
|
|
||||||
isFavorite = favorites.contains(item.packageName),
|
|
||||||
onUserClick = { mainActivityX.navigateProduct(it.packageName) },
|
|
||||||
onFavouriteClick = {
|
|
||||||
viewModel.setFavorite(
|
|
||||||
it.packageName,
|
|
||||||
!favorites.contains(it.packageName)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
installed = installedList?.get(item.packageName),
|
|
||||||
onActionClick = {
|
|
||||||
val installed = installedList?.get(it.packageName)
|
|
||||||
if (installed != null && installed.launcherActivities.isNotEmpty())
|
|
||||||
requireContext().onLaunchClick(installed, childFragmentManager)
|
|
||||||
else
|
|
||||||
mainActivityX.syncConnection.binder?.installApps(listOf(it))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
package com.machiav3lli.fdroid.ui.fragments
|
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import com.machiav3lli.fdroid.R
|
|
||||||
import com.machiav3lli.fdroid.entity.Order
|
|
||||||
import com.machiav3lli.fdroid.entity.Section
|
|
||||||
import com.machiav3lli.fdroid.entity.UpdateCategory
|
|
||||||
import com.machiav3lli.fdroid.ui.activities.MainActivityX
|
|
||||||
import com.machiav3lli.fdroid.ui.viewmodels.MainNavFragmentViewModelX
|
|
||||||
|
|
||||||
abstract class MainNavFragmentX : BaseNavFragment() {
|
|
||||||
protected val mainActivityX: MainActivityX
|
|
||||||
get() = requireActivity() as MainActivityX
|
|
||||||
val viewModel: MainNavFragmentViewModelX by viewModels {
|
|
||||||
MainNavFragmentViewModelX.Factory(mainActivityX.db, primarySource, secondarySource)
|
|
||||||
}
|
|
||||||
abstract val primarySource: Source
|
|
||||||
abstract val secondarySource: Source
|
|
||||||
|
|
||||||
open fun onBackPressed(): Boolean = false
|
|
||||||
|
|
||||||
protected fun launchFragment(fragment: Fragment): Boolean {
|
|
||||||
requireActivity().supportFragmentManager
|
|
||||||
.beginTransaction()
|
|
||||||
.replace(R.id.fragment_content, fragment)
|
|
||||||
.addToBackStack(null)
|
|
||||||
.commit()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class Source(val sections: Boolean, val order: Boolean) {
|
|
||||||
AVAILABLE(true, true),
|
|
||||||
INSTALLED(false, true),
|
|
||||||
UPDATES(false, false),
|
|
||||||
UPDATED(false, true),
|
|
||||||
NEW(false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Request {
|
|
||||||
internal abstract val id: Int
|
|
||||||
internal abstract val installed: Boolean
|
|
||||||
internal abstract val updates: Boolean
|
|
||||||
internal abstract val searchQuery: String
|
|
||||||
internal abstract val section: Section
|
|
||||||
internal abstract val order: Order
|
|
||||||
internal abstract val updateCategory: UpdateCategory
|
|
||||||
internal open val numberOfItems: Int = 0
|
|
||||||
|
|
||||||
data class ProductsAll(
|
|
||||||
override val searchQuery: String, override val section: Section,
|
|
||||||
override val order: Order,
|
|
||||||
) : Request() {
|
|
||||||
override val id: Int
|
|
||||||
get() = 1
|
|
||||||
override val installed: Boolean
|
|
||||||
get() = false
|
|
||||||
override val updates: Boolean
|
|
||||||
get() = false
|
|
||||||
override val updateCategory: UpdateCategory
|
|
||||||
get() = UpdateCategory.ALL
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ProductsInstalled(
|
|
||||||
override val searchQuery: String, override val section: Section,
|
|
||||||
override val order: Order,
|
|
||||||
) : Request() {
|
|
||||||
override val id: Int
|
|
||||||
get() = 2
|
|
||||||
override val installed: Boolean
|
|
||||||
get() = true
|
|
||||||
override val updates: Boolean
|
|
||||||
get() = false
|
|
||||||
override val updateCategory: UpdateCategory
|
|
||||||
get() = UpdateCategory.ALL
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ProductsUpdates(
|
|
||||||
override val searchQuery: String, override val section: Section,
|
|
||||||
override val order: Order,
|
|
||||||
) : Request() {
|
|
||||||
override val id: Int
|
|
||||||
get() = 3
|
|
||||||
override val installed: Boolean
|
|
||||||
get() = true
|
|
||||||
override val updates: Boolean
|
|
||||||
get() = true
|
|
||||||
override val updateCategory: UpdateCategory
|
|
||||||
get() = UpdateCategory.ALL
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ProductsUpdated(
|
|
||||||
override val searchQuery: String, override val section: Section,
|
|
||||||
override val order: Order, override val numberOfItems: Int,
|
|
||||||
) : Request() {
|
|
||||||
override val id: Int
|
|
||||||
get() = 4
|
|
||||||
override val installed: Boolean
|
|
||||||
get() = false
|
|
||||||
override val updates: Boolean
|
|
||||||
get() = false
|
|
||||||
override val updateCategory: UpdateCategory
|
|
||||||
get() = UpdateCategory.UPDATED
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ProductsNew(
|
|
||||||
override val searchQuery: String, override val section: Section,
|
|
||||||
override val order: Order, override val numberOfItems: Int,
|
|
||||||
) : Request() {
|
|
||||||
override val id: Int
|
|
||||||
get() = 5
|
|
||||||
override val installed: Boolean
|
|
||||||
get() = false
|
|
||||||
override val updates: Boolean
|
|
||||||
get() = false
|
|
||||||
override val updateCategory: UpdateCategory
|
|
||||||
get() = UpdateCategory.NEW
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,8 +17,8 @@ import com.google.accompanist.navigation.animation.AnimatedNavHost
|
|||||||
import com.google.accompanist.navigation.animation.composable
|
import com.google.accompanist.navigation.animation.composable
|
||||||
import com.machiav3lli.fdroid.content.Preferences
|
import com.machiav3lli.fdroid.content.Preferences
|
||||||
import com.machiav3lli.fdroid.database.DatabaseX
|
import com.machiav3lli.fdroid.database.DatabaseX
|
||||||
|
import com.machiav3lli.fdroid.entity.Source
|
||||||
import com.machiav3lli.fdroid.ui.activities.PrefsActivityX
|
import com.machiav3lli.fdroid.ui.activities.PrefsActivityX
|
||||||
import com.machiav3lli.fdroid.ui.fragments.Source
|
|
||||||
import com.machiav3lli.fdroid.ui.pages.ExplorePage
|
import com.machiav3lli.fdroid.ui.pages.ExplorePage
|
||||||
import com.machiav3lli.fdroid.ui.pages.InstalledPage
|
import com.machiav3lli.fdroid.ui.pages.InstalledPage
|
||||||
import com.machiav3lli.fdroid.ui.pages.LatestPage
|
import com.machiav3lli.fdroid.ui.pages.LatestPage
|
||||||
|
@ -12,9 +12,9 @@ import com.machiav3lli.fdroid.database.entity.Installed
|
|||||||
import com.machiav3lli.fdroid.database.entity.Product
|
import com.machiav3lli.fdroid.database.entity.Product
|
||||||
import com.machiav3lli.fdroid.database.entity.Repository
|
import com.machiav3lli.fdroid.database.entity.Repository
|
||||||
import com.machiav3lli.fdroid.entity.Order
|
import com.machiav3lli.fdroid.entity.Order
|
||||||
|
import com.machiav3lli.fdroid.entity.Request
|
||||||
import com.machiav3lli.fdroid.entity.Section
|
import com.machiav3lli.fdroid.entity.Section
|
||||||
import com.machiav3lli.fdroid.ui.fragments.Request
|
import com.machiav3lli.fdroid.entity.Source
|
||||||
import com.machiav3lli.fdroid.ui.fragments.Source
|
|
||||||
import com.machiav3lli.fdroid.utility.extension.ManageableLiveData
|
import com.machiav3lli.fdroid.utility.extension.ManageableLiveData
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<data>
|
|
||||||
|
|
||||||
</data>
|
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?colorSurface">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:id="@+id/appbar_layout"
|
|
||||||
style="?attr/appBarLayoutStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@android:color/transparent">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
|
||||||
android:id="@+id/collapsing_toolbar"
|
|
||||||
style="?attr/collapsingToolbarLayoutLargeStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?attr/collapsingToolbarLayoutLargeSize"
|
|
||||||
app:layout_scrollFlags="scroll|snap|exitUntilCollapsed">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
|
||||||
android:id="@+id/toolbar"
|
|
||||||
style="?attr/toolbarStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?actionBarSize" />
|
|
||||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.circularreveal.CircularRevealFrameLayout
|
|
||||||
android:id="@+id/toolbar_extra"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
android:id="@+id/fragment_content"
|
|
||||||
style="?materialCardViewFilledStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:cardBackgroundColor="?android:colorBackground"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
|
||||||
app:shapeAppearanceOverlay="@style/Shape.BottomSheet" />
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
</layout>
|
|
Loading…
x
Reference in New Issue
Block a user