From f908f71a7e7af7b6046b911f716553ef71ad52cb Mon Sep 17 00:00:00 2001 From: parneet-guraya Date: Sun, 15 Dec 2024 22:42:58 +0530 Subject: [PATCH 1/8] database setup and insert/delete working Signed-off-by: parneet-guraya --- .../category/BookmarkCategoriesDao.kt | 26 +++++++ .../category/BookmarkCategoriesFragment.kt | 26 +++++++ .../category/BookmarkCategoriesViewModel.kt | 9 +++ .../models/BookmarksCategoryModal.kt | 9 +++ .../category/CategoryDetailsActivity.kt | 45 +++++++++++ .../category/CategoryDetailsViewModel.kt | 77 +++++++++++++++++++ .../fr/free/nrw/commons/db/AppDatabase.kt | 6 +- .../commons/di/CommonsApplicationModule.kt | 5 ++ .../layout/fragment_bookmark_categories.xml | 14 ++++ .../res/menu/fragment_category_detail.xml | 7 ++ 10 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt create mode 100644 app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt create mode 100644 app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesViewModel.kt create mode 100644 app/src/main/java/fr/free/nrw/commons/bookmarks/models/BookmarksCategoryModal.kt create mode 100644 app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt create mode 100644 app/src/main/res/layout/fragment_bookmark_categories.xml diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt new file mode 100644 index 0000000000..870c0556f1 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt @@ -0,0 +1,26 @@ +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 fr.free.nrw.commons.bookmarks.models.BookmarksCategoryModal +import kotlinx.coroutines.flow.Flow + +@Dao +interface BookmarkCategoriesDao { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(bookmarksCategoryModal: BookmarksCategoryModal) + + @Delete + suspend fun delete(bookmarksCategoryModal: BookmarksCategoryModal) + + @Query("SELECT EXISTS (SELECT 1 FROM bookmarks_categories WHERE categoryName = :categoryName)") + suspend fun doesExist(categoryName: String): Boolean + + @Query("SELECT * FROM bookmarks_categories") + fun getAllCategories(): Flow> + +} diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt new file mode 100644 index 0000000000..7e5c04db99 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt @@ -0,0 +1,26 @@ +package fr.free.nrw.commons.bookmarks.category + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import dagger.android.support.DaggerFragment +import fr.free.nrw.commons.R + + +class BookmarkCategoriesFragment : DaggerFragment() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_bookmark_categories, container, false) + } + + companion object { + @JvmStatic + fun newInstance(param1: String, param2: String) = + BookmarkCategoriesFragment() + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesViewModel.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesViewModel.kt new file mode 100644 index 0000000000..5967813b39 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesViewModel.kt @@ -0,0 +1,9 @@ +package fr.free.nrw.commons.bookmarks.category + +class BookmarkCategoriesViewModel( + +) { + + + +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/models/BookmarksCategoryModal.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/models/BookmarksCategoryModal.kt new file mode 100644 index 0000000000..2958037203 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/models/BookmarksCategoryModal.kt @@ -0,0 +1,9 @@ +package fr.free.nrw.commons.bookmarks.models + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "bookmarks_categories") +data class BookmarksCategoryModal( + @PrimaryKey val categoryName: String +) \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt index ba1fcfdae2..13934d7748 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt @@ -7,8 +7,12 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View +import androidx.activity.viewModels import androidx.fragment.app.Fragment 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.R 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.media.MediaDetailPagerFragment 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 + @Inject + lateinit var categoryViewModelFactory: CategoryDetailsViewModel.ViewModelFactory + + private val viewModel: CategoryDetailsViewModel by viewModels { categoryViewModelFactory } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -53,6 +64,15 @@ class CategoryDetailsActivity : BaseActivity(), supportActionBar?.setDisplayHomeAsUpEnabled(true) setTabs() setPageTitle() + + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED){ + viewModel.bookmarkState.collect { + invalidateOptionsMenu() + } + } + } + } /** @@ -73,6 +93,8 @@ class CategoryDetailsActivity : BaseActivity(), categoriesMediaFragment.arguments = arguments subCategoryListFragment.arguments = arguments parentCategoriesFragment.arguments = arguments + + viewModel.onCheckIfBookmarked(categoryName!!) } fragmentList.add(categoriesMediaFragment) titleList.add("MEDIA") @@ -181,6 +203,15 @@ class CategoryDetailsActivity : BaseActivity(), Utils.handleWebUrl(this, Uri.parse(title.canonicalUri)) true } + + R.id.menu_bookmark_current_category -> { + //TODO: most likely won't be null + categoryName?.let { + viewModel.onBookmarkClick(categoryName = it) + } + true + } + android.R.id.home -> { onBackPressed() true @@ -189,6 +220,20 @@ class CategoryDetailsActivity : BaseActivity(), } } + override fun onPrepareOptionsMenu(menu: Menu?): Boolean { + menu?.run { + val bookmarkMenuItem = findItem(R.id.menu_bookmark_current_category) + 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. * If condition is called when mediaDetailFragment is opened. diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt new file mode 100644 index 0000000000..fd3220b0ed --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt @@ -0,0 +1,77 @@ +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.models.BookmarksCategoryModal +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import javax.inject.Inject + +class CategoryDetailsViewModel( + private val bookmarkCategoriesDao: BookmarkCategoriesDao +) : ViewModel() { + + private val _bookmarkState = MutableStateFlow(false) + val bookmarkState = _bookmarkState.asStateFlow() + + fun onCheckIfBookmarked(categoryName: String) { + viewModelScope.launch { + val isBookmarked = bookmarkCategoriesDao.doesExist(categoryName) + _bookmarkState.update { + isBookmarked + } + } + } + + fun onBookmarkClick(categoryName: String) { + if (_bookmarkState.value) { + deleteBookmark(categoryName) + _bookmarkState.update { + false + } + } else { + addBookmark(categoryName) + _bookmarkState.update { + true + } + } + } + + private fun addBookmark(categoryName: String) { + viewModelScope.launch { + // TODO [Parry] view only knows about `name` see if we can have more data + val categoryItem = BookmarksCategoryModal( + categoryName = categoryName + ) + + bookmarkCategoriesDao.insert(categoryItem) + } + } + + private fun deleteBookmark(categoryName: String) { + viewModelScope.launch { + bookmarkCategoriesDao.delete( + BookmarksCategoryModal( + categoryName = categoryName + ) + ) + } + } + + class ViewModelFactory @Inject constructor( + private val bookmarkCategoriesDao: BookmarkCategoriesDao + ) : ViewModelProvider.Factory { + + @Suppress("UNCHECKED_CAST") + override fun create(modelClass: Class): T = + if (modelClass.isAssignableFrom(CategoryDetailsViewModel::class.java)) { + CategoryDetailsViewModel(bookmarkCategoriesDao) as T + } else { + throw IllegalArgumentException("Unknown class name") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt b/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt index 71947fa1a6..6222f2462c 100644 --- a/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt +++ b/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt @@ -3,6 +3,8 @@ package fr.free.nrw.commons.db import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.TypeConverters +import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao +import fr.free.nrw.commons.bookmarks.models.BookmarksCategoryModal import fr.free.nrw.commons.contributions.Contribution import fr.free.nrw.commons.contributions.ContributionDao import fr.free.nrw.commons.customselector.database.NotForUploadStatus @@ -21,7 +23,7 @@ import fr.free.nrw.commons.upload.depicts.DepictsDao * */ @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, exportSchema = false, ) @@ -38,4 +40,6 @@ abstract class AppDatabase : RoomDatabase() { abstract fun NotForUploadStatusDao(): NotForUploadStatusDao abstract fun ReviewDao(): ReviewDao + + abstract fun bookmarkCategoriesDao(): BookmarkCategoriesDao } diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.kt b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.kt index b195674a99..58d9039d53 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.kt +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.kt @@ -15,6 +15,7 @@ import dagger.Provides import fr.free.nrw.commons.BuildConfig import fr.free.nrw.commons.R 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.customselector.database.NotForUploadStatusDao import fr.free.nrw.commons.customselector.database.UploadedStatusDao @@ -221,6 +222,10 @@ open class CommonsApplicationModule(private val applicationContext: Context) { fun providesReviewDao(appDatabase: AppDatabase): ReviewDao = appDatabase.ReviewDao() + @Provides + fun providesBookmarkCategoriesDao (appDatabase: AppDatabase): BookmarkCategoriesDao = + appDatabase.bookmarkCategoriesDao() + @Provides fun providesContentResolver(context: Context): ContentResolver = context.contentResolver diff --git a/app/src/main/res/layout/fragment_bookmark_categories.xml b/app/src/main/res/layout/fragment_bookmark_categories.xml new file mode 100644 index 0000000000..5838e8b037 --- /dev/null +++ b/app/src/main/res/layout/fragment_bookmark_categories.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/fragment_category_detail.xml b/app/src/main/res/menu/fragment_category_detail.xml index 386e678fd3..b3663ee97f 100644 --- a/app/src/main/res/menu/fragment_category_detail.xml +++ b/app/src/main/res/menu/fragment_category_detail.xml @@ -2,6 +2,13 @@ + + + Date: Sun, 15 Dec 2024 23:48:15 +0530 Subject: [PATCH 2/8] add new categories screen in bookmarks page Signed-off-by: parneet-guraya --- .../bookmarks/BookmarkListRootFragment.java | 19 ++-- .../bookmarks/BookmarksPagerAdapter.java | 7 ++ .../category/BookmarkCategoriesFragment.kt | 99 +++++++++++++++++-- .../nrw/commons/di/FragmentBuilderModule.kt | 4 + .../layout/fragment_bookmark_categories.xml | 14 --- .../res/menu/fragment_category_detail.xml | 1 - app/src/main/res/values/strings.xml | 1 + 7 files changed, 116 insertions(+), 29 deletions(-) delete mode 100644 app/src/main/res/layout/fragment_bookmark_categories.xml diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/BookmarkListRootFragment.java b/app/src/main/java/fr/free/nrw/commons/bookmarks/BookmarkListRootFragment.java index 281248ca45..8b66a104a7 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/BookmarkListRootFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/BookmarkListRootFragment.java @@ -7,13 +7,13 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; -import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import fr.free.nrw.commons.Media; 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.locations.BookmarkLocationsFragment; import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment; @@ -48,14 +48,21 @@ public BookmarkListRootFragment(Bundle bundle, BookmarksPagerAdapter bookmarksPa String title = bundle.getString("categoryName"); int order = bundle.getInt("order"); final int orderItem = bundle.getInt("orderItem"); - if (order == 0) { - listFragment = new BookmarkPicturesFragment(); - } else { - listFragment = new BookmarkLocationsFragment(); + + switch (order){ + case 0: listFragment = new BookmarkPicturesFragment(); + break; + + case 1: listFragment = new BookmarkLocationsFragment(); + break; + + case 3: listFragment = new BookmarkCategoriesFragment(); + break; + } if(orderItem == 2) { listFragment = new BookmarkItemsFragment(); } - } + Bundle featuredArguments = new Bundle(); featuredArguments.putString("categoryName", title); listFragment.setArguments(featuredArguments); diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/BookmarksPagerAdapter.java b/app/src/main/java/fr/free/nrw/commons/bookmarks/BookmarksPagerAdapter.java index ea3a9a453a..f0620032a1 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/BookmarksPagerAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/BookmarksPagerAdapter.java @@ -49,6 +49,13 @@ public class BookmarksPagerAdapter extends FragmentPagerAdapter { new BookmarkListRootFragment(locationBundle, this), 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(); } diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt index 7e5c04db99..f523c8b2f9 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt @@ -1,26 +1,109 @@ 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.clickable +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.Icon +import androidx.compose.material3.ListItem +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +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 class BookmarkCategoriesFragment : DaggerFragment() { + @Inject + lateinit var bookmarkCategoriesDao: BookmarkCategoriesDao + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { - // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_bookmark_categories, container, false) + ): View { + return ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + MaterialTheme { + 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)) + } else { + LazyColumn { + 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 = { + Icon( + modifier = Modifier.size(48.dp), + painter = painterResource(R.drawable.commons), + contentDescription = null + ) + }, + headlineContent = { + Text(text = categoryName) + } + ) + } } - companion object { - @JvmStatic - fun newInstance(param1: String, param2: String) = - BookmarkCategoriesFragment() + @Preview + @Composable + private fun CategoryItemPreview() { + CategoryItem(onClick = {}, categoryName = "Test Category") } -} \ No newline at end of file +} diff --git a/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.kt b/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.kt index bfdb90181a..0ef34e3551 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.kt +++ b/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.kt @@ -4,6 +4,7 @@ import dagger.Module import dagger.android.ContributesAndroidInjector import fr.free.nrw.commons.bookmarks.BookmarkFragment 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.locations.BookmarkLocationsFragment import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment @@ -97,6 +98,9 @@ abstract class FragmentBuilderModule { @ContributesAndroidInjector(modules = [BookmarkItemsFragmentModule::class]) abstract fun bindBookmarkItemListFragment(): BookmarkItemsFragment + @ContributesAndroidInjector + abstract fun bindBookmarkCategoriesListFragment(): BookmarkCategoriesFragment + @ContributesAndroidInjector abstract fun bindReviewOutOfContextFragment(): ReviewImageFragment diff --git a/app/src/main/res/layout/fragment_bookmark_categories.xml b/app/src/main/res/layout/fragment_bookmark_categories.xml deleted file mode 100644 index 5838e8b037..0000000000 --- a/app/src/main/res/layout/fragment_bookmark_categories.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/fragment_category_detail.xml b/app/src/main/res/menu/fragment_category_detail.xml index b3663ee97f..0d2624238e 100644 --- a/app/src/main/res/menu/fragment_category_detail.xml +++ b/app/src/main/res/menu/fragment_category_detail.xml @@ -5,7 +5,6 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4bf76c4050..2137a1c603 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -415,6 +415,7 @@ No compatible map application could be found on your device. Please install a map application to use this feature. Pictures Locations + Categories Add/Remove to bookmarks Bookmarks You haven\'t added any bookmarks From 477b1728a4cea52d0cc3d9cad2b0faaf71039cab Mon Sep 17 00:00:00 2001 From: parneet-guraya Date: Mon, 16 Dec 2024 01:01:44 +0530 Subject: [PATCH 3/8] add theme Signed-off-by: parneet-guraya --- .../category/BookmarkCategoriesFragment.kt | 46 ++++++++++++++++--- .../category/CategoryDetailsActivity.kt | 14 +++--- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt index f523c8b2f9..857222e9d9 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt @@ -5,26 +5,32 @@ 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.Icon 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 @@ -46,15 +52,32 @@ class BookmarkCategoriesFragment : DaggerFragment() { return ComposeView(requireContext()).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { - MaterialTheme { + 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)) + Text( + text = stringResource(R.string.bookmark_empty), + style = MaterialTheme.typography.bodyMedium, + color = if (isSystemInDarkTheme()) Color(0xB3FFFFFF) + else Color( + 0x8A000000 + ) + ) } else { - LazyColumn { + LazyColumn(modifier = Modifier.fillMaxSize()) { items(items = listOfBookmarks) { bookmarkItem -> CategoryItem( categoryName = bookmarkItem.categoryName, @@ -88,14 +111,20 @@ class BookmarkCategoriesFragment : DaggerFragment() { }) { ListItem( leadingContent = { - Icon( + Image( modifier = Modifier.size(48.dp), painter = painterResource(R.drawable.commons), contentDescription = null ) }, headlineContent = { - Text(text = categoryName) + Text( + text = categoryName, + maxLines = 2, + color = if (isSystemInDarkTheme()) Color.White else Color.Black, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.SemiBold + ) } ) } @@ -104,6 +133,9 @@ class BookmarkCategoriesFragment : DaggerFragment() { @Preview @Composable private fun CategoryItemPreview() { - CategoryItem(onClick = {}, categoryName = "Test Category") + CategoryItem( + onClick = {}, + categoryName = "Test Category" + ) } } diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt index 13934d7748..cd13953fc7 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt @@ -223,13 +223,15 @@ class CategoryDetailsActivity : BaseActivity(), override fun onPrepareOptionsMenu(menu: Menu?): Boolean { menu?.run { val bookmarkMenuItem = findItem(R.id.menu_bookmark_current_category) - val icon = if(viewModel.bookmarkState.value){ - R.drawable.menu_ic_round_star_filled_24px - } else { - R.drawable.menu_ic_round_star_border_24px - } + 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) + bookmarkMenuItem.setIcon(icon) + } } return super.onPrepareOptionsMenu(menu) } From 2daca3aa98621ad311199845c87a85aa31d6581b Mon Sep 17 00:00:00 2001 From: parneet-guraya Date: Mon, 16 Dec 2024 01:12:33 +0530 Subject: [PATCH 4/8] set tab layout scrollable Signed-off-by: parneet-guraya --- app/src/main/res/layout/fragment_bookmarks.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/fragment_bookmarks.xml b/app/src/main/res/layout/fragment_bookmarks.xml index 930faf5922..1ffb7bc5d9 100644 --- a/app/src/main/res/layout/fragment_bookmarks.xml +++ b/app/src/main/res/layout/fragment_bookmarks.xml @@ -17,7 +17,7 @@ android:layout_below="@id/toolbar" android:background="?attr/tabBackground" app:tabIndicatorColor="?attr/tabIndicatorColor" - app:tabMode="fixed" + app:tabMode="scrollable" app:tabSelectedTextColor="?attr/tabSelectedTextColor" app:tabTextColor="?attr/tabTextColor" /> From c89469e208c1221559d03a7d2a8e9d3a4fda25ab Mon Sep 17 00:00:00 2001 From: parneet-guraya Date: Mon, 16 Dec 2024 01:23:44 +0530 Subject: [PATCH 5/8] cleanup Signed-off-by: parneet-guraya --- .../commons/bookmarks/category/BookmarkCategoriesDao.kt | 1 - .../bookmarks/category/BookmarkCategoriesViewModel.kt | 9 --------- .../{models => category}/BookmarksCategoryModal.kt | 4 ++-- .../free/nrw/commons/category/CategoryDetailsActivity.kt | 1 - .../nrw/commons/category/CategoryDetailsViewModel.kt | 5 ++--- app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt | 2 +- 6 files changed, 5 insertions(+), 17 deletions(-) delete mode 100644 app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesViewModel.kt rename app/src/main/java/fr/free/nrw/commons/bookmarks/{models => category}/BookmarksCategoryModal.kt (78%) diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt index 870c0556f1..611ae3ca08 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt @@ -5,7 +5,6 @@ import androidx.room.Delete import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query -import fr.free.nrw.commons.bookmarks.models.BookmarksCategoryModal import kotlinx.coroutines.flow.Flow @Dao diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesViewModel.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesViewModel.kt deleted file mode 100644 index 5967813b39..0000000000 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesViewModel.kt +++ /dev/null @@ -1,9 +0,0 @@ -package fr.free.nrw.commons.bookmarks.category - -class BookmarkCategoriesViewModel( - -) { - - - -} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/models/BookmarksCategoryModal.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarksCategoryModal.kt similarity index 78% rename from app/src/main/java/fr/free/nrw/commons/bookmarks/models/BookmarksCategoryModal.kt rename to app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarksCategoryModal.kt index 2958037203..966b846dd8 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/models/BookmarksCategoryModal.kt +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarksCategoryModal.kt @@ -1,4 +1,4 @@ -package fr.free.nrw.commons.bookmarks.models +package fr.free.nrw.commons.bookmarks.category import androidx.room.Entity import androidx.room.PrimaryKey @@ -6,4 +6,4 @@ import androidx.room.PrimaryKey @Entity(tableName = "bookmarks_categories") data class BookmarksCategoryModal( @PrimaryKey val categoryName: String -) \ No newline at end of file +) diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt index cd13953fc7..a42d26fd62 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt @@ -205,7 +205,6 @@ class CategoryDetailsActivity : BaseActivity(), } R.id.menu_bookmark_current_category -> { - //TODO: most likely won't be null categoryName?.let { viewModel.onBookmarkClick(categoryName = it) } diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt index fd3220b0ed..e4d010ec10 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt @@ -4,7 +4,7 @@ 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.models.BookmarksCategoryModal +import fr.free.nrw.commons.bookmarks.category.BookmarksCategoryModal import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update @@ -43,7 +43,6 @@ class CategoryDetailsViewModel( private fun addBookmark(categoryName: String) { viewModelScope.launch { - // TODO [Parry] view only knows about `name` see if we can have more data val categoryItem = BookmarksCategoryModal( categoryName = categoryName ) @@ -74,4 +73,4 @@ class CategoryDetailsViewModel( throw IllegalArgumentException("Unknown class name") } } -} \ No newline at end of file +} diff --git a/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt b/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt index 6222f2462c..6ca71239aa 100644 --- a/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt +++ b/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt @@ -4,7 +4,7 @@ import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.TypeConverters import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao -import fr.free.nrw.commons.bookmarks.models.BookmarksCategoryModal +import fr.free.nrw.commons.bookmarks.category.BookmarksCategoryModal import fr.free.nrw.commons.contributions.Contribution import fr.free.nrw.commons.contributions.ContributionDao import fr.free.nrw.commons.customselector.database.NotForUploadStatus From 1c2ac9065b0a8b45933cc727d93bd8fdce135b43 Mon Sep 17 00:00:00 2001 From: parneet-guraya Date: Mon, 16 Dec 2024 02:13:22 +0530 Subject: [PATCH 6/8] fix tests Signed-off-by: parneet-guraya --- .../fr/free/nrw/commons/bookmarks/BookmarksPagerAdapterTests.kt | 2 +- .../commons/bookmarks/LoggedOutBookmarksPagerAdapterTests.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/BookmarksPagerAdapterTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/BookmarksPagerAdapterTests.kt index 9423c90958..bf143ecc06 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/BookmarksPagerAdapterTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/BookmarksPagerAdapterTests.kt @@ -37,7 +37,7 @@ class BookmarksPagerAdapterTests { @Test fun testGetCount() { - Assert.assertEquals(bookmarksPagerAdapter.count, 3) + Assert.assertEquals(bookmarksPagerAdapter.count, 4) } @Test diff --git a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/LoggedOutBookmarksPagerAdapterTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/LoggedOutBookmarksPagerAdapterTests.kt index 4c20bdda93..7ba7d559e7 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/LoggedOutBookmarksPagerAdapterTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/bookmarks/LoggedOutBookmarksPagerAdapterTests.kt @@ -53,7 +53,7 @@ class LoggedOutBookmarksPagerAdapterTests { */ @Test fun testGetCount() { - Assert.assertEquals(bookmarksPagerAdapter.count, 1) + Assert.assertEquals(bookmarksPagerAdapter.count, 2) } /** From 325cb2264b7e61e549f6a174cbf89a48f495ff29 Mon Sep 17 00:00:00 2001 From: parneet-guraya Date: Mon, 16 Dec 2024 02:50:27 +0530 Subject: [PATCH 7/8] bump database version Signed-off-by: parneet-guraya --- app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt b/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt index 6ca71239aa..0c34bbdec3 100644 --- a/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt +++ b/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt @@ -24,7 +24,7 @@ import fr.free.nrw.commons.upload.depicts.DepictsDao */ @Database( entities = [Contribution::class, Depicts::class, UploadedStatus::class, NotForUploadStatus::class, ReviewEntity::class, Place::class, BookmarksCategoryModal::class], - version = 18, + version = 19, exportSchema = false, ) @TypeConverters(Converters::class) From d1b6dc28d953507fc45366d1ec1a8db473f1b78f Mon Sep 17 00:00:00 2001 From: parneet-guraya Date: Tue, 17 Dec 2024 16:58:15 +0530 Subject: [PATCH 8/8] add docs Signed-off-by: parneet-guraya --- .../category/BookmarkCategoriesDao.kt | 27 +++++++++++++++ .../category/BookmarkCategoriesFragment.kt | 4 ++- .../category/BookmarksCategoryModal.kt | 6 ++++ .../category/CategoryDetailsViewModel.kt | 33 +++++++++++++++++++ 4 files changed, 69 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt index 611ae3ca08..71a2d1ec98 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesDao.kt @@ -7,18 +7,45 @@ 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> diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt index 857222e9d9..ef5bc613df 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarkCategoriesFragment.kt @@ -39,7 +39,9 @@ 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 diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarksCategoryModal.kt b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarksCategoryModal.kt index 966b846dd8..ab679611f0 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarksCategoryModal.kt +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/category/BookmarksCategoryModal.kt @@ -3,6 +3,12 @@ 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 diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt index e4d010ec10..a50f25669c 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsViewModel.kt @@ -11,6 +11,9 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import javax.inject.Inject +/** + * ViewModal for [CategoryDetailsActivity] + */ class CategoryDetailsViewModel( private val bookmarkCategoriesDao: BookmarkCategoriesDao ) : ViewModel() { @@ -18,6 +21,12 @@ class CategoryDetailsViewModel( 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) @@ -27,6 +36,12 @@ class CategoryDetailsViewModel( } } + /** + * 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) @@ -41,6 +56,12 @@ class CategoryDetailsViewModel( } } + + /** + * Add bookmark into DB + * + * @param categoryName + */ private fun addBookmark(categoryName: String) { viewModelScope.launch { val categoryItem = BookmarksCategoryModal( @@ -51,6 +72,12 @@ class CategoryDetailsViewModel( } } + + /** + * Delete bookmark from DB + * + * @param categoryName + */ private fun deleteBookmark(categoryName: String) { viewModelScope.launch { bookmarkCategoriesDao.delete( @@ -61,6 +88,12 @@ class CategoryDetailsViewModel( } } + /** + * View model factory to create [CategoryDetailsViewModel] + * + * @property bookmarkCategoriesDao + * @constructor Create empty View model factory + */ class ViewModelFactory @Inject constructor( private val bookmarkCategoriesDao: BookmarkCategoriesDao ) : ViewModelProvider.Factory {