Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Expansion of Preferences Manager #96

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

AsimRibo
Copy link
Contributor

@AsimRibo AsimRibo commented Feb 8, 2025

Summary

To make finding specific preferences easier, I decided to split our logic for displaying preferences into 2 parts: all preferences and targeted ones.

Changes

PreferencesTab is now split into 2 parts, tab itself contains TargetedPreferences and there is a button that leads to AllPreferences. I added additional collector that will collect only files and properties sent by clients via watch function.

Recycler

Since a lot data was being collected, Sentinel started stuttering and crashing sometimes. I switched item displaying to recyclerView. Adapter has been a bit harder to write since we had a list of data that also contains a list of data, and everything needs to be displayed. SOLUTION: I went with flattening the preferences data and 2 view holders, where one is preference file item and one is preference property (or child as I called it)

Type

  • Feature: This pull request introduces a new feature.
  • Bug fix: This pull request fixes a bug.
  • Refactor: This pull request refactors existing code.
  • Documentation: This pull request updates documentation.
  • Other: This pull request makes other changes.

Additional information

  • This pull request introduces a breaking change.

Description

TargetedPreferences

SpecificPreferences

Checklist

  • I have performed a self-review of my own code.
  • I have tested my changes, including edge cases.
  • I have added necessary tests for the changes introduced (if applicable).
  • I have updated the documentation to reflect my changes (if applicable).

Additional notes

I will upload documentation a bit later.

Currently if you update an item in AllPreferences and go back to TargetedPreferences, that change won't be shown there. I will try to fix it when I find time, but I don't think it is a blocker for now.

Also, since we have many files, if you minimize a couple of files and they are still visible on the screen when you click to change a preference property and save it, all other files will expand and you will be scrolled away from that specific preference[if minimized items are not visible, this won't happen]. This is because when preference property is changed, we reload entire screen. We would have to adjust logic so we don't reload entire screen but this can be done later.

@AsimRibo AsimRibo added the enhancement New feature or request label Feb 8, 2025
@AsimRibo AsimRibo requested a review from KCeh February 8, 2025 08:33
@AsimRibo AsimRibo self-assigned this Feb 8, 2025
Copy link

sonarqubecloud bot commented Feb 8, 2025

@AsimRibo
Copy link
Contributor Author

AsimRibo commented Feb 8, 2025

We should probably disable this lexicographic ordering, not sure about benefits?

Copy link
Collaborator

@KCeh KCeh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me 🚀
I like idea of "parent" and "child" in recycler viewer to simplify logic.

I just see potential area where we can improve:
Unify targeted and all preferences logic and presentation.
To me, it seems that both logic and presentations are same(ish). For targeted prefs we just pass "filter". And for all prefs we pass empty "filter"/all included filter (depending on how logic works out)
Could we use just one fragment and one VM for both things? If needed we can add nav argument to make distinction which screen is in question.

Correct me if I am wrong. And if you see potential issues.

Comment on lines +16 to +35
/**
* Used to initialize Sentinel.
*
* @param tools list of tools you want to have e.g. ChuckerTool
* @param targetedPreferences map of preference files and their properties, used to make finding specific
* properties more easily, if properties list is empty returns all properties of that file
*
* **Example:**
* // This will contain only tools which are default to Sentinel
* Sentinel.watch()
*
* // This will contain default Sentinel tools + Chucker
* Sentinel.watch(setOf(ChuckerTool()))
*
* // This will contain default Sentinel tools + Chucker and all preference properties of MY_PREFS_FILE
* Sentinel.watch(setOf(ChuckerTool()), mapOf("MY_PREFS_FILE" to emptyList()))
*
* // This will contain default Sentinel tools + Chucker and only MY_PROPERTY property of MY_PREFS_FILE
* Sentinel.watch(setOf(ChuckerTool()), mapOf("MY_PREFS_FILE" to listOf("MY_PROPERTY")))
*/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kudos for docs 👏

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have questions:

  1. I know this might counter your design goal (selected prefs and all prefs on separate screens). But, can you watch all preferences in this selected preferences quick view? How? Regardless of answer could we add an example in docs to watch 2 separate files?
  2. How does the iOS version behave in the default state where a user of lib doesn't specify which preferences they want to watch

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this might counter your design goal (selected prefs and all prefs on separate screens). But, can you watch all preferences in this selected preferences quick view? How? Regardless of answer could we add an example in docs to watch 2 separate files?

In selected preferences quick view, you can monitor multiple files but you have to provide names of those files. If that's what you are asking. IMO, it makes sense since app will have dozens of not so relevant files which are then cluttering your UI [but you can access them in AllFiles].

How does the iOS version behave in the default state where a user of lib doesn't specify which preferences they want to watch

To my knowledge, they don't have option to display all files, they just display what clients want. They also have some logic of mapping where clients can provide readable names of properties (instead of KEY_ONE they can send mapping "key one" which is more readable lets say.) I will have to double check with them just in case.

Comment on lines +11 to +37
internal class TargetedPreferencesCollector(
private val context: Context,
private val targetedPreferences: Map<String, List<String>>
) : Collectors.TargetedPreferences {

override fun invoke(): List<PreferencesData> {
if (targetedPreferences.isEmpty()) return emptyList()

return targetedPreferences.mapNotNull { (fileName, keys) ->
val allPrefs = context.getSharedPreferences(fileName, MODE_PRIVATE).all

val tuples = allPrefs.keys
.filter { keys.isEmpty() || keys.contains(it) }
.mapNotNull { key ->
@Suppress("UNCHECKED_CAST")
when (val value = allPrefs[key]) {
is Boolean -> Triple(PreferenceType.BOOLEAN, key, value)
is Float -> Triple(PreferenceType.FLOAT, key, value)
is Int -> Triple(PreferenceType.INT, key, value)
is Long -> Triple(PreferenceType.LONG, key, value)
is String -> Triple(PreferenceType.STRING, key, value)
is Set<*> -> Triple(PreferenceType.SET, key, value as Set<String>)
else -> null
}
}

if (tuples.isNotEmpty()) PreferencesData(fileName, tuples) else null
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be included in regular PreferencesCollector?
As far as I see only difference is using targetedPreferences as source. We could use targetedPreferences as parameter
Correct me if I am wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it can be done. I would just have to add additional filtering of files since there we also fetch all preference files. 👍

Comment on lines +27 to +29
} else {
emptyList()
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌
Interesting workaround

@KCeh
Copy link
Collaborator

KCeh commented Feb 9, 2025

We should probably disable this lexicographic ordering, not sure about benefits?

What is the source of this "problem"
Ktlint or detekt? We can update rules. Hopefully it will resolve things (and TBT I think just detekt should be enough)

@AsimRibo
Copy link
Contributor Author

Could we use just one fragment and one VM for both things? If needed we can add nav argument to make distinction which screen is in question.

I was being a bit lazy 😄 , but this can be done yes. We will just need some feature flag to toggle visible views since we have that all preferences button, and I plan on adding search functionality limited to AllPreferences (there is no space on TargetedPreferences IMO, maybe if I added collapsing toolbar but we will see).

@AsimRibo
Copy link
Contributor Author

What is the source of this "problem"
Ktlint or detekt? We can update rules. Hopefully it will resolve things (and TBT I think just detekt should be enough)

I think for lexicographic ordering it was detekt. We should probably update rules.

@KCeh
Copy link
Collaborator

KCeh commented Feb 10, 2025

What is the source of this "problem"
Ktlint or detekt? We can update rules. Hopefully it will resolve things (and TBT I think just detekt should be enough)

I think for lexicographic ordering it was detekt. We should probably update rules.

Yea sure, I will open task for it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants