mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Feature: Bookmark Categories (#6035)
* database setup and insert/delete working Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> * add new categories screen in bookmarks page Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> * add theme Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> * set tab layout scrollable Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> * cleanup Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> * fix tests Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> * bump database version Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> * add docs Signed-off-by: parneet-guraya <gurayaparneet@gmail.com> --------- Signed-off-by: parneet-guraya <gurayaparneet@gmail.com>
This commit is contained in:
parent
0153cbe0ed
commit
5500b03976
15 changed files with 410 additions and 11 deletions
|
|
@ -7,13 +7,13 @@ import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import fr.free.nrw.commons.Media;
|
import fr.free.nrw.commons.Media;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
|
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesFragment;
|
||||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsFragment;
|
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsFragment;
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsFragment;
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsFragment;
|
||||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment;
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment;
|
||||||
|
|
@ -48,14 +48,21 @@ public class BookmarkListRootFragment extends CommonsDaggerSupportFragment imple
|
||||||
String title = bundle.getString("categoryName");
|
String title = bundle.getString("categoryName");
|
||||||
int order = bundle.getInt("order");
|
int order = bundle.getInt("order");
|
||||||
final int orderItem = bundle.getInt("orderItem");
|
final int orderItem = bundle.getInt("orderItem");
|
||||||
if (order == 0) {
|
|
||||||
listFragment = new BookmarkPicturesFragment();
|
switch (order){
|
||||||
} else {
|
case 0: listFragment = new BookmarkPicturesFragment();
|
||||||
listFragment = new BookmarkLocationsFragment();
|
break;
|
||||||
|
|
||||||
|
case 1: listFragment = new BookmarkLocationsFragment();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: listFragment = new BookmarkCategoriesFragment();
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(orderItem == 2) {
|
if(orderItem == 2) {
|
||||||
listFragment = new BookmarkItemsFragment();
|
listFragment = new BookmarkItemsFragment();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Bundle featuredArguments = new Bundle();
|
Bundle featuredArguments = new Bundle();
|
||||||
featuredArguments.putString("categoryName", title);
|
featuredArguments.putString("categoryName", title);
|
||||||
listFragment.setArguments(featuredArguments);
|
listFragment.setArguments(featuredArguments);
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,13 @@ public class BookmarksPagerAdapter extends FragmentPagerAdapter {
|
||||||
new BookmarkListRootFragment(locationBundle, this),
|
new BookmarkListRootFragment(locationBundle, this),
|
||||||
context.getString(R.string.title_page_bookmarks_items)));
|
context.getString(R.string.title_page_bookmarks_items)));
|
||||||
}
|
}
|
||||||
|
final Bundle categoriesBundle = new Bundle();
|
||||||
|
categoriesBundle.putString("categoryName",
|
||||||
|
context.getString(R.string.title_page_bookmarks_categories));
|
||||||
|
categoriesBundle.putInt("order", 3);
|
||||||
|
pages.add(new BookmarkPages(
|
||||||
|
new BookmarkListRootFragment(categoriesBundle, this),
|
||||||
|
context.getString(R.string.title_page_bookmarks_categories)));
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package fr.free.nrw.commons.bookmarks.category
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bookmark categories dao
|
||||||
|
*
|
||||||
|
* @constructor Create empty Bookmark categories dao
|
||||||
|
*/
|
||||||
|
@Dao
|
||||||
|
interface BookmarkCategoriesDao {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert or Delete category bookmark into DB
|
||||||
|
*
|
||||||
|
* @param bookmarksCategoryModal
|
||||||
|
*/
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun insert(bookmarksCategoryModal: BookmarksCategoryModal)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete category bookmark from DB
|
||||||
|
*
|
||||||
|
* @param bookmarksCategoryModal
|
||||||
|
*/
|
||||||
|
@Delete
|
||||||
|
suspend fun delete(bookmarksCategoryModal: BookmarksCategoryModal)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if given category exist in DB
|
||||||
|
*
|
||||||
|
* @param categoryName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Query("SELECT EXISTS (SELECT 1 FROM bookmarks_categories WHERE categoryName = :categoryName)")
|
||||||
|
suspend fun doesExist(categoryName: String): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all categories
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Query("SELECT * FROM bookmarks_categories")
|
||||||
|
fun getAllCategories(): Flow<List<BookmarksCategoryModal>>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
package fr.free.nrw.commons.bookmarks.category
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.ListItem
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.darkColorScheme
|
||||||
|
import androidx.compose.material3.lightColorScheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.ComposeView
|
||||||
|
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||||
|
import androidx.compose.ui.res.colorResource
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import dagger.android.support.DaggerFragment
|
||||||
|
import fr.free.nrw.commons.R
|
||||||
|
import fr.free.nrw.commons.category.CategoryDetailsActivity
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tab fragment to show list of bookmarked Categories
|
||||||
|
*/
|
||||||
|
class BookmarkCategoriesFragment : DaggerFragment() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var bookmarkCategoriesDao: BookmarkCategoriesDao
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
return ComposeView(requireContext()).apply {
|
||||||
|
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||||
|
setContent {
|
||||||
|
MaterialTheme(
|
||||||
|
colorScheme = if (isSystemInDarkTheme()) darkColorScheme(
|
||||||
|
primary = colorResource(R.color.primaryDarkColor),
|
||||||
|
surface = colorResource(R.color.main_background_dark),
|
||||||
|
background = colorResource(R.color.main_background_dark)
|
||||||
|
) else lightColorScheme(
|
||||||
|
primary = colorResource(R.color.primaryColor),
|
||||||
|
surface = colorResource(R.color.main_background_light),
|
||||||
|
background = colorResource(R.color.main_background_light)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
val listOfBookmarks by bookmarkCategoriesDao.getAllCategories()
|
||||||
|
.collectAsStateWithLifecycle(initialValue = emptyList())
|
||||||
|
Surface(modifier = Modifier.fillMaxSize()) {
|
||||||
|
Box(contentAlignment = Alignment.Center) {
|
||||||
|
if (listOfBookmarks.isEmpty()) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.bookmark_empty),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = if (isSystemInDarkTheme()) Color(0xB3FFFFFF)
|
||||||
|
else Color(
|
||||||
|
0x8A000000
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||||
|
items(items = listOfBookmarks) { bookmarkItem ->
|
||||||
|
CategoryItem(
|
||||||
|
categoryName = bookmarkItem.categoryName,
|
||||||
|
onClick = {
|
||||||
|
val categoryDetailsIntent = Intent(
|
||||||
|
requireContext(),
|
||||||
|
CategoryDetailsActivity::class.java
|
||||||
|
).putExtra("categoryName", it)
|
||||||
|
startActivity(categoryDetailsIntent)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CategoryItem(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onClick: (String) -> Unit,
|
||||||
|
categoryName: String
|
||||||
|
) {
|
||||||
|
Row(modifier = modifier.clickable {
|
||||||
|
onClick(categoryName)
|
||||||
|
}) {
|
||||||
|
ListItem(
|
||||||
|
leadingContent = {
|
||||||
|
Image(
|
||||||
|
modifier = Modifier.size(48.dp),
|
||||||
|
painter = painterResource(R.drawable.commons),
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
},
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = categoryName,
|
||||||
|
maxLines = 2,
|
||||||
|
color = if (isSystemInDarkTheme()) Color.White else Color.Black,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun CategoryItemPreview() {
|
||||||
|
CategoryItem(
|
||||||
|
onClick = {},
|
||||||
|
categoryName = "Test Category"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package fr.free.nrw.commons.bookmarks.category
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class representing bookmarked category in DB
|
||||||
|
*
|
||||||
|
* @property categoryName
|
||||||
|
* @constructor Create empty Bookmarks category modal
|
||||||
|
*/
|
||||||
|
@Entity(tableName = "bookmarks_categories")
|
||||||
|
data class BookmarksCategoryModal(
|
||||||
|
@PrimaryKey val categoryName: String
|
||||||
|
)
|
||||||
|
|
@ -7,8 +7,12 @@ import android.os.Bundle
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import fr.free.nrw.commons.Media
|
import fr.free.nrw.commons.Media
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.Utils
|
import fr.free.nrw.commons.Utils
|
||||||
|
|
@ -19,6 +23,8 @@ import fr.free.nrw.commons.explore.categories.parent.ParentCategoriesFragment
|
||||||
import fr.free.nrw.commons.explore.categories.sub.SubCategoriesFragment
|
import fr.free.nrw.commons.explore.categories.sub.SubCategoriesFragment
|
||||||
import fr.free.nrw.commons.media.MediaDetailPagerFragment
|
import fr.free.nrw.commons.media.MediaDetailPagerFragment
|
||||||
import fr.free.nrw.commons.theme.BaseActivity
|
import fr.free.nrw.commons.theme.BaseActivity
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -38,6 +44,11 @@ class CategoryDetailsActivity : BaseActivity(),
|
||||||
|
|
||||||
private lateinit var binding: ActivityCategoryDetailsBinding
|
private lateinit var binding: ActivityCategoryDetailsBinding
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var categoryViewModelFactory: CategoryDetailsViewModel.ViewModelFactory
|
||||||
|
|
||||||
|
private val viewModel: CategoryDetailsViewModel by viewModels<CategoryDetailsViewModel> { categoryViewModelFactory }
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
|
@ -53,6 +64,15 @@ class CategoryDetailsActivity : BaseActivity(),
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
setTabs()
|
setTabs()
|
||||||
setPageTitle()
|
setPageTitle()
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
repeatOnLifecycle(Lifecycle.State.STARTED){
|
||||||
|
viewModel.bookmarkState.collect {
|
||||||
|
invalidateOptionsMenu()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -73,6 +93,8 @@ class CategoryDetailsActivity : BaseActivity(),
|
||||||
categoriesMediaFragment.arguments = arguments
|
categoriesMediaFragment.arguments = arguments
|
||||||
subCategoryListFragment.arguments = arguments
|
subCategoryListFragment.arguments = arguments
|
||||||
parentCategoriesFragment.arguments = arguments
|
parentCategoriesFragment.arguments = arguments
|
||||||
|
|
||||||
|
viewModel.onCheckIfBookmarked(categoryName!!)
|
||||||
}
|
}
|
||||||
fragmentList.add(categoriesMediaFragment)
|
fragmentList.add(categoriesMediaFragment)
|
||||||
titleList.add("MEDIA")
|
titleList.add("MEDIA")
|
||||||
|
|
@ -181,6 +203,14 @@ class CategoryDetailsActivity : BaseActivity(),
|
||||||
Utils.handleWebUrl(this, Uri.parse(title.canonicalUri))
|
Utils.handleWebUrl(this, Uri.parse(title.canonicalUri))
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R.id.menu_bookmark_current_category -> {
|
||||||
|
categoryName?.let {
|
||||||
|
viewModel.onBookmarkClick(categoryName = it)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
true
|
true
|
||||||
|
|
@ -189,6 +219,22 @@ class CategoryDetailsActivity : BaseActivity(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
|
||||||
|
menu?.run {
|
||||||
|
val bookmarkMenuItem = findItem(R.id.menu_bookmark_current_category)
|
||||||
|
if (bookmarkMenuItem != null) {
|
||||||
|
val icon = if(viewModel.bookmarkState.value){
|
||||||
|
R.drawable.menu_ic_round_star_filled_24px
|
||||||
|
} else {
|
||||||
|
R.drawable.menu_ic_round_star_border_24px
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmarkMenuItem.setIcon(icon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onPrepareOptionsMenu(menu)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called on backPressed of anyFragment in the activity.
|
* This method is called on backPressed of anyFragment in the activity.
|
||||||
* If condition is called when mediaDetailFragment is opened.
|
* If condition is called when mediaDetailFragment is opened.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
package fr.free.nrw.commons.category
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao
|
||||||
|
import fr.free.nrw.commons.bookmarks.category.BookmarksCategoryModal
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewModal for [CategoryDetailsActivity]
|
||||||
|
*/
|
||||||
|
class CategoryDetailsViewModel(
|
||||||
|
private val bookmarkCategoriesDao: BookmarkCategoriesDao
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
private val _bookmarkState = MutableStateFlow(false)
|
||||||
|
val bookmarkState = _bookmarkState.asStateFlow()
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to check if bookmark exists for the given category in DB
|
||||||
|
* based on that bookmark state is updated
|
||||||
|
* @param categoryName
|
||||||
|
*/
|
||||||
|
fun onCheckIfBookmarked(categoryName: String) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val isBookmarked = bookmarkCategoriesDao.doesExist(categoryName)
|
||||||
|
_bookmarkState.update {
|
||||||
|
isBookmarked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles event when bookmark button is clicked from view
|
||||||
|
* based on that category is bookmarked or removed in/from in the DB
|
||||||
|
* and bookmark state is update as well
|
||||||
|
* @param categoryName
|
||||||
|
*/
|
||||||
|
fun onBookmarkClick(categoryName: String) {
|
||||||
|
if (_bookmarkState.value) {
|
||||||
|
deleteBookmark(categoryName)
|
||||||
|
_bookmarkState.update {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addBookmark(categoryName)
|
||||||
|
_bookmarkState.update {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add bookmark into DB
|
||||||
|
*
|
||||||
|
* @param categoryName
|
||||||
|
*/
|
||||||
|
private fun addBookmark(categoryName: String) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val categoryItem = BookmarksCategoryModal(
|
||||||
|
categoryName = categoryName
|
||||||
|
)
|
||||||
|
|
||||||
|
bookmarkCategoriesDao.insert(categoryItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete bookmark from DB
|
||||||
|
*
|
||||||
|
* @param categoryName
|
||||||
|
*/
|
||||||
|
private fun deleteBookmark(categoryName: String) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
bookmarkCategoriesDao.delete(
|
||||||
|
BookmarksCategoryModal(
|
||||||
|
categoryName = categoryName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View model factory to create [CategoryDetailsViewModel]
|
||||||
|
*
|
||||||
|
* @property bookmarkCategoriesDao
|
||||||
|
* @constructor Create empty View model factory
|
||||||
|
*/
|
||||||
|
class ViewModelFactory @Inject constructor(
|
||||||
|
private val bookmarkCategoriesDao: BookmarkCategoriesDao
|
||||||
|
) : ViewModelProvider.Factory {
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T =
|
||||||
|
if (modelClass.isAssignableFrom(CategoryDetailsViewModel::class.java)) {
|
||||||
|
CategoryDetailsViewModel(bookmarkCategoriesDao) as T
|
||||||
|
} else {
|
||||||
|
throw IllegalArgumentException("Unknown class name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,8 @@ package fr.free.nrw.commons.db
|
||||||
import androidx.room.Database
|
import androidx.room.Database
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import androidx.room.TypeConverters
|
import androidx.room.TypeConverters
|
||||||
|
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao
|
||||||
|
import fr.free.nrw.commons.bookmarks.category.BookmarksCategoryModal
|
||||||
import fr.free.nrw.commons.contributions.Contribution
|
import fr.free.nrw.commons.contributions.Contribution
|
||||||
import fr.free.nrw.commons.contributions.ContributionDao
|
import fr.free.nrw.commons.contributions.ContributionDao
|
||||||
import fr.free.nrw.commons.customselector.database.NotForUploadStatus
|
import fr.free.nrw.commons.customselector.database.NotForUploadStatus
|
||||||
|
|
@ -21,8 +23,8 @@ import fr.free.nrw.commons.upload.depicts.DepictsDao
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Database(
|
@Database(
|
||||||
entities = [Contribution::class, Depicts::class, UploadedStatus::class, NotForUploadStatus::class, ReviewEntity::class, Place::class],
|
entities = [Contribution::class, Depicts::class, UploadedStatus::class, NotForUploadStatus::class, ReviewEntity::class, Place::class, BookmarksCategoryModal::class],
|
||||||
version = 18,
|
version = 19,
|
||||||
exportSchema = false,
|
exportSchema = false,
|
||||||
)
|
)
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
|
|
@ -38,4 +40,6 @@ abstract class AppDatabase : RoomDatabase() {
|
||||||
abstract fun NotForUploadStatusDao(): NotForUploadStatusDao
|
abstract fun NotForUploadStatusDao(): NotForUploadStatusDao
|
||||||
|
|
||||||
abstract fun ReviewDao(): ReviewDao
|
abstract fun ReviewDao(): ReviewDao
|
||||||
|
|
||||||
|
abstract fun bookmarkCategoriesDao(): BookmarkCategoriesDao
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import dagger.Provides
|
||||||
import fr.free.nrw.commons.BuildConfig
|
import fr.free.nrw.commons.BuildConfig
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.auth.SessionManager
|
import fr.free.nrw.commons.auth.SessionManager
|
||||||
|
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao
|
||||||
import fr.free.nrw.commons.contributions.ContributionDao
|
import fr.free.nrw.commons.contributions.ContributionDao
|
||||||
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
|
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
|
||||||
import fr.free.nrw.commons.customselector.database.UploadedStatusDao
|
import fr.free.nrw.commons.customselector.database.UploadedStatusDao
|
||||||
|
|
@ -221,6 +222,10 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
|
||||||
fun providesReviewDao(appDatabase: AppDatabase): ReviewDao =
|
fun providesReviewDao(appDatabase: AppDatabase): ReviewDao =
|
||||||
appDatabase.ReviewDao()
|
appDatabase.ReviewDao()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun providesBookmarkCategoriesDao (appDatabase: AppDatabase): BookmarkCategoriesDao =
|
||||||
|
appDatabase.bookmarkCategoriesDao()
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun providesContentResolver(context: Context): ContentResolver =
|
fun providesContentResolver(context: Context): ContentResolver =
|
||||||
context.contentResolver
|
context.contentResolver
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import fr.free.nrw.commons.bookmarks.BookmarkFragment
|
import fr.free.nrw.commons.bookmarks.BookmarkFragment
|
||||||
import fr.free.nrw.commons.bookmarks.BookmarkListRootFragment
|
import fr.free.nrw.commons.bookmarks.BookmarkListRootFragment
|
||||||
|
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesFragment
|
||||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsFragment
|
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsFragment
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsFragment
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsFragment
|
||||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment
|
||||||
|
|
@ -97,6 +98,9 @@ abstract class FragmentBuilderModule {
|
||||||
@ContributesAndroidInjector(modules = [BookmarkItemsFragmentModule::class])
|
@ContributesAndroidInjector(modules = [BookmarkItemsFragmentModule::class])
|
||||||
abstract fun bindBookmarkItemListFragment(): BookmarkItemsFragment
|
abstract fun bindBookmarkItemListFragment(): BookmarkItemsFragment
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindBookmarkCategoriesListFragment(): BookmarkCategoriesFragment
|
||||||
|
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindReviewOutOfContextFragment(): ReviewImageFragment
|
abstract fun bindReviewOutOfContextFragment(): ReviewImageFragment
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
android:layout_below="@id/toolbar"
|
android:layout_below="@id/toolbar"
|
||||||
android:background="?attr/tabBackground"
|
android:background="?attr/tabBackground"
|
||||||
app:tabIndicatorColor="?attr/tabIndicatorColor"
|
app:tabIndicatorColor="?attr/tabIndicatorColor"
|
||||||
app:tabMode="fixed"
|
app:tabMode="scrollable"
|
||||||
app:tabSelectedTextColor="?attr/tabSelectedTextColor"
|
app:tabSelectedTextColor="?attr/tabSelectedTextColor"
|
||||||
app:tabTextColor="?attr/tabTextColor" />
|
app:tabTextColor="?attr/tabTextColor" />
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,12 @@
|
||||||
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_bookmark_current_category"
|
||||||
|
android:title="@string/menu_bookmark"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_browser_current_category"
|
android:id="@+id/menu_browser_current_category"
|
||||||
android:title="@string/menu_view_category_page"
|
android:title="@string/menu_view_category_page"
|
||||||
|
|
|
||||||
|
|
@ -415,6 +415,7 @@
|
||||||
<string name="map_application_missing">No compatible map application could be found on your device. Please install a map application to use this feature.</string>
|
<string name="map_application_missing">No compatible map application could be found on your device. Please install a map application to use this feature.</string>
|
||||||
<string name="title_page_bookmarks_pictures">Pictures</string>
|
<string name="title_page_bookmarks_pictures">Pictures</string>
|
||||||
<string name="title_page_bookmarks_locations">Locations</string>
|
<string name="title_page_bookmarks_locations">Locations</string>
|
||||||
|
<string name="title_page_bookmarks_categories">Categories</string>
|
||||||
<string name="menu_bookmark">Add/Remove to bookmarks</string>
|
<string name="menu_bookmark">Add/Remove to bookmarks</string>
|
||||||
<string name="provider_bookmarks">Bookmarks</string>
|
<string name="provider_bookmarks">Bookmarks</string>
|
||||||
<string name="bookmark_empty">You haven\'t added any bookmarks</string>
|
<string name="bookmark_empty">You haven\'t added any bookmarks</string>
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ class BookmarksPagerAdapterTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testGetCount() {
|
fun testGetCount() {
|
||||||
Assert.assertEquals(bookmarksPagerAdapter.count, 3)
|
Assert.assertEquals(bookmarksPagerAdapter.count, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class LoggedOutBookmarksPagerAdapterTests {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun testGetCount() {
|
fun testGetCount() {
|
||||||
Assert.assertEquals(bookmarksPagerAdapter.count, 1)
|
Assert.assertEquals(bookmarksPagerAdapter.count, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue