diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt b/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt index 952addaab8..4e2c02a4ed 100644 --- a/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt @@ -16,6 +16,7 @@ package com.keylesspalace.tusky +import android.content.SharedPreferences import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -25,7 +26,6 @@ import androidx.appcompat.widget.SearchView import androidx.fragment.app.DialogFragment import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.ListAdapter @@ -44,6 +44,7 @@ import com.keylesspalace.tusky.util.viewBinding import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel import com.keylesspalace.tusky.viewmodel.State import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject import kotlinx.coroutines.launch private typealias AccountInfo = Pair @@ -51,6 +52,9 @@ private typealias AccountInfo = Pair @AndroidEntryPoint class AccountsInListFragment : DialogFragment() { + @Inject + lateinit var preferences: SharedPreferences + private val viewModel: AccountsInListViewModel by viewModels() private val binding by viewBinding(FragmentAccountsInListBinding::bind) @@ -60,9 +64,6 @@ class AccountsInListFragment : DialogFragment() { private val searchAdapter = SearchAdapter() private val radius by unsafeLazy { resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp) } - private val pm by unsafeLazy { PreferenceManager.getDefaultSharedPreferences(requireContext()) } - private val animateAvatar by unsafeLazy { pm.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false) } - private val animateEmojis by unsafeLazy { pm.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -206,6 +207,8 @@ class AccountsInListFragment : DialogFragment() { position: Int ) { val account = getItem(position) + val animateAvatar = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false) + val animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) holder.binding.displayNameTextView.text = account.name.emojify(account.emojis, holder.binding.displayNameTextView, animateEmojis) holder.binding.usernameTextView.text = account.username loadAvatar(account.avatar, holder.binding.avatar, radius, animateAvatar) @@ -257,6 +260,9 @@ class AccountsInListFragment : DialogFragment() { ) { val (account, inAList) = getItem(position) + val animateAvatar = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false) + val animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) + holder.binding.displayNameTextView.text = account.name.emojify(account.emojis, holder.binding.displayNameTextView, animateEmojis) holder.binding.usernameTextView.text = account.username loadAvatar(account.avatar, holder.binding.avatar, radius, animateAvatar) diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java index dc9c42e35e..34c6aa9e8f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java @@ -42,6 +42,7 @@ import com.keylesspalace.tusky.components.login.LoginActivity; import com.keylesspalace.tusky.db.entity.AccountEntity; import com.keylesspalace.tusky.db.AccountManager; +import com.keylesspalace.tusky.di.PreferencesEntryPoint; import com.keylesspalace.tusky.interfaces.AccountSelectionListener; import com.keylesspalace.tusky.settings.AppTheme; import com.keylesspalace.tusky.settings.PrefKeys; @@ -55,6 +56,8 @@ import static com.keylesspalace.tusky.settings.PrefKeys.APP_THEME; +import dagger.hilt.EntryPoints; + /** * All activities inheriting from BaseActivity must be annotated with @AndroidEntryPoint */ @@ -68,6 +71,10 @@ public abstract class BaseActivity extends AppCompatActivity { @NonNull public AccountManager accountManager; + @Inject + @NonNull + public SharedPreferences preferences; + /** * Allows overriding the default ViewModelProvider.Factory for testing purposes. */ @@ -93,8 +100,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { ); } - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - /* There isn't presently a way to globally change the theme of a whole application at * runtime, just individual activities. So, each activity has to set its theme before any * views are created. */ @@ -127,7 +132,8 @@ private boolean activityTransitionWasRequested() { @Override protected void attachBaseContext(Context newBase) { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(newBase); + // injected preferences not yet available at this point of the lifecycle + SharedPreferences preferences = EntryPoints.get(newBase.getApplicationContext(), PreferencesEntryPoint.class).preferences(); // Scale text in the UI from PrefKeys.UI_TEXT_SCALE_RATIO float uiScaleRatio = preferences.getFloat(PrefKeys.UI_TEXT_SCALE_RATIO, 100F); @@ -247,7 +253,11 @@ public void showAccountChooserDialog(@Nullable CharSequence dialogTitle, boolean if (!showActiveAccount && activeAccount != null) { accounts.remove(activeAccount); } - AccountSelectionAdapter adapter = new AccountSelectionAdapter(this); + AccountSelectionAdapter adapter = new AccountSelectionAdapter( + this, + preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false), + preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) + ); adapter.addAll(accounts); new AlertDialog.Builder(this) diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt index 305ce07c39..e3195d36ba 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt @@ -51,7 +51,6 @@ import androidx.core.view.MenuProvider import androidx.core.view.forEach import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope -import androidx.preference.PreferenceManager import androidx.viewpager2.widget.MarginPageTransformer import at.connyduck.calladapter.networkresult.fold import com.bumptech.glide.Glide @@ -112,7 +111,6 @@ import com.keylesspalace.tusky.util.overrideActivityTransitionCompat import com.keylesspalace.tusky.util.reduceSwipeSensitivity import com.keylesspalace.tusky.util.show import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation -import com.keylesspalace.tusky.util.unsafeLazy import com.keylesspalace.tusky.util.viewBinding import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial @@ -183,8 +181,6 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider { private var unreadAnnouncementsCount = 0 - private val preferences by unsafeLazy { PreferenceManager.getDefaultSharedPreferences(this) } - // We need to know if the emoji pack has been changed private var selectedEmojiPack: String? = null @@ -1188,7 +1184,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider { header.clear() header.profiles = profiles header.setActiveProfile(accountManager.activeAccount!!.id) - binding.mainToolbar.subtitle = if (accountManager.shouldDisplaySelfUsername(this)) { + binding.mainToolbar.subtitle = if (accountManager.shouldDisplaySelfUsername()) { accountManager.activeAccount!!.fullName } else { null diff --git a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt index cb0cc615ee..7e374ba7c6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt +++ b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt @@ -52,7 +52,7 @@ class TuskyApplication : Application(), Configuration.Provider { lateinit var localeManager: LocaleManager @Inject - lateinit var sharedPreferences: SharedPreferences + lateinit var preferences: SharedPreferences override fun onCreate() { // Uncomment me to get StrictMode violation logs @@ -70,7 +70,7 @@ class TuskyApplication : Application(), Configuration.Provider { Security.insertProviderAt(Conscrypt.newProvider(), 1) // Migrate shared preference keys and defaults from version to version. - val oldVersion = sharedPreferences.getInt( + val oldVersion = preferences.getInt( PrefKeys.SCHEMA_VERSION, NEW_INSTALL_SCHEMA_VERSION ) @@ -84,7 +84,7 @@ class TuskyApplication : Application(), Configuration.Provider { EmojiPackHelper.init(this, DefaultEmojiPackList.get(this), allowPackImports = false) // init night mode - val theme = sharedPreferences.getString(APP_THEME, AppTheme.DEFAULT.value) + val theme = preferences.getString(APP_THEME, AppTheme.DEFAULT.value) setAppNightMode(theme) localeManager.setLocale() @@ -109,7 +109,7 @@ class TuskyApplication : Application(), Configuration.Provider { private fun upgradeSharedPreferences(oldVersion: Int, newVersion: Int) { Log.d(TAG, "Upgrading shared preferences: $oldVersion -> $newVersion") - val editor = sharedPreferences.edit() + val editor = preferences.edit() if (oldVersion < 2023022701) { // These preferences are (now) handled in AccountPreferenceHandler. Remove them from shared for clarity. @@ -123,7 +123,7 @@ class TuskyApplication : Application(), Configuration.Provider { // Default value for appTheme is now THEME_SYSTEM. If the user is upgrading and // didn't have an explicit preference set use the previous default, so the // theme does not unexpectedly change. - if (!sharedPreferences.contains(APP_THEME)) { + if (!preferences.contains(APP_THEME)) { editor.putString(APP_THEME, AppTheme.NIGHT.value) } } diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt index d8463134dd..8d42f0a9f6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt @@ -20,15 +20,17 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ArrayAdapter -import androidx.preference.PreferenceManager import com.keylesspalace.tusky.R import com.keylesspalace.tusky.databinding.ItemAutocompleteAccountBinding import com.keylesspalace.tusky.db.entity.AccountEntity -import com.keylesspalace.tusky.settings.PrefKeys import com.keylesspalace.tusky.util.emojify import com.keylesspalace.tusky.util.loadAvatar -class AccountSelectionAdapter(context: Context) : ArrayAdapter( +class AccountSelectionAdapter( + context: Context, + private val animateAvatars: Boolean, + private val animateEmojis: Boolean +) : ArrayAdapter( context, R.layout.item_autocomplete_account ) { @@ -42,17 +44,13 @@ class AccountSelectionAdapter(context: Context) : ArrayAdapter( val account = getItem(position) if (account != null) { - val pm = PreferenceManager.getDefaultSharedPreferences(binding.avatar.context) - val animateEmojis = pm.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) - binding.username.text = account.fullName binding.displayName.text = account.displayName.emojify(account.emojis, binding.displayName, animateEmojis) binding.avatarBadge.visibility = View.GONE // We never want to display the bot badge here val avatarRadius = context.resources.getDimensionPixelSize(R.dimen.avatar_radius_42dp) - val animateAvatar = pm.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false) - loadAvatar(account.profilePictureUrl, binding.avatar, avatarRadius, animateAvatar) + loadAvatar(account.profilePictureUrl, binding.avatar, avatarRadius, animateAvatars) } return binding.root diff --git a/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt index 6d1754c525..c04bd6dc4a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt @@ -48,7 +48,6 @@ import androidx.core.view.WindowInsetsCompat.Type.systemBars import androidx.core.view.updatePadding import androidx.core.widget.doAfterTextChanged import androidx.lifecycle.lifecycleScope -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.viewpager2.widget.MarginPageTransformer import com.bumptech.glide.Glide @@ -92,7 +91,6 @@ import com.keylesspalace.tusky.util.reduceSwipeSensitivity import com.keylesspalace.tusky.util.setClickableText import com.keylesspalace.tusky.util.show import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation -import com.keylesspalace.tusky.util.unsafeLazy import com.keylesspalace.tusky.util.viewBinding import com.keylesspalace.tusky.util.visible import com.keylesspalace.tusky.view.showMuteAccountDialog @@ -121,8 +119,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide private lateinit var accountFieldAdapter: AccountFieldAdapter - private val preferences by unsafeLazy { PreferenceManager.getDefaultSharedPreferences(this) } - private var followState: FollowState = FollowState.NOT_FOLLOWING private var blocking: Boolean = false private var muting: Boolean = false @@ -173,10 +169,9 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide // Obtain information to fill out the profile. viewModel.setAccountInfo(intent.getStringExtra(KEY_ACCOUNT_ID)!!) - val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this) - animateAvatar = sharedPrefs.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false) - animateEmojis = sharedPrefs.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) - hideFab = sharedPrefs.getBoolean(PrefKeys.FAB_HIDE, false) + animateAvatar = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false) + animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) + hideFab = preferences.getBoolean(PrefKeys.FAB_HIDE, false) handleWindowInsets() setupToolbar() @@ -241,7 +236,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide } // 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) { @@ -675,7 +669,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide binding.accountFloatingActionButton.setOnClickListener { mention() } binding.accountFollowButton.setOnClickListener { - val preferences = PreferenceManager.getDefaultSharedPreferences(this) val confirmFollows = preferences.getBoolean(PrefKeys.CONFIRM_FOLLOWS, false) if (viewModel.isSelf) { val intent = Intent(this@AccountActivity, EditProfileActivity::class.java) @@ -721,7 +714,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide showingReblogs = relation.showingReblogs // 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) binding.accountFollowsYouTextView.visible(relation.followedBy && !wellbeingEnabled) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaFragment.kt index 73065b39dc..1847e04813 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaFragment.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.components.account.media +import android.content.SharedPreferences import android.os.Bundle import android.view.Menu import android.view.MenuInflater @@ -28,7 +29,6 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.paging.LoadState -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.GridLayoutManager import com.google.android.material.color.MaterialColors import com.keylesspalace.tusky.R @@ -64,6 +64,9 @@ class AccountMediaFragment : @Inject lateinit var accountManager: AccountManager + @Inject + lateinit var preferences: SharedPreferences + private val binding by viewBinding(FragmentTimelineBinding::bind) private val viewModel: AccountMediaViewModel by viewModels() @@ -78,7 +81,6 @@ class AccountMediaFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) - val preferences = PreferenceManager.getDefaultSharedPreferences(view.context) val useBlurhash = preferences.getBoolean(PrefKeys.USE_BLURHASH, true) adapter = AccountMediaGridAdapter( diff --git a/app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListFragment.kt index b0390efef6..c48d1f3d35 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListFragment.kt @@ -15,12 +15,12 @@ package com.keylesspalace.tusky.components.accountlist +import android.content.SharedPreferences import android.os.Bundle import android.util.Log import android.view.View import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -73,6 +73,9 @@ class AccountListFragment : @Inject lateinit var accountManager: AccountManager + @Inject + lateinit var preferences: SharedPreferences + private val binding by viewBinding(FragmentAccountListBinding::bind) private lateinit var type: Type @@ -101,10 +104,9 @@ class AccountListFragment : binding.swipeRefreshLayout.setOnRefreshListener { fetchAccounts() } binding.swipeRefreshLayout.setColorSchemeResources(R.color.tusky_blue) - val pm = PreferenceManager.getDefaultSharedPreferences(view.context) - val animateAvatar = pm.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false) - val animateEmojis = pm.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) - val showBotOverlay = pm.getBoolean(PrefKeys.SHOW_BOT_OVERLAY, true) + val animateAvatar = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false) + val animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) + val showBotOverlay = preferences.getBoolean(PrefKeys.SHOW_BOT_OVERLAY, true) val activeAccount = accountManager.activeAccount!! diff --git a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt index a12460b9c2..69abe8174e 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt @@ -17,7 +17,6 @@ package com.keylesspalace.tusky.components.announcements import android.content.Context import android.content.Intent -import android.content.SharedPreferences import android.os.Bundle import android.view.Menu import android.view.MenuInflater @@ -27,7 +26,6 @@ import android.widget.PopupWindow import androidx.activity.viewModels import androidx.core.view.MenuProvider import androidx.lifecycle.lifecycleScope -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.color.MaterialColors @@ -100,7 +98,6 @@ class AnnouncementsActivity : val divider = DividerItemDecoration(this, DividerItemDecoration.VERTICAL) binding.announcementsList.addItemDecoration(divider) - val preferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) val wellbeingEnabled = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false) val animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt index 59a3263e43..85e3244956 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt @@ -56,7 +56,6 @@ import androidx.core.view.isVisible import androidx.core.widget.doAfterTextChanged import androidx.core.widget.doOnTextChanged import androidx.lifecycle.lifecycleScope -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.transition.TransitionManager import com.canhub.cropper.CropImage @@ -104,7 +103,6 @@ import com.keylesspalace.tusky.util.loadAvatar import com.keylesspalace.tusky.util.modernLanguageCode import com.keylesspalace.tusky.util.setDrawableTint import com.keylesspalace.tusky.util.show -import com.keylesspalace.tusky.util.unsafeLazy import com.keylesspalace.tusky.util.viewBinding import com.keylesspalace.tusky.util.visible import com.mikepenz.iconics.IconicsDrawable @@ -146,8 +144,6 @@ class ComposeActivity : private var photoUploadUri: Uri? = null - private val preferences by unsafeLazy { PreferenceManager.getDefaultSharedPreferences(this) } - @VisibleForTesting var maximumTootCharacters = InstanceInfoRepository.DEFAULT_CHARACTER_LIMIT var charactersReservedPerUrl = InstanceInfoRepository.DEFAULT_CHARACTERS_RESERVED_PER_URL @@ -290,7 +286,7 @@ class ComposeActivity : setupButtons() subscribeToUpdates(mediaAdapter) - if (accountManager.shouldDisplaySelfUsername(this)) { + if (accountManager.shouldDisplaySelfUsername()) { binding.composeUsernameView.text = getString( R.string.compose_active_account_description, activeAccount.fullName diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt index 828c8957af..1cf0dea5ba 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.components.conversation +import android.content.SharedPreferences import android.os.Bundle import android.view.LayoutInflater import android.view.Menu @@ -30,7 +31,6 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.paging.LoadState -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -79,6 +79,9 @@ class ConversationsFragment : @Inject lateinit var eventHub: EventHub + @Inject + lateinit var preferences: SharedPreferences + private val viewModel: ConversationsViewModel by viewModels() private val binding by viewBinding(FragmentTimelineBinding::bind) @@ -98,8 +101,6 @@ class ConversationsFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) - val preferences = PreferenceManager.getDefaultSharedPreferences(view.context) - val statusDisplayOptions = StatusDisplayOptions( animateAvatars = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false), mediaPreviewEnabled = accountManager.activeAccount?.mediaPreviewEnabled ?: true, @@ -407,10 +408,9 @@ class ConversationsFragment : } private fun onPreferenceChanged(key: String) { - val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) when (key) { PrefKeys.FAB_HIDE -> { - hideFab = sharedPreferences.getBoolean(PrefKeys.FAB_HIDE, false) + hideFab = preferences.getBoolean(PrefKeys.FAB_HIDE, false) } PrefKeys.MEDIA_PREVIEW_ENABLED -> { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt index bd4c6965a1..3483c255db 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt @@ -17,7 +17,6 @@ package com.keylesspalace.tusky.components.login import android.content.Context import android.content.Intent -import android.content.SharedPreferences import android.os.Bundle import android.text.method.LinkMovementMethod import android.util.Log @@ -55,8 +54,6 @@ class LoginActivity : BaseActivity() { private val binding by viewBinding(ActivityLoginBinding::inflate) - private lateinit var preferences: SharedPreferences - private val oauthRedirectUri: String get() { val scheme = getString(R.string.oauth_scheme) @@ -74,6 +71,10 @@ class LoginActivity : BaseActivity() { } } + private var domain: String = "" + private var clientId: String = "" + private var clientSecret: String = "" + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -87,6 +88,12 @@ class LoginActivity : BaseActivity() { binding.domainEditText.setSelection(BuildConfig.CUSTOM_INSTANCE.length) } + if (savedInstanceState != null) { + domain = savedInstanceState.getString(DOMAIN, "") + clientId = savedInstanceState.getString(CLIENT_ID, "") + clientSecret = savedInstanceState.getString(CLIENT_SECRET, "") + } + if (isAccountMigration()) { binding.domainEditText.setText(accountManager.activeAccount!!.domain) binding.domainEditText.isEnabled = false @@ -99,11 +106,6 @@ class LoginActivity : BaseActivity() { .into(binding.loginLogo) } - preferences = getSharedPreferences( - getString(R.string.preferences_file_key), - Context.MODE_PRIVATE - ) - binding.loginButton.setOnClickListener { onLoginClick(true) } binding.whatsAnInstanceTextView.setOnClickListener { @@ -135,16 +137,18 @@ class LoginActivity : BaseActivity() { return super.onCreateOptionsMenu(menu) } - /** - * Obtain the oauth client credentials for this app. This is only necessary the first time the - * app is run on a given server instance. So, after the first authentication, they are - * saved in SharedPreferences and every subsequent run they are simply fetched from there. - */ + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putString(DOMAIN, domain) + outState.putString(CLIENT_ID, clientId) + outState.putString(CLIENT_SECRET, clientSecret) + } + private fun onLoginClick(openInWebView: Boolean) { binding.loginButton.isEnabled = false binding.domainTextInputLayout.error = null - val domain = canonicalizeDomain(binding.domainEditText.text.toString()) + domain = canonicalizeDomain(binding.domainEditText.text.toString()) try { HttpUrl.Builder().host(domain).scheme("https").build() @@ -170,16 +174,9 @@ class LoginActivity : BaseActivity() { getString(R.string.tusky_website) ).fold( { credentials -> - // Before we open browser page we save the data. - // Even if we don't open other apps user may go to password manager or somewhere else - // and we will need to pick up the process where we left off. - // Alternatively we could pass it all as part of the intent and receive it back - // but it is a bit of a workaround. - preferences.edit() - .putString(DOMAIN, domain) - .putString(CLIENT_ID, credentials.clientId) - .putString(CLIENT_SECRET, credentials.clientSecret) - .apply() + // Save credentials. These will be put into the savedInstanceState so they get restored after activity recreation. + clientId = credentials.clientId + clientSecret = credentials.clientSecret redirectUserToAuthorizeAndLogin(domain, credentials.clientId, openInWebView) }, @@ -267,11 +264,6 @@ class LoginActivity : BaseActivity() { } private suspend fun fetchOauthToken(code: String) { - /* restore variables from SharedPreferences */ - val domain = preferences.getNonNullString(DOMAIN, "") - val clientId = preferences.getNonNullString(CLIENT_ID, "") - val clientSecret = preferences.getNonNullString(CLIENT_SECRET, "") - setLoading(true) mastodonApi.fetchOAuthToken( diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt index d1acec2b15..383ea2c964 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesActivity.kt @@ -26,7 +26,6 @@ import androidx.fragment.app.commit import androidx.lifecycle.lifecycleScope import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat -import androidx.preference.PreferenceManager import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.MainActivity import com.keylesspalace.tusky.R @@ -123,16 +122,12 @@ class PreferencesActivity : override fun onResume() { super.onResume() - PreferenceManager.getDefaultSharedPreferences( - this - ).registerOnSharedPreferenceChangeListener(this) + preferences.registerOnSharedPreferenceChangeListener(this) } override fun onPause() { super.onPause() - PreferenceManager.getDefaultSharedPreferences( - this - ).unregisterOnSharedPreferenceChangeListener(this) + preferences.unregisterOnSharedPreferenceChangeListener(this) } override fun onSaveInstanceState(outState: Bundle) { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt index 416bedb871..bebd198ded 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.components.report.fragments +import android.content.SharedPreferences import android.os.Bundle import android.view.Menu import android.view.MenuInflater @@ -28,7 +29,6 @@ import androidx.fragment.app.activityViewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.paging.LoadState -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.SimpleItemAnimator @@ -72,6 +72,9 @@ class ReportStatusesFragment : @Inject lateinit var accountManager: AccountManager + @Inject + lateinit var preferences: SharedPreferences + private val viewModel: ReportViewModel by activityViewModels() private val binding by viewBinding(FragmentReportStatusesBinding::bind) @@ -145,7 +148,6 @@ class ReportStatusesFragment : } private fun initStatusesView() { - val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) val statusDisplayOptions = StatusDisplayOptions( animateAvatars = false, mediaPreviewEnabled = accountManager.activeAccount?.mediaPreviewEnabled ?: true, diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt index a36cfdd84b..5ea7247354 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt @@ -25,7 +25,6 @@ import android.view.MenuItem import androidx.activity.viewModels import androidx.appcompat.widget.SearchView import androidx.core.view.MenuProvider -import androidx.preference.PreferenceManager import com.google.android.material.tabs.TabLayoutMediator import com.keylesspalace.tusky.BottomSheetActivity import com.keylesspalace.tusky.R @@ -33,7 +32,6 @@ import com.keylesspalace.tusky.components.search.adapter.SearchPagerAdapter import com.keylesspalace.tusky.databinding.ActivitySearchBinding import com.keylesspalace.tusky.settings.PrefKeys import com.keylesspalace.tusky.util.reduceSwipeSensitivity -import com.keylesspalace.tusky.util.unsafeLazy import com.keylesspalace.tusky.util.viewBinding import dagger.hilt.android.AndroidEntryPoint @@ -44,8 +42,6 @@ class SearchActivity : BottomSheetActivity(), MenuProvider, SearchView.OnQueryTe private val binding by viewBinding(ActivitySearchBinding::inflate) - private val preferences by unsafeLazy { PreferenceManager.getDefaultSharedPreferences(this) } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(binding.root) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchAccountsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchAccountsFragment.kt index dff440b07e..a413feefc4 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchAccountsFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchAccountsFragment.kt @@ -15,20 +15,25 @@ package com.keylesspalace.tusky.components.search.fragments +import android.content.SharedPreferences import android.os.Bundle import android.view.View import androidx.paging.PagingData import androidx.paging.PagingDataAdapter -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import com.keylesspalace.tusky.components.search.adapter.SearchAccountsAdapter import com.keylesspalace.tusky.entity.TimelineAccount import com.keylesspalace.tusky.settings.PrefKeys import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject import kotlinx.coroutines.flow.Flow @AndroidEntryPoint class SearchAccountsFragment : SearchFragment() { + + @Inject + lateinit var preferences: SharedPreferences + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.searchRecyclerView.addItemDecoration( @@ -40,10 +45,6 @@ class SearchAccountsFragment : SearchFragment() { } override fun createAdapter(): PagingDataAdapter { - val preferences = PreferenceManager.getDefaultSharedPreferences( - binding.searchRecyclerView.context - ) - return SearchAccountsAdapter( this, preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false), diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt index 9a4be2ed6e..031daa1e96 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt @@ -21,6 +21,7 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent +import android.content.SharedPreferences import android.net.Uri import android.os.Build import android.os.Bundle @@ -37,7 +38,6 @@ import androidx.core.view.ViewCompat import androidx.lifecycle.lifecycleScope import androidx.paging.PagingData import androidx.paging.PagingDataAdapter -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import at.connyduck.calladapter.networkresult.fold @@ -76,6 +76,9 @@ class SearchStatusesFragment : SearchFragment(), Status @Inject lateinit var accountManager: AccountManager + @Inject + lateinit var preferences: SharedPreferences + override val data: Flow> get() = viewModel.statusesFlow @@ -111,9 +114,6 @@ class SearchStatusesFragment : SearchFragment(), Status } override fun createAdapter(): PagingDataAdapter { - val preferences = PreferenceManager.getDefaultSharedPreferences( - binding.searchRecyclerView.context - ) val statusDisplayOptions = StatusDisplayOptions( animateAvatars = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false), mediaPreviewEnabled = viewModel.mediaPreviewEnabled, diff --git a/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt index b5d5840f9f..6325a9e60f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/timeline/TimelineFragment.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.components.timeline +import android.content.SharedPreferences import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -30,7 +31,6 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.paging.LoadState -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -92,6 +92,9 @@ class TimelineFragment : @Inject lateinit var eventHub: EventHub + @Inject + lateinit var preferences: SharedPreferences + private val viewModel: TimelineViewModel by unsafeLazy { val viewModelProvider = ViewModelProvider(viewModelStore, defaultViewModelProviderFactory, defaultViewModelCreationExtras) if (kind == TimelineViewModel.Kind.HOME) { @@ -170,7 +173,6 @@ class TimelineFragment : isSwipeToRefreshEnabled = arguments.getBoolean(ARG_ENABLE_SWIPE_TO_REFRESH, true) - val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) readingOrder = ReadingOrder.from(preferences.getString(PrefKeys.READING_ORDER, null)) val statusDisplayOptions = StatusDisplayOptions( @@ -282,7 +284,6 @@ class TimelineFragment : } if (actionButtonPresent()) { - val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) hideFab = preferences.getBoolean(PrefKeys.FAB_HIDE, false) binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(view: RecyclerView, dx: Int, dy: Int) { @@ -317,7 +318,7 @@ class TimelineFragment : } } - updateRelativeTimePeriodically { + updateRelativeTimePeriodically(preferences) { adapter.notifyItemRangeChanged( 0, adapter.itemCount, @@ -568,10 +569,9 @@ class TimelineFragment : } private fun onPreferenceChanged(key: String) { - val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) when (key) { PrefKeys.FAB_HIDE -> { - hideFab = sharedPreferences.getBoolean(PrefKeys.FAB_HIDE, false) + hideFab = preferences.getBoolean(PrefKeys.FAB_HIDE, false) } PrefKeys.MEDIA_PREVIEW_ENABLED -> { @@ -585,7 +585,7 @@ class TimelineFragment : PrefKeys.READING_ORDER -> { readingOrder = ReadingOrder.from( - sharedPreferences.getString(PrefKeys.READING_ORDER, null) + preferences.getString(PrefKeys.READING_ORDER, null) ) } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadFragment.kt index 7ed5695380..9726b7c1f4 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadFragment.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.components.viewthread +import android.content.SharedPreferences import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -30,7 +31,6 @@ import androidx.fragment.app.commit import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.SimpleItemAnimator @@ -57,6 +57,7 @@ import com.keylesspalace.tusky.viewdata.AttachmentViewData.Companion.list import com.keylesspalace.tusky.viewdata.StatusViewData import com.keylesspalace.tusky.viewdata.TranslationViewData import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.delay @@ -69,6 +70,9 @@ class ViewThreadFragment : StatusActionListener, MenuProvider { + @Inject + lateinit var preferences: SharedPreferences + private val viewModel: ViewThreadViewModel by viewModels() private val binding by viewBinding(FragmentViewThreadBinding::bind) @@ -92,7 +96,6 @@ class ViewThreadFragment : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) thisThreadsStatusId = requireArguments().getString(ID_EXTRA)!! - val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) val statusDisplayOptions = StatusDisplayOptions( animateAvatars = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false), diff --git a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsFragment.kt index a0f3cc1e6e..422399161e 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsFragment.kt @@ -15,6 +15,7 @@ package com.keylesspalace.tusky.components.viewthread.edits +import android.content.SharedPreferences import android.os.Bundle import android.util.Log import android.view.Menu @@ -27,7 +28,6 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.SimpleItemAnimator @@ -52,6 +52,7 @@ import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.sizeDp import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject import kotlinx.coroutines.launch @AndroidEntryPoint @@ -61,6 +62,9 @@ class ViewEditsFragment : OnRefreshListener, MenuProvider { + @Inject + lateinit var preferences: SharedPreferences + private val viewModel: ViewEditsViewModel by viewModels() private val binding by viewBinding(FragmentViewEditsBinding::bind) @@ -81,7 +85,6 @@ class ViewEditsFragment : (binding.recyclerView.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false statusId = requireArguments().getString(STATUS_ID_EXTRA)!! - val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) val animateAvatars = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false) val animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false) diff --git a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt index 83f8dada82..32e50f74b3 100644 --- a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt +++ b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt @@ -15,9 +15,8 @@ package com.keylesspalace.tusky.db -import android.content.Context +import android.content.SharedPreferences import android.util.Log -import androidx.preference.PreferenceManager import com.keylesspalace.tusky.db.dao.AccountDao import com.keylesspalace.tusky.db.entity.AccountEntity import com.keylesspalace.tusky.entity.Account @@ -35,7 +34,10 @@ import javax.inject.Singleton private const val TAG = "AccountManager" @Singleton -class AccountManager @Inject constructor(db: AppDatabase) { +class AccountManager @Inject constructor( + db: AppDatabase, + private val preferences: SharedPreferences +) { @Volatile var activeAccount: AccountEntity? = null @@ -236,9 +238,8 @@ class AccountManager @Inject constructor(db: AppDatabase) { /** * @return true if the name of the currently-selected account should be displayed in UIs */ - fun shouldDisplaySelfUsername(context: Context): Boolean { - val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - val showUsernamePreference = sharedPreferences.getString( + fun shouldDisplaySelfUsername(): Boolean { + val showUsernamePreference = preferences.getString( PrefKeys.SHOW_SELF_USERNAME, "disambiguate" ) diff --git a/app/src/main/java/com/keylesspalace/tusky/di/PreferencesEntryPoint.kt b/app/src/main/java/com/keylesspalace/tusky/di/PreferencesEntryPoint.kt new file mode 100644 index 0000000000..5ff1c31c44 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/di/PreferencesEntryPoint.kt @@ -0,0 +1,12 @@ +package com.keylesspalace.tusky.di + +import android.content.SharedPreferences +import dagger.hilt.EntryPoint +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@EntryPoint +@InstallIn(SingletonComponent::class) +interface PreferencesEntryPoint { + fun preferences(): SharedPreferences +} diff --git a/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt b/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt index 927ab6f33e..8f3d2a7c97 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt @@ -21,7 +21,6 @@ import android.os.Build import androidx.appcompat.app.AppCompatDelegate import androidx.core.os.LocaleListCompat import androidx.preference.PreferenceDataStore -import androidx.preference.PreferenceManager import com.keylesspalace.tusky.R import com.keylesspalace.tusky.settings.PrefKeys import dagger.hilt.android.qualifiers.ApplicationContext @@ -33,10 +32,11 @@ class LocaleManager @Inject constructor( @ApplicationContext val context: Context ) : PreferenceDataStore() { - private var prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + @Inject + lateinit var preferences: SharedPreferences fun setLocale() { - val language = prefs.getNonNullString(PrefKeys.LANGUAGE, DEFAULT) + val language = preferences.getNonNullString(PrefKeys.LANGUAGE, DEFAULT) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (language != HANDLED_BY_SYSTEM) { @@ -44,7 +44,7 @@ class LocaleManager @Inject constructor( // hand over the old setting to the system and save a dummy value in Shared Preferences applyLanguageToApp(language) - prefs.edit() + preferences.edit() .putString(PrefKeys.LANGUAGE, HANDLED_BY_SYSTEM) .apply() } @@ -58,7 +58,7 @@ class LocaleManager @Inject constructor( // if we are on Android < 13 we have to save the selected language so we can apply it at appstart // on Android 13+ the system handles it for us if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { - prefs.edit() + preferences.edit() .putString(PrefKeys.LANGUAGE, value) .apply() } @@ -84,7 +84,7 @@ class LocaleManager @Inject constructor( } } } else { - prefs.getNonNullString(PrefKeys.LANGUAGE, DEFAULT) + preferences.getNonNullString(PrefKeys.LANGUAGE, DEFAULT) } } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/RelativeTimeUpdater.kt b/app/src/main/java/com/keylesspalace/tusky/util/RelativeTimeUpdater.kt index a4dd857480..9af2323db6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/RelativeTimeUpdater.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/RelativeTimeUpdater.kt @@ -2,11 +2,11 @@ package com.keylesspalace.tusky.util +import android.content.SharedPreferences import androidx.fragment.app.Fragment import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope import androidx.lifecycle.repeatOnLifecycle -import androidx.preference.PreferenceManager import com.keylesspalace.tusky.settings.PrefKeys import kotlin.time.Duration.Companion.minutes import kotlinx.coroutines.delay @@ -19,8 +19,7 @@ private val UPDATE_INTERVAL = 1.minutes * if setting absoluteTimeView is false. * Start updates when the Fragment becomes visible and stop when it is hidden. */ -fun Fragment.updateRelativeTimePeriodically(callback: Runnable) { - val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) +fun Fragment.updateRelativeTimePeriodically(preferences: SharedPreferences, callback: Runnable) { val lifecycle = viewLifecycleOwner.lifecycle lifecycle.coroutineScope.launch { // This child coroutine will launch each time the Fragment moves to the STARTED state diff --git a/app/src/test/java/com/keylesspalace/tusky/MainActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/MainActivityTest.kt index cd1566edaf..35ccb3c255 100644 --- a/app/src/test/java/com/keylesspalace/tusky/MainActivityTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/MainActivityTest.kt @@ -140,6 +140,13 @@ class MainActivityTest { onBlocking { accountVerifyCredentials() } doReturn NetworkResult.success(account) onBlocking { listAnnouncements(false) } doReturn NetworkResult.success(emptyList()) } + activity.preferences = mock(defaultAnswer = { + when (it.method.returnType) { + String::class.java -> "test" + Boolean::class.java -> false + else -> null + } + }) controller.create().start() return activity } diff --git a/app/src/test/java/com/keylesspalace/tusky/TuskyApplication.kt b/app/src/test/java/com/keylesspalace/tusky/TuskyApplication.kt index a9b066319b..cd07c21c37 100644 --- a/app/src/test/java/com/keylesspalace/tusky/TuskyApplication.kt +++ b/app/src/test/java/com/keylesspalace/tusky/TuskyApplication.kt @@ -16,14 +16,20 @@ package com.keylesspalace.tusky import android.app.Application +import android.content.SharedPreferences +import com.keylesspalace.tusky.di.PreferencesEntryPoint +import dagger.hilt.internal.GeneratedComponent import de.c1710.filemojicompat_defaults.DefaultEmojiPackList import de.c1710.filemojicompat_ui.helpers.EmojiPackHelper +import org.mockito.kotlin.mock // override TuskyApplication for Robolectric tests, only initialize the necessary stuff -class TuskyApplication : Application() { +class TuskyApplication : Application(), PreferencesEntryPoint, GeneratedComponent { override fun onCreate() { super.onCreate() EmojiPackHelper.init(this, DefaultEmojiPackList.get(this)) } + + override fun preferences(): SharedPreferences = mock {} } diff --git a/app/src/test/java/com/keylesspalace/tusky/components/compose/ComposeActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/components/compose/ComposeActivityTest.kt index 654ffe82cb..f8fd924a23 100644 --- a/app/src/test/java/com/keylesspalace/tusky/components/compose/ComposeActivityTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/components/compose/ComposeActivityTest.kt @@ -163,6 +163,14 @@ class ComposeActivityTest { activity.accountManager = accountManagerMock activity.viewModelProviderFactory = testViewModelFactory + activity.preferences = mock(defaultAnswer = { + when (it.method.returnType) { + String::class.java -> "test" + Boolean::class.java -> false + else -> null + } + }) + controller.create().start() shadowOf(getMainLooper()).idle() }