Wellbeing mode (#1992)

* Add wellbeing mode settings toggle

* Translate wellbeing mode string to german

* Disable fav/boost count on toots if wellbeing is enabled

* Hide follow/post stats on profiles

* Reload notifications when wellbeing mode is toggled

* Add wellbeing mode explainer dialog

* Move wellbeing filter timeline into own category

* Add toggles for quantitative stats

* Hide announcement badge counts if wellbeing is enabled

* Move fetching of wellbeing setting to activity

* Add wellbeing option to statusDisplayOptions

* Update post filters for all accounts

* Remove local translations

* Revert "Remove local translations"

This reverts commit e92e636a5c759b09649174ab68ec91bc13680287.

* Remove german translations
This commit is contained in:
Garrit Franke 2020-12-23 19:13:37 +01:00 committed by GitHub
parent 05233de0f9
commit 0fbb4e9713
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 164 additions and 29 deletions

View file

@ -57,6 +57,7 @@ import com.keylesspalace.tusky.interfaces.ActionButtonActivity
import com.keylesspalace.tusky.interfaces.LinkListener import com.keylesspalace.tusky.interfaces.LinkListener
import com.keylesspalace.tusky.interfaces.ReselectableFragment import com.keylesspalace.tusky.interfaces.ReselectableFragment
import com.keylesspalace.tusky.pager.AccountPagerAdapter import com.keylesspalace.tusky.pager.AccountPagerAdapter
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.* import com.keylesspalace.tusky.util.*
import com.keylesspalace.tusky.view.showMuteAccountDialog import com.keylesspalace.tusky.view.showMuteAccountDialog
import com.keylesspalace.tusky.viewmodel.AccountViewModel import com.keylesspalace.tusky.viewmodel.AccountViewModel
@ -185,6 +186,17 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
poorTabView.isPressed = true poorTabView.isPressed = true
accountTabLayout.postDelayed({ poorTabView.isPressed = false }, 300) accountTabLayout.postDelayed({ poorTabView.isPressed = false }, 300)
} }
// If wellbeing mode is enabled, follow stats and posts count should be hidden
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
val wellbeingEnabled = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_PROFILE, false)
if (wellbeingEnabled) {
accountStatuses.hide()
accountFollowers.hide()
accountFollowing.hide()
}
} }
/** /**
@ -199,8 +211,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
val pageTitles = arrayOf(getString(R.string.title_statuses), getString(R.string.title_statuses_with_replies), getString(R.string.title_statuses_pinned), getString(R.string.title_media)) val pageTitles = arrayOf(getString(R.string.title_statuses), getString(R.string.title_statuses_with_replies), getString(R.string.title_statuses_pinned), getString(R.string.title_media))
TabLayoutMediator(accountTabLayout, accountFragmentViewPager) { TabLayoutMediator(accountTabLayout, accountFragmentViewPager) { tab, position ->
tab, position ->
tab.text = pageTitles[position] tab.text = pageTitles[position]
}.attach() }.attach()
@ -534,7 +545,11 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
blockingDomain = relation.blockingDomain blockingDomain = relation.blockingDomain
showingReblogs = relation.showingReblogs showingReblogs = relation.showingReblogs
accountFollowsYouTextView.visible(relation.followedBy) // If wellbeing mode is enabled, "follows you" text should not be visible
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
val wellbeingEnabled = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_PROFILE, false)
accountFollowsYouTextView.visible(relation.followedBy && !wellbeingEnabled)
// because subscribing is Pleroma extension, enable it __only__ when we have non-null subscribing field // because subscribing is Pleroma extension, enable it __only__ when we have non-null subscribing field
// it's also now supported in Mastodon 3.3.0rc but called notifying and use different API call // it's also now supported in Mastodon 3.3.0rc but called notifying and use different API call
@ -749,8 +764,8 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
if (viewModel.relationshipData.value?.data?.muting != true) { if (viewModel.relationshipData.value?.data?.muting != true) {
loadedAccount?.let { loadedAccount?.let {
showMuteAccountDialog( showMuteAccountDialog(
this, this,
it.username it.username
) { notifications -> ) { notifications ->
viewModel.muteAccount(notifications) viewModel.muteAccount(notifications)
} }

View file

@ -254,7 +254,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
statusDisplayOptions.showBotOverlay(), statusDisplayOptions.showBotOverlay(),
statusDisplayOptions.useBlurhash(), statusDisplayOptions.useBlurhash(),
CardViewMode.NONE, CardViewMode.NONE,
statusDisplayOptions.confirmReblogs() statusDisplayOptions.confirmReblogs(),
statusDisplayOptions.hideStats()
); );
} }

View file

@ -108,7 +108,12 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
super.setupWithStatus(status, listener, statusDisplayOptions, payloads); super.setupWithStatus(status, listener, statusDisplayOptions, payloads);
setupCard(status, CardViewMode.FULL_WIDTH, statusDisplayOptions); // Always show card for detailed status setupCard(status, CardViewMode.FULL_WIDTH, statusDisplayOptions); // Always show card for detailed status
if (payloads == null) { if (payloads == null) {
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
if (!statusDisplayOptions.hideStats()) {
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
} else {
hideQuantitativeStats();
}
setApplication(status.getApplication()); setApplication(status.getApplication());
@ -174,4 +179,10 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
null null
); );
} }
private void hideQuantitativeStats() {
reblogs.setVisibility(View.GONE);
favourites.setVisibility(View.GONE);
infoDivider.setVisibility(View.GONE);
}
} }

View file

@ -65,7 +65,8 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
statusDisplayOptions.showBotOverlay(), statusDisplayOptions.showBotOverlay(),
statusDisplayOptions.useBlurhash(), statusDisplayOptions.useBlurhash(),
statusDisplayOptions.cardViewMode(), statusDisplayOptions.cardViewMode(),
statusDisplayOptions.confirmReblogs() statusDisplayOptions.confirmReblogs(),
statusDisplayOptions.hideStats()
); );
} }

View file

@ -32,6 +32,7 @@ import com.keylesspalace.tusky.util.LinkHelper
import com.keylesspalace.tusky.util.emojify import com.keylesspalace.tusky.util.emojify
import kotlinx.android.synthetic.main.item_announcement.view.* import kotlinx.android.synthetic.main.item_announcement.view.*
interface AnnouncementActionListener: LinkListener { interface AnnouncementActionListener: LinkListener {
fun openReactionPicker(announcementId: String, target: View) fun openReactionPicker(announcementId: String, target: View)
fun addReaction(announcementId: String, name: String) fun addReaction(announcementId: String, name: String)
@ -40,7 +41,8 @@ interface AnnouncementActionListener: LinkListener {
class AnnouncementAdapter( class AnnouncementAdapter(
private var items: List<Announcement> = emptyList(), private var items: List<Announcement> = emptyList(),
private val listener: AnnouncementActionListener private val listener: AnnouncementActionListener,
private val wellbeingEnabled: Boolean = false
) : RecyclerView.Adapter<AnnouncementAdapter.AnnouncementViewHolder>() { ) : RecyclerView.Adapter<AnnouncementAdapter.AnnouncementViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AnnouncementViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AnnouncementViewHolder {
@ -68,6 +70,14 @@ class AnnouncementAdapter(
fun bind(item: Announcement) { fun bind(item: Announcement) {
LinkHelper.setClickableText(text, item.content, null, listener) LinkHelper.setClickableText(text, item.content, null, listener)
// If wellbeing mode is enabled, announcement badge counts should not be shown.
if (wellbeingEnabled) {
// Since reactions are not visible in wellbeing mode,
// we shouldn't be able to add any ourselves.
addReactionChip.visibility = View.GONE
return
}
item.reactions.forEachIndexed { i, reaction -> item.reactions.forEachIndexed { i, reaction ->
(chips.getChildAt(i)?.takeUnless { it.id == R.id.addReactionChip } as Chip? (chips.getChildAt(i)?.takeUnless { it.id == R.id.addReactionChip } as Chip?
?: Chip(ContextThemeWrapper(view.context, R.style.Widget_MaterialComponents_Chip_Choice)).apply { ?: Chip(ContextThemeWrapper(view.context, R.style.Widget_MaterialComponents_Chip_Choice)).apply {

View file

@ -17,18 +17,23 @@ package com.keylesspalace.tusky.components.announcements
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.PopupWindow import android.widget.PopupWindow
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.keylesspalace.tusky.* import com.keylesspalace.tusky.BottomSheetActivity
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.ViewTagActivity
import com.keylesspalace.tusky.adapter.EmojiAdapter import com.keylesspalace.tusky.adapter.EmojiAdapter
import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener
import com.keylesspalace.tusky.di.Injectable import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.di.ViewModelFactory import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.* import com.keylesspalace.tusky.util.*
import com.keylesspalace.tusky.view.EmojiPicker import com.keylesspalace.tusky.view.EmojiPicker
import kotlinx.android.synthetic.main.activity_announcements.* import kotlinx.android.synthetic.main.activity_announcements.*
@ -42,7 +47,7 @@ class AnnouncementsActivity : BottomSheetActivity(), AnnouncementActionListener,
private val viewModel: AnnouncementsViewModel by viewModels { viewModelFactory } private val viewModel: AnnouncementsViewModel by viewModels { viewModelFactory }
private val adapter = AnnouncementAdapter(emptyList(), this) private lateinit var adapter: AnnouncementAdapter
private val picker by lazy { EmojiPicker(this) } private val picker by lazy { EmojiPicker(this) }
private val pickerDialog by lazy { private val pickerDialog by lazy {
@ -75,6 +80,12 @@ class AnnouncementsActivity : BottomSheetActivity(), AnnouncementActionListener,
announcementsList.layoutManager = LinearLayoutManager(this) announcementsList.layoutManager = LinearLayoutManager(this)
val divider = DividerItemDecoration(this, DividerItemDecoration.VERTICAL) val divider = DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
announcementsList.addItemDecoration(divider) announcementsList.addItemDecoration(divider)
val preferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
val wellbeingEnabled = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false)
adapter = AnnouncementAdapter(emptyList(), this, wellbeingEnabled)
announcementsList.adapter = adapter announcementsList.adapter = adapter
viewModel.announcements.observe(this) { viewModel.announcements.observe(this) {

View file

@ -34,6 +34,7 @@ import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.fragment.SFragment import com.keylesspalace.tusky.fragment.SFragment
import com.keylesspalace.tusky.interfaces.ReselectableFragment import com.keylesspalace.tusky.interfaces.ReselectableFragment
import com.keylesspalace.tusky.interfaces.StatusActionListener import com.keylesspalace.tusky.interfaces.StatusActionListener
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.CardViewMode import com.keylesspalace.tusky.util.CardViewMode
import com.keylesspalace.tusky.util.NetworkState import com.keylesspalace.tusky.util.NetworkState
import com.keylesspalace.tusky.util.StatusDisplayOptions import com.keylesspalace.tusky.util.StatusDisplayOptions
@ -68,7 +69,9 @@ class ConversationsFragment : SFragment(), StatusActionListener, Injectable, Res
showBotOverlay = preferences.getBoolean("showBotOverlay", true), showBotOverlay = preferences.getBoolean("showBotOverlay", true),
useBlurhash = preferences.getBoolean("useBlurhash", true), useBlurhash = preferences.getBoolean("useBlurhash", true),
cardViewMode = CardViewMode.NONE, cardViewMode = CardViewMode.NONE,
confirmReblogs = preferences.getBoolean("confirmReblogs", true) confirmReblogs = preferences.getBoolean("confirmReblogs", true),
hideStats = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false)
) )
adapter = ConversationAdapter(statusDisplayOptions, this, ::onTopLoaded, viewModel::retry) adapter = ConversationAdapter(statusDisplayOptions, this, ::onTopLoaded, viewModel::retry)

View file

@ -19,10 +19,14 @@ import android.os.Bundle
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.di.Injectable import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.entity.Notification
import com.keylesspalace.tusky.settings.* import com.keylesspalace.tusky.settings.*
import com.keylesspalace.tusky.util.ThemeUtils import com.keylesspalace.tusky.util.ThemeUtils
import com.keylesspalace.tusky.util.deserialize
import com.keylesspalace.tusky.util.getNonNullString import com.keylesspalace.tusky.util.getNonNullString
import com.keylesspalace.tusky.util.serialize
import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.colorInt
@ -35,6 +39,9 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
@Inject @Inject
lateinit var okhttpclient: OkHttpClient lateinit var okhttpclient: OkHttpClient
@Inject
lateinit var accountManager: AccountManager
private val iconSize by lazy { resources.getDimensionPixelSize(R.dimen.preference_icon_size) } private val iconSize by lazy { resources.getDimensionPixelSize(R.dimen.preference_icon_size) }
private var httpProxyPref: Preference? = null private var httpProxyPref: Preference? = null
@ -192,6 +199,45 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
} }
} }
preferenceCategory(R.string.pref_title_wellbeing_mode) {
switchPreference {
title = getString(R.string.limit_notifications)
setDefaultValue(false)
key = PrefKeys.WELLBEING_LIMITED_NOTIFICATIONS
setOnPreferenceChangeListener { _, value ->
for (account in accountManager.accounts) {
val notificationFilter = deserialize(account.notificationsFilter).toMutableSet()
if (value == true) {
notificationFilter.add(Notification.Type.FAVOURITE)
notificationFilter.add(Notification.Type.FOLLOW)
notificationFilter.add(Notification.Type.REBLOG)
} else {
notificationFilter.remove(Notification.Type.FAVOURITE)
notificationFilter.remove(Notification.Type.FOLLOW)
notificationFilter.remove(Notification.Type.REBLOG)
}
account.notificationsFilter = serialize(notificationFilter)
accountManager.saveAccount(account)
}
true
}
}
switchPreference {
title = getString(R.string.wellbeing_hide_stats_posts)
setDefaultValue(false)
key = PrefKeys.WELLBEING_HIDE_STATS_POSTS
}
switchPreference {
title = getString(R.string.wellbeing_hide_stats_profile)
setDefaultValue(false)
key = PrefKeys.WELLBEING_HIDE_STATS_PROFILE
}
}
preferenceCategory(R.string.pref_title_proxy_settings) { preferenceCategory(R.string.pref_title_proxy_settings) {
httpProxyPref = preference { httpProxyPref = preference {
setTitle(R.string.pref_title_http_proxy_settings) setTitle(R.string.pref_title_http_proxy_settings)

View file

@ -41,6 +41,7 @@ import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.di.ViewModelFactory import com.keylesspalace.tusky.di.ViewModelFactory
import com.keylesspalace.tusky.entity.Attachment import com.keylesspalace.tusky.entity.Attachment
import com.keylesspalace.tusky.entity.Status import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.CardViewMode import com.keylesspalace.tusky.util.CardViewMode
import com.keylesspalace.tusky.util.StatusDisplayOptions import com.keylesspalace.tusky.util.StatusDisplayOptions
import com.keylesspalace.tusky.util.hide import com.keylesspalace.tusky.util.hide
@ -118,7 +119,8 @@ class ReportStatusesFragment : Fragment(), Injectable, AdapterHandler {
showBotOverlay = false, showBotOverlay = false,
useBlurhash = preferences.getBoolean("useBlurhash", true), useBlurhash = preferences.getBoolean("useBlurhash", true),
cardViewMode = CardViewMode.NONE, cardViewMode = CardViewMode.NONE,
confirmReblogs = preferences.getBoolean("confirmReblogs", true) confirmReblogs = preferences.getBoolean("confirmReblogs", true),
hideStats = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false)
) )
adapter = StatusesAdapter(statusDisplayOptions, adapter = StatusesAdapter(statusDisplayOptions,

View file

@ -52,6 +52,7 @@ import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.entity.Status.Mention import com.keylesspalace.tusky.entity.Status.Mention
import com.keylesspalace.tusky.interfaces.AccountSelectionListener import com.keylesspalace.tusky.interfaces.AccountSelectionListener
import com.keylesspalace.tusky.interfaces.StatusActionListener import com.keylesspalace.tusky.interfaces.StatusActionListener
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.CardViewMode import com.keylesspalace.tusky.util.CardViewMode
import com.keylesspalace.tusky.util.NetworkState import com.keylesspalace.tusky.util.NetworkState
import com.keylesspalace.tusky.util.StatusDisplayOptions import com.keylesspalace.tusky.util.StatusDisplayOptions
@ -84,7 +85,8 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
showBotOverlay = preferences.getBoolean("showBotOverlay", true), showBotOverlay = preferences.getBoolean("showBotOverlay", true),
useBlurhash = preferences.getBoolean("useBlurhash", true), useBlurhash = preferences.getBoolean("useBlurhash", true),
cardViewMode = CardViewMode.NONE, cardViewMode = CardViewMode.NONE,
confirmReblogs = preferences.getBoolean("confirmReblogs", true) confirmReblogs = preferences.getBoolean("confirmReblogs", true),
hideStats = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false)
) )
searchRecyclerView.addItemDecoration(DividerItemDecoration(searchRecyclerView.context, DividerItemDecoration.VERTICAL)) searchRecyclerView.addItemDecoration(DividerItemDecoration(searchRecyclerView.context, DividerItemDecoration.VERTICAL))

View file

@ -35,7 +35,8 @@ class AccountManager @Inject constructor(db: AppDatabase) {
@Volatile @Volatile
var activeAccount: AccountEntity? = null var activeAccount: AccountEntity? = null
private var accounts: MutableList<AccountEntity> = mutableListOf() var accounts: MutableList<AccountEntity> = mutableListOf()
private set
private val accountDao: AccountDao = db.accountDao() private val accountDao: AccountDao = db.accountDao()
init { init {

View file

@ -15,14 +15,14 @@
package com.keylesspalace.tusky.db; package com.keylesspalace.tusky.db;
import com.keylesspalace.tusky.TabDataKt; import androidx.annotation.NonNull;
import com.keylesspalace.tusky.components.conversation.ConversationEntity;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.room.Database; import androidx.room.Database;
import androidx.room.RoomDatabase; import androidx.room.RoomDatabase;
import androidx.room.migration.Migration; import androidx.room.migration.Migration;
import androidx.annotation.NonNull; import androidx.sqlite.db.SupportSQLiteDatabase;
import com.keylesspalace.tusky.TabDataKt;
import com.keylesspalace.tusky.components.conversation.ConversationEntity;
/** /**
* DB version & declare DAO * DB version & declare DAO

View file

@ -15,7 +15,10 @@
package com.keylesspalace.tusky.entity package com.keylesspalace.tusky.entity
import com.google.gson.* import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonParseException
import com.google.gson.annotations.JsonAdapter import com.google.gson.annotations.JsonAdapter
data class Notification( data class Notification(

View file

@ -49,7 +49,7 @@ import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import java.io.IOException import java.io.IOException
import java.util.HashMap import java.util.*
import javax.inject.Inject import javax.inject.Inject
class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {

View file

@ -71,6 +71,7 @@ import com.keylesspalace.tusky.interfaces.AccountActionListener;
import com.keylesspalace.tusky.interfaces.ActionButtonActivity; import com.keylesspalace.tusky.interfaces.ActionButtonActivity;
import com.keylesspalace.tusky.interfaces.ReselectableFragment; import com.keylesspalace.tusky.interfaces.ReselectableFragment;
import com.keylesspalace.tusky.interfaces.StatusActionListener; import com.keylesspalace.tusky.interfaces.StatusActionListener;
import com.keylesspalace.tusky.settings.PrefKeys;
import com.keylesspalace.tusky.util.CardViewMode; import com.keylesspalace.tusky.util.CardViewMode;
import com.keylesspalace.tusky.util.Either; import com.keylesspalace.tusky.util.Either;
import com.keylesspalace.tusky.util.HttpHeaderLink; import com.keylesspalace.tusky.util.HttpHeaderLink;
@ -251,7 +252,8 @@ public class NotificationsFragment extends SFragment implements
preferences.getBoolean("showBotOverlay", true), preferences.getBoolean("showBotOverlay", true),
preferences.getBoolean("useBlurhash", true), preferences.getBoolean("useBlurhash", true),
CardViewMode.NONE, CardViewMode.NONE,
preferences.getBoolean("confirmReblogs", true) preferences.getBoolean("confirmReblogs", true),
preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false)
); );
adapter = new NotificationsAdapter(accountManager.getActiveAccount().getAccountId(), adapter = new NotificationsAdapter(accountManager.getActiveAccount().getAccountId(),
@ -801,6 +803,7 @@ public class NotificationsFragment extends SFragment implements
private void loadNotificationsFilter() { private void loadNotificationsFilter() {
AccountEntity account = accountManager.getActiveAccount(); AccountEntity account = accountManager.getActiveAccount();
if (account != null) { if (account != null) {
notificationFilter.clear();
notificationFilter.addAll(NotificationTypeConverterKt.deserialize( notificationFilter.addAll(NotificationTypeConverterKt.deserialize(
account.getNotificationsFilter())); account.getNotificationsFilter()));
} }
@ -1277,6 +1280,12 @@ public class NotificationsFragment extends SFragment implements
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
String rawAccountNotificationFilter = accountManager.getActiveAccount().getNotificationsFilter();
Set<Notification.Type> accountNotificationFilter = NotificationTypeConverterKt.deserialize(rawAccountNotificationFilter);
if (!notificationFilter.equals(accountNotificationFilter)) {
loadNotificationsFilter();
fullyRefreshWithProgressBar(true);
}
startUpdateTimestamp(); startUpdateTimestamp();
} }

View file

@ -74,6 +74,7 @@ import com.keylesspalace.tusky.network.MastodonApi;
import com.keylesspalace.tusky.repository.Placeholder; import com.keylesspalace.tusky.repository.Placeholder;
import com.keylesspalace.tusky.repository.TimelineRepository; import com.keylesspalace.tusky.repository.TimelineRepository;
import com.keylesspalace.tusky.repository.TimelineRequestMode; import com.keylesspalace.tusky.repository.TimelineRequestMode;
import com.keylesspalace.tusky.settings.PrefKeys;
import com.keylesspalace.tusky.util.CardViewMode; import com.keylesspalace.tusky.util.CardViewMode;
import com.keylesspalace.tusky.util.Either; import com.keylesspalace.tusky.util.Either;
import com.keylesspalace.tusky.util.HttpHeaderLink; import com.keylesspalace.tusky.util.HttpHeaderLink;
@ -83,7 +84,6 @@ import com.keylesspalace.tusky.util.ListUtils;
import com.keylesspalace.tusky.util.PairedList; import com.keylesspalace.tusky.util.PairedList;
import com.keylesspalace.tusky.util.StatusDisplayOptions; import com.keylesspalace.tusky.util.StatusDisplayOptions;
import com.keylesspalace.tusky.util.StringUtils; import com.keylesspalace.tusky.util.StringUtils;
import com.keylesspalace.tusky.util.ThemeUtils;
import com.keylesspalace.tusky.util.ViewDataUtils; import com.keylesspalace.tusky.util.ViewDataUtils;
import com.keylesspalace.tusky.view.BackgroundMessageView; import com.keylesspalace.tusky.view.BackgroundMessageView;
import com.keylesspalace.tusky.view.EndlessOnScrollListener; import com.keylesspalace.tusky.view.EndlessOnScrollListener;
@ -252,7 +252,8 @@ public class TimelineFragment extends SFragment implements
preferences.getBoolean("showCardsInTimelines", false) ? preferences.getBoolean("showCardsInTimelines", false) ?
CardViewMode.INDENTED : CardViewMode.INDENTED :
CardViewMode.NONE, CardViewMode.NONE,
preferences.getBoolean("confirmReblogs", true) preferences.getBoolean("confirmReblogs", true),
preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false)
); );
adapter = new TimelineAdapter(dataSource, statusDisplayOptions, this); adapter = new TimelineAdapter(dataSource, statusDisplayOptions, this);

View file

@ -58,11 +58,11 @@ import com.keylesspalace.tusky.entity.Status;
import com.keylesspalace.tusky.entity.StatusContext; import com.keylesspalace.tusky.entity.StatusContext;
import com.keylesspalace.tusky.interfaces.StatusActionListener; import com.keylesspalace.tusky.interfaces.StatusActionListener;
import com.keylesspalace.tusky.network.MastodonApi; import com.keylesspalace.tusky.network.MastodonApi;
import com.keylesspalace.tusky.settings.PrefKeys;
import com.keylesspalace.tusky.util.CardViewMode; import com.keylesspalace.tusky.util.CardViewMode;
import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate; import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate;
import com.keylesspalace.tusky.util.PairedList; import com.keylesspalace.tusky.util.PairedList;
import com.keylesspalace.tusky.util.StatusDisplayOptions; import com.keylesspalace.tusky.util.StatusDisplayOptions;
import com.keylesspalace.tusky.util.ThemeUtils;
import com.keylesspalace.tusky.util.ViewDataUtils; import com.keylesspalace.tusky.util.ViewDataUtils;
import com.keylesspalace.tusky.view.ConversationLineItemDecoration; import com.keylesspalace.tusky.view.ConversationLineItemDecoration;
import com.keylesspalace.tusky.viewdata.StatusViewData; import com.keylesspalace.tusky.viewdata.StatusViewData;
@ -127,6 +127,7 @@ public final class ViewThreadFragment extends SFragment implements
thisThreadsStatusId = getArguments().getString("id"); thisThreadsStatusId = getArguments().getString("id");
SharedPreferences preferences = SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(getActivity()); PreferenceManager.getDefaultSharedPreferences(getActivity());
StatusDisplayOptions statusDisplayOptions = new StatusDisplayOptions( StatusDisplayOptions statusDisplayOptions = new StatusDisplayOptions(
preferences.getBoolean("animateGifAvatars", false), preferences.getBoolean("animateGifAvatars", false),
accountManager.getActiveAccount().getMediaPreviewEnabled(), accountManager.getActiveAccount().getMediaPreviewEnabled(),
@ -136,7 +137,8 @@ public final class ViewThreadFragment extends SFragment implements
preferences.getBoolean("showCardsInTimelines", false) ? preferences.getBoolean("showCardsInTimelines", false) ?
CardViewMode.INDENTED : CardViewMode.INDENTED :
CardViewMode.NONE, CardViewMode.NONE,
preferences.getBoolean("confirmReblogs", true) preferences.getBoolean("confirmReblogs", true),
preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false)
); );
adapter = new ThreadAdapter(statusDisplayOptions, this); adapter = new ThreadAdapter(statusDisplayOptions, this);
} }

View file

@ -33,6 +33,9 @@ object PrefKeys {
const val ENABLE_SWIPE_FOR_TABS = "enableSwipeForTabs" const val ENABLE_SWIPE_FOR_TABS = "enableSwipeForTabs"
const val CUSTOM_TABS = "customTabs" const val CUSTOM_TABS = "customTabs"
const val WELLBEING_LIMITED_NOTIFICATIONS = "wellbeingModeLimitedNotifications"
const val WELLBEING_HIDE_STATS_POSTS = "wellbeingHideStatsPosts"
const val WELLBEING_HIDE_STATS_PROFILE = "wellbeingHideStatsProfile"
const val HTTP_PROXY_ENABLED = "httpProxyEnabled" const val HTTP_PROXY_ENABLED = "httpProxyEnabled"
const val HTTP_PROXY_SERVER = "httpProxyServer" const val HTTP_PROXY_SERVER = "httpProxyServer"

View file

@ -14,5 +14,7 @@ data class StatusDisplayOptions(
@get:JvmName("cardViewMode") @get:JvmName("cardViewMode")
val cardViewMode: CardViewMode, val cardViewMode: CardViewMode,
@get:JvmName("confirmReblogs") @get:JvmName("confirmReblogs")
val confirmReblogs: Boolean val confirmReblogs: Boolean,
@get:JvmName("hideStats")
val hideStats: Boolean
) )

View file

@ -20,11 +20,12 @@ import android.content.res.TypedArray;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import androidx.annotation.AttrRes; import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.app.AppCompatDelegate;
import android.util.TypedValue;
/** /**
* Provides runtime compatibility to obtain theme information and re-theme views, especially where * Provides runtime compatibility to obtain theme information and re-theme views, especially where

View file

@ -578,7 +578,18 @@
<string name="pref_title_show_cards_in_timelines">Show link previews in timelines</string> <string name="pref_title_show_cards_in_timelines">Show link previews in timelines</string>
<string name="pref_title_confirm_reblogs">Show confirmation dialog before boosting</string> <string name="pref_title_confirm_reblogs">Show confirmation dialog before boosting</string>
<string name="pref_title_hide_top_toolbar">Hide the title of the top toolbar</string> <string name="pref_title_hide_top_toolbar">Hide the title of the top toolbar</string>
<string name="pref_title_wellbeing_mode">Wellbeing</string>
<string name="account_note_hint">Your private note about this account</string> <string name="account_note_hint">Your private note about this account</string>
<string name="account_note_saved">Saved!</string> <string name="account_note_saved">Saved!</string>
<string name="wellbeing_mode_notice">Some information that might affect your mental wellbeing will be hidden. This includes:\n\n
- Favorite/Boost/Follow notifications\n
- Favorite/Boost count on toots\n
- Follower/Post stats on profiles\n\n
Push-notifications will not be affected, but you can review your notification preferences manually.
</string>
<string name="review_notifications">Review Notifications</string>
<string name="limit_notifications">Limit timeline notifications</string>
<string name="wellbeing_hide_stats_posts">Hide quantitative stats on posts</string>
<string name="wellbeing_hide_stats_profile">Hide quantitative stats on profiles</string>
</resources> </resources>