Commit 6eb3e60e authored by Christophe Henry's avatar Christophe Henry

Solves #45: Add badge to unread articles section to indicate total count of unread articles

parent 02386b09
......@@ -8,6 +8,7 @@
* Add animation in views's transtions ([4f84e6b5](https://git.feneas.org/christophehenry/freshrss-android/commit/4f84e6b5f6de7d42a24d541e099a402d034792da))
* Implement [#10](https://git.feneas.org/christophehenry/freshrss-android/issues/10) : fetch subscription's icons and display them ([!4](https://git.feneas.org/christophehenry/freshrss-android/merge_requests/4))
* Add sections and section headers to subscriptions ([!10](https://git.feneas.org/christophehenry/freshrss-android/merge_requests/5))
* Implement [#45](https://git.feneas.org/christophehenry/freshrss-android/issues/45): add badge to unread articles section to indicate total count of unread articles ([!9](https://git.feneas.org/christophehenry/freshrss-android/merge_requests/9))
## Bug fixes
......
package fr.chenry.android.freshrss.components.subscriptions
import android.os.Bundle
import android.util.TypedValue
import android.view.*
import android.widget.LinearLayout
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentPagerAdapter
import androidx.lifecycle.Observer
import androidx.viewpager.widget.ViewPager.SimpleOnPageChangeListener
import com.google.android.material.bottomnavigation.BottomNavigationItemView
import com.google.android.material.bottomnavigation.BottomNavigationView
import fr.chenry.android.freshrss.FreshRSSApplication
import fr.chenry.android.freshrss.R
import fr.chenry.android.freshrss.store.Store
import fr.chenry.android.freshrss.utils.whenNotNull
import kotlinx.android.synthetic.main.fragment_main_subscription.*
import kotlinx.android.synthetic.main.menu_badge.*
import nl.komponents.kovenant.ui.alwaysUi
class MainSubscriptionFragment: Fragment(), BottomNavigationView.OnNavigationItemSelectedListener {
......@@ -22,6 +28,8 @@ class MainSubscriptionFragment: Fragment(), BottomNavigationView.OnNavigationIte
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setupBadgeCount()
subcription_pull_to_refresh.setOnRefreshListener {
FreshRSSApplication.application.refresherService.value.whenNotNull {
it.refresh().alwaysUi {subcription_pull_to_refresh.isRefreshing = false}
......@@ -45,8 +53,10 @@ class MainSubscriptionFragment: Fragment(), BottomNavigationView.OnNavigationIte
override fun onNavigationItemSelected(it: MenuItem): Boolean {
SubscriptionSection.fromNavigationButton(it.itemId).let {
Store.subscriptionsSection.value = it
setupBadgeStyle(it)
subcription_fragment_container.currentItem = it.ordinal
}
return true
}
......@@ -55,6 +65,48 @@ class MainSubscriptionFragment: Fragment(), BottomNavigationView.OnNavigationIte
subcription_bottom_navigation.selectedItemId = it.navigationButtonId
}
private fun setupBadgeCount() {
val menuItems = subcription_bottom_navigation.getChildAt(0)
menuItems.findViewById<BottomNavigationItemView>(R.id.subscriptions_bottom_navigation_unread).apply {
addView(layoutInflater.inflate(R.layout.menu_badge, menuItems as ViewGroup, false))
}
val observer = Observer<Int?> {count ->
menu_counter_badge_count.visibility = if((count ?: 0) > 0) View.VISIBLE else View.INVISIBLE
menu_counter_badge_count.text = (count ?: 0).let {if(it > 99) "99+" else it.toString()}
}
setupBadgeStyle(Store.subscriptionsSection.value!!)
observer.onChanged(Store.totalUnreadCount.value)
Store.totalUnreadCount.observe(this, observer)
}
private fun setupBadgeStyle(activeSubscriptionSection: SubscriptionSection) {
if(activeSubscriptionSection == SubscriptionSection.UNREAD) {
val offset =
(resources.getDimensionPixelSize(R.dimen.badge_active_text_size) -
resources.getDimensionPixelSize(R.dimen.badge_inactive_text_size)) / 2
menu_counter_badge_count.updateLayoutParams<LinearLayout.LayoutParams> {
setMargins(0, 0, 0, resources.getDimensionPixelSize(R.dimen.badge_margin_bottom) - offset)
marginStart = resources.getDimensionPixelSize(R.dimen.badge_margin_start) + offset
}
menu_counter_badge_count
.setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.badge_active_text_size))
menu_counter_badge_count.background = resources.getDrawable(R.drawable.red_circle_background)
} else {
menu_counter_badge_count.updateLayoutParams<LinearLayout.LayoutParams> {
setMargins(0, 0, 0, resources.getDimensionPixelSize(R.dimen.badge_margin_bottom))
marginStart = resources.getDimensionPixelSize(R.dimen.badge_margin_start)
}
menu_counter_badge_count
.setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.badge_inactive_text_size))
menu_counter_badge_count.background = resources.getDrawable(R.drawable.grey_circle_background)
}
}
inner class MainSubscriptionPagerAdapter: FragmentPagerAdapter(childFragmentManager) {
override fun getItem(position: Int) = instantiateFragment(SubscriptionSection.byPosition(position))
override fun getCount() = SubscriptionSection.values().size
......
......@@ -9,6 +9,7 @@ import fr.chenry.android.freshrss.store.database.models.ReadStatus.READ
import fr.chenry.android.freshrss.store.database.models.ReadStatus.UNREAD
import nl.komponents.kovenant.*
import nl.komponents.kovenant.functional.bind
import kotlin.math.max
object Store {
var debugMode = false
......@@ -91,8 +92,14 @@ object Store {
FreshRSSApplication.database.apply {
upsertArticle(article.copy(readStatus = readStatus))
when(readStatus) {
READ -> decrementSubscriptionCount(article.streamId)
UNREAD -> incrementSubscriptionCount(article.streamId)
READ -> {
decrementSubscriptionCount(article.streamId)
totalUnreadCount.value = max((totalUnreadCount.value ?: 0) - 1, 0)
}
UNREAD -> {
incrementSubscriptionCount(article.streamId)
totalUnreadCount.value = (totalUnreadCount.value ?: 0) + 1
}
}
}
}
......
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="@dimen/badge_radius" />
<solid android:color="@color/alert_inactive"/>
<size android:width="@dimen/badge_width" android:height="@dimen/badge_height" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="@dimen/badge_radius" />
<solid android:color="@color/alert"/>
<size android:width="@dimen/badge_width" android:height="@dimen/badge_height" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_gravity="center"
android:gravity="center">
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/menu_counter_badge_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/red_circle_background"
android:gravity="center"
android:text="0"
android:layout_marginStart="@dimen/badge_margin_start"
android:layout_marginBottom="@dimen/badge_margin_bottom"
android:textStyle="bold"
android:textColor="@color/alert_text"
android:visibility="visible"
tools:ignore="HardcodedText" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:textAppearance="@style/TextAppearance.AppCompat.Body2" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/subscriptions_bottom_navigation_favorites"
android:icon="@drawable/ic_favorites_black_24dp"
android:title="@string/title_favorites"
app:actionLayout="@layout/menu_counter"/>
android:title="@string/title_favorites" />
<item
android:id="@+id/subscriptions_bottom_navigation_all"
android:icon="@drawable/ic_home_black_24dp"
android:title="@string/title_all"
app:actionLayout="@layout/menu_counter"/>
android:title="@string/title_all" />
<item
android:id="@+id/subscriptions_bottom_navigation_unread"
android:icon="@drawable/ic_unread_black_24dp"
android:title="@string/title_unread"
app:actionLayout="@layout/menu_counter"/>
android:title="@string/title_unread" />
</menu>
......@@ -6,6 +6,9 @@
<color name="black">#000</color>
<color name="grey">#666666</color>
<color name="error">#A00</color>
<color name="alert">#A00</color>
<color name="alert_text">#FFF</color>
<color name="alert_inactive">@color/grey</color>
<color name="light_grey">#9E9E9E</color>
<color name="logo_obsidian">#41444f</color>
<color name="logo_grey">#c5c6ca</color>
......
......@@ -8,4 +8,11 @@
<dimen name="subscription_section_h_padding">8dp</dimen>
<dimen name="hline_weight">2dp</dimen>
<dimen name="fab_margin">16dp</dimen>
<dimen name="badge_inactive_text_size">12sp</dimen>
<dimen name="badge_active_text_size">14sp</dimen>
<dimen name="badge_height">@dimen/badge_active_text_size</dimen>
<dimen name="badge_width">22sp</dimen>
<dimen name="badge_radius">@dimen/badge_width</dimen>
<dimen name="badge_margin_start">10dp</dimen>
<dimen name="badge_margin_bottom">30dp</dimen>
</resources>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment