Skip to content

Commit cd9e724

Browse files
authored
Merge branch 'main' into nearby/performance-experiments
2 parents f19352b + a4b7479 commit cd9e724

30 files changed

+467
-13
lines changed

app/src/main/java/fr/free/nrw/commons/bookmarks/BookmarkListRootFragment.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
import android.view.View;
88
import android.view.ViewGroup;
99
import android.widget.AdapterView;
10-
import android.widget.FrameLayout;
1110
import androidx.annotation.NonNull;
1211
import androidx.annotation.Nullable;
1312
import androidx.fragment.app.Fragment;
1413
import androidx.fragment.app.FragmentManager;
1514
import fr.free.nrw.commons.Media;
1615
import fr.free.nrw.commons.R;
16+
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesFragment;
1717
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsFragment;
1818
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsFragment;
1919
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment;
@@ -48,14 +48,21 @@ public BookmarkListRootFragment(Bundle bundle, BookmarksPagerAdapter bookmarksPa
4848
String title = bundle.getString("categoryName");
4949
int order = bundle.getInt("order");
5050
final int orderItem = bundle.getInt("orderItem");
51-
if (order == 0) {
52-
listFragment = new BookmarkPicturesFragment();
53-
} else {
54-
listFragment = new BookmarkLocationsFragment();
51+
52+
switch (order){
53+
case 0: listFragment = new BookmarkPicturesFragment();
54+
break;
55+
56+
case 1: listFragment = new BookmarkLocationsFragment();
57+
break;
58+
59+
case 3: listFragment = new BookmarkCategoriesFragment();
60+
break;
61+
}
5562
if(orderItem == 2) {
5663
listFragment = new BookmarkItemsFragment();
5764
}
58-
}
65+
5966
Bundle featuredArguments = new Bundle();
6067
featuredArguments.putString("categoryName", title);
6168
listFragment.setArguments(featuredArguments);

app/src/main/java/fr/free/nrw/commons/bookmarks/BookmarksPagerAdapter.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ public class BookmarksPagerAdapter extends FragmentPagerAdapter {
4949
new BookmarkListRootFragment(locationBundle, this),
5050
context.getString(R.string.title_page_bookmarks_items)));
5151
}
52+
final Bundle categoriesBundle = new Bundle();
53+
categoriesBundle.putString("categoryName",
54+
context.getString(R.string.title_page_bookmarks_categories));
55+
categoriesBundle.putInt("order", 3);
56+
pages.add(new BookmarkPages(
57+
new BookmarkListRootFragment(categoriesBundle, this),
58+
context.getString(R.string.title_page_bookmarks_categories)));
5259
notifyDataSetChanged();
5360
}
5461

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package fr.free.nrw.commons.bookmarks.category
2+
3+
import androidx.room.Dao
4+
import androidx.room.Delete
5+
import androidx.room.Insert
6+
import androidx.room.OnConflictStrategy
7+
import androidx.room.Query
8+
import kotlinx.coroutines.flow.Flow
9+
10+
/**
11+
* Bookmark categories dao
12+
*
13+
* @constructor Create empty Bookmark categories dao
14+
*/
15+
@Dao
16+
interface BookmarkCategoriesDao {
17+
18+
/**
19+
* Insert or Delete category bookmark into DB
20+
*
21+
* @param bookmarksCategoryModal
22+
*/
23+
@Insert(onConflict = OnConflictStrategy.REPLACE)
24+
suspend fun insert(bookmarksCategoryModal: BookmarksCategoryModal)
25+
26+
27+
/**
28+
* Delete category bookmark from DB
29+
*
30+
* @param bookmarksCategoryModal
31+
*/
32+
@Delete
33+
suspend fun delete(bookmarksCategoryModal: BookmarksCategoryModal)
34+
35+
/**
36+
* Checks if given category exist in DB
37+
*
38+
* @param categoryName
39+
* @return
40+
*/
41+
@Query("SELECT EXISTS (SELECT 1 FROM bookmarks_categories WHERE categoryName = :categoryName)")
42+
suspend fun doesExist(categoryName: String): Boolean
43+
44+
/**
45+
* Get all categories
46+
*
47+
* @return
48+
*/
49+
@Query("SELECT * FROM bookmarks_categories")
50+
fun getAllCategories(): Flow<List<BookmarksCategoryModal>>
51+
52+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package fr.free.nrw.commons.bookmarks.category
2+
3+
import android.content.Intent
4+
import android.os.Bundle
5+
import android.view.LayoutInflater
6+
import android.view.View
7+
import android.view.ViewGroup
8+
import androidx.compose.foundation.Image
9+
import androidx.compose.foundation.clickable
10+
import androidx.compose.foundation.isSystemInDarkTheme
11+
import androidx.compose.foundation.layout.Box
12+
import androidx.compose.foundation.layout.Row
13+
import androidx.compose.foundation.layout.fillMaxSize
14+
import androidx.compose.foundation.layout.size
15+
import androidx.compose.foundation.lazy.LazyColumn
16+
import androidx.compose.foundation.lazy.items
17+
import androidx.compose.material3.ListItem
18+
import androidx.compose.material3.MaterialTheme
19+
import androidx.compose.material3.Surface
20+
import androidx.compose.material3.Text
21+
import androidx.compose.material3.darkColorScheme
22+
import androidx.compose.material3.lightColorScheme
23+
import androidx.compose.runtime.Composable
24+
import androidx.compose.runtime.getValue
25+
import androidx.compose.ui.Alignment
26+
import androidx.compose.ui.Modifier
27+
import androidx.compose.ui.graphics.Color
28+
import androidx.compose.ui.platform.ComposeView
29+
import androidx.compose.ui.platform.ViewCompositionStrategy
30+
import androidx.compose.ui.res.colorResource
31+
import androidx.compose.ui.res.painterResource
32+
import androidx.compose.ui.res.stringResource
33+
import androidx.compose.ui.text.font.FontWeight
34+
import androidx.compose.ui.tooling.preview.Preview
35+
import androidx.compose.ui.unit.dp
36+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
37+
import dagger.android.support.DaggerFragment
38+
import fr.free.nrw.commons.R
39+
import fr.free.nrw.commons.category.CategoryDetailsActivity
40+
import javax.inject.Inject
41+
42+
/**
43+
* Tab fragment to show list of bookmarked Categories
44+
*/
45+
class BookmarkCategoriesFragment : DaggerFragment() {
46+
47+
@Inject
48+
lateinit var bookmarkCategoriesDao: BookmarkCategoriesDao
49+
50+
override fun onCreateView(
51+
inflater: LayoutInflater, container: ViewGroup?,
52+
savedInstanceState: Bundle?
53+
): View {
54+
return ComposeView(requireContext()).apply {
55+
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
56+
setContent {
57+
MaterialTheme(
58+
colorScheme = if (isSystemInDarkTheme()) darkColorScheme(
59+
primary = colorResource(R.color.primaryDarkColor),
60+
surface = colorResource(R.color.main_background_dark),
61+
background = colorResource(R.color.main_background_dark)
62+
) else lightColorScheme(
63+
primary = colorResource(R.color.primaryColor),
64+
surface = colorResource(R.color.main_background_light),
65+
background = colorResource(R.color.main_background_light)
66+
)
67+
) {
68+
val listOfBookmarks by bookmarkCategoriesDao.getAllCategories()
69+
.collectAsStateWithLifecycle(initialValue = emptyList())
70+
Surface(modifier = Modifier.fillMaxSize()) {
71+
Box(contentAlignment = Alignment.Center) {
72+
if (listOfBookmarks.isEmpty()) {
73+
Text(
74+
text = stringResource(R.string.bookmark_empty),
75+
style = MaterialTheme.typography.bodyMedium,
76+
color = if (isSystemInDarkTheme()) Color(0xB3FFFFFF)
77+
else Color(
78+
0x8A000000
79+
)
80+
)
81+
} else {
82+
LazyColumn(modifier = Modifier.fillMaxSize()) {
83+
items(items = listOfBookmarks) { bookmarkItem ->
84+
CategoryItem(
85+
categoryName = bookmarkItem.categoryName,
86+
onClick = {
87+
val categoryDetailsIntent = Intent(
88+
requireContext(),
89+
CategoryDetailsActivity::class.java
90+
).putExtra("categoryName", it)
91+
startActivity(categoryDetailsIntent)
92+
}
93+
)
94+
}
95+
}
96+
}
97+
}
98+
}
99+
}
100+
}
101+
}
102+
}
103+
104+
105+
@Composable
106+
fun CategoryItem(
107+
modifier: Modifier = Modifier,
108+
onClick: (String) -> Unit,
109+
categoryName: String
110+
) {
111+
Row(modifier = modifier.clickable {
112+
onClick(categoryName)
113+
}) {
114+
ListItem(
115+
leadingContent = {
116+
Image(
117+
modifier = Modifier.size(48.dp),
118+
painter = painterResource(R.drawable.commons),
119+
contentDescription = null
120+
)
121+
},
122+
headlineContent = {
123+
Text(
124+
text = categoryName,
125+
maxLines = 2,
126+
color = if (isSystemInDarkTheme()) Color.White else Color.Black,
127+
style = MaterialTheme.typography.bodyMedium,
128+
fontWeight = FontWeight.SemiBold
129+
)
130+
}
131+
)
132+
}
133+
}
134+
135+
@Preview
136+
@Composable
137+
private fun CategoryItemPreview() {
138+
CategoryItem(
139+
onClick = {},
140+
categoryName = "Test Category"
141+
)
142+
}
143+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package fr.free.nrw.commons.bookmarks.category
2+
3+
import androidx.room.Entity
4+
import androidx.room.PrimaryKey
5+
6+
/**
7+
* Data class representing bookmarked category in DB
8+
*
9+
* @property categoryName
10+
* @constructor Create empty Bookmarks category modal
11+
*/
12+
@Entity(tableName = "bookmarks_categories")
13+
data class BookmarksCategoryModal(
14+
@PrimaryKey val categoryName: String
15+
)

app/src/main/java/fr/free/nrw/commons/category/CategoryDetailsActivity.kt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ import android.os.Bundle
77
import android.view.Menu
88
import android.view.MenuItem
99
import android.view.View
10+
import androidx.activity.viewModels
1011
import androidx.fragment.app.Fragment
1112
import androidx.fragment.app.FragmentManager
13+
import androidx.lifecycle.Lifecycle
14+
import androidx.lifecycle.lifecycleScope
15+
import androidx.lifecycle.repeatOnLifecycle
1216
import fr.free.nrw.commons.Media
1317
import fr.free.nrw.commons.R
1418
import fr.free.nrw.commons.Utils
@@ -19,6 +23,8 @@ import fr.free.nrw.commons.explore.categories.parent.ParentCategoriesFragment
1923
import fr.free.nrw.commons.explore.categories.sub.SubCategoriesFragment
2024
import fr.free.nrw.commons.media.MediaDetailPagerFragment
2125
import fr.free.nrw.commons.theme.BaseActivity
26+
import kotlinx.coroutines.launch
27+
import javax.inject.Inject
2228

2329

2430
/**
@@ -38,6 +44,11 @@ class CategoryDetailsActivity : BaseActivity(),
3844

3945
private lateinit var binding: ActivityCategoryDetailsBinding
4046

47+
@Inject
48+
lateinit var categoryViewModelFactory: CategoryDetailsViewModel.ViewModelFactory
49+
50+
private val viewModel: CategoryDetailsViewModel by viewModels<CategoryDetailsViewModel> { categoryViewModelFactory }
51+
4152
override fun onCreate(savedInstanceState: Bundle?) {
4253
super.onCreate(savedInstanceState)
4354

@@ -53,6 +64,15 @@ class CategoryDetailsActivity : BaseActivity(),
5364
supportActionBar?.setDisplayHomeAsUpEnabled(true)
5465
setTabs()
5566
setPageTitle()
67+
68+
lifecycleScope.launch {
69+
repeatOnLifecycle(Lifecycle.State.STARTED){
70+
viewModel.bookmarkState.collect {
71+
invalidateOptionsMenu()
72+
}
73+
}
74+
}
75+
5676
}
5777

5878
/**
@@ -73,6 +93,8 @@ class CategoryDetailsActivity : BaseActivity(),
7393
categoriesMediaFragment.arguments = arguments
7494
subCategoryListFragment.arguments = arguments
7595
parentCategoriesFragment.arguments = arguments
96+
97+
viewModel.onCheckIfBookmarked(categoryName!!)
7698
}
7799
fragmentList.add(categoriesMediaFragment)
78100
titleList.add("MEDIA")
@@ -181,6 +203,14 @@ class CategoryDetailsActivity : BaseActivity(),
181203
Utils.handleWebUrl(this, Uri.parse(title.canonicalUri))
182204
true
183205
}
206+
207+
R.id.menu_bookmark_current_category -> {
208+
categoryName?.let {
209+
viewModel.onBookmarkClick(categoryName = it)
210+
}
211+
true
212+
}
213+
184214
android.R.id.home -> {
185215
onBackPressed()
186216
true
@@ -189,6 +219,22 @@ class CategoryDetailsActivity : BaseActivity(),
189219
}
190220
}
191221

222+
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
223+
menu?.run {
224+
val bookmarkMenuItem = findItem(R.id.menu_bookmark_current_category)
225+
if (bookmarkMenuItem != null) {
226+
val icon = if(viewModel.bookmarkState.value){
227+
R.drawable.menu_ic_round_star_filled_24px
228+
} else {
229+
R.drawable.menu_ic_round_star_border_24px
230+
}
231+
232+
bookmarkMenuItem.setIcon(icon)
233+
}
234+
}
235+
return super.onPrepareOptionsMenu(menu)
236+
}
237+
192238
/**
193239
* This method is called on backPressed of anyFragment in the activity.
194240
* If condition is called when mediaDetailFragment is opened.

0 commit comments

Comments
 (0)