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

Improve search results #1327

Merged

Conversation

pandasoft0
Copy link
Contributor

Issue #1081

@connyduck connyduck added this to the Tusky 9 milestone Jun 21, 2019
Copy link
Collaborator

@connyduck connyduck left a comment

Choose a reason for hiding this comment

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

  • The tabs are blue with white font for me, should be Backgroundcolor + textcolor, blue only for selected tab
  • I like the setup with the SearchFragment that handles common functionality
  • it should probably not be the SearchFragment that inherits from SFragment, but only the SearchStatusFragment?
  • The error handling needs some improvement. The snackbar only retries one of the requests, but i feel like it should retry all 3. Maybe the sad elephant fullscreen is be a better way to show the error?


import android.view.View

interface AnchorActivity {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Without comments its absolutely unclear what this interface is doing. I think you can remove it, Snackbar should also work with another view.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It worked not correct because activity has a scrollable toolbar and fragments have CoordinatorLayout as root. When app searches the layout for snackbar it founds the fragment's CoordinatorLayout. But root CoordinatorLayout hides the bottom of the fragment (with Snackbar) when toolbar shown. I've removed child CoordinatorLayout, so, Snackbar always uses the Activity's CoordinatorLayout

app/src/main/res/layout/activity_search2.xml Outdated Show resolved Hide resolved
data class HashTag(

@field:SerializedName("name")
val name: String,
Copy link
Collaborator

Choose a reason for hiding this comment

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

@SerializedName is not necessary when the property has the same name

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We must not forget to add this file to proguard rules in this case. I prefer to set the SerializedName and do not worry about proguard.

}

override fun onReblog(reblog: Boolean, position: Int) {
//TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't forget to implement these methods

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implemented. I decided to do a trick.
ViewModel stores loaded statuses at the separate list.
When user update the status - app updates the status at this list and invalidate DataSource. DataSource uses this precached list as initial load data. When user changes the search phrase, app clear this list and app uses the network request to load data.
Not sure that this is the best solution, but it allow to use standard paging libraries.

@pandasoft0
Copy link
Contributor Author

pandasoft0 commented Jun 26, 2019

  • Tabs style updated
  • I left the SFragment because all 3 fragments has the similar setup and functionality. Yes, i thought about something like a
    SearchBasicFragment<T>: Fragment(), Injectable, LinkListener{}
    for a Hashtag and Account fragments, and SFragment for SearchStatusFragment, but most code will be the same and from another side - SFragment is lightweight.
    As another solution - i think we may not to use the SFragment at all, but copy-paste some methods from SFragment to a SearchStatusFragment: SearchBasicFragment<...>(), StatusActionListener. Please, let me know if this is a better solution and i will implement it. It's not a problem.

@pandasoft0
Copy link
Contributor Author

About error handling.
Search fragment may show the error not only on initial load but during a scroll also.
Also, it calls 3 different search request for every page.
Yes, we may show the elephant for initial load error, but i prefer to show it per fragment. And refresh content only for that fragment where user clicked the refresh button. So, app may return success on first requests, but error on load next data request for statuses and we don't need to refresh all pages because data on other pages are valid. Also, we must not repeat all 3 requests even if initial request failed for all 3 pages. If user wants to find a hashtag and search failed, he will click repeat on hashtag page and app will do a single request but will not to do 2 other unneeded requests...
But if you want to repeat all failed requests - not a problem for me. I will do.


public override fun getItem(position: Int): Account? {
return super.getItem(position)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

this override is unnecessary, it just calls super

Copy link
Collaborator

@connyduck connyduck left a comment

Choose a reason for hiding this comment

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

This is really well done, nice work.

  • Can you give the tabs the same color as the search bar please (in all themes)? I do not care if you make the tabs the color of the bar or the other way.
  • there is still a problem with error handling, retrying does not work for me sometimes. Seems like all snackbars just reload the first tab or something like that. I can send you a video if you want.
  • (optional) pull to refresh would actually be really nice inside the tabs


public override fun getItem(position: Int): HashTag? {
return super.getItem(position)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

unnecessary override


public override fun getItem(position: Int): Pair<Status, StatusViewData.Concrete>? {
return super.getItem(position)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

unnecessary overrride

Copy link

Choose a reason for hiding this comment

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

This one is required in order to change visibility of the method from protected to public , used at:

import com.google.gson.annotations.SerializedName

data class HashTag(
@field:SerializedName("name")
Copy link
Collaborator

Choose a reason for hiding this comment

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

SerializedName does nothing if the property has the same name anyway.


}

protected fun showNoData(isEmpty: Boolean) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

can be private

if (it == NetworkState.LOADING) {
searchProgressBar.show()
} else
searchProgressBar.hide()
Copy link
Collaborator

Choose a reason for hiding this comment

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

there is a extension function visible so you can do these checks shorter
searchProgressBar.visible(it == NetworkState.LOADING)


val loggedInAccountId = viewModel.activeAccount?.accountId

val popup = PopupMenu(context!!, view)
Copy link
Collaborator

Choose a reason for hiding this comment

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

view.context is always non-null

if (activity == null) {
return
}
AlertDialog.Builder(activity!!)
Copy link
Collaborator

Choose a reason for hiding this comment

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

activity?.let{ makes this shorter and you don't have to use !!

@noln noln force-pushed the upstream/1081/improve_search_results branch from 7f51a3c to 8c5b21a Compare July 5, 2019 18:31
@noln
Copy link

noln commented Jul 5, 2019

@connyduck could you provide the video showing the weird retry behaviour that you mention above please? I've not been able to replicate it.

@connyduck
Copy link
Collaborator

Do you have a new GitHub account?

@connyduck
Copy link
Collaborator

Here is a video https://connyduck.at/device-2019-07-07-143455.mp4
Notice how only the first tab shows data after going back into WiFi and clicking retry.

@noln
Copy link

noln commented Jul 8, 2019

@connyduck Nope, different person. I'm leading on Roma for Android now, so aiming to tidy up and close out any remnant PRs from the fork before starting any new ones, and thanks for the vid!

@noln noln force-pushed the upstream/1081/improve_search_results branch from e9972dd to 635e9a4 Compare July 16, 2019 23:04
@noln
Copy link

noln commented Jul 16, 2019

@connyduck

  • Themes and colours are now showing as requested.
  • That retry bug is fixed too.
  • I've added pull-to-refresh for each tab too.

One thing to note is that searching hashtags results in infinite paging, full of the same result, which looks like a bug. However that's actually what the V2 API returns from server-side when the offset
parameter is changed, so the client-side code is implemented correctly. Therefore the issue will go away when the server returns the correct result.

I think that satisfies all of the prior comments, but would welcome further review and feedback.

Update: Oh and it's no longer WIP, but I don't own the PR so can't rename it. I didn't want to create a new one and lose the review conversation.

@connyduck connyduck changed the title [WIP] Improve search results Improve search results Jul 19, 2019
Copy link
Collaborator

@connyduck connyduck 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 now, thx. Awesome work.

Just one more thing from a UX perspective: What if there are no results on the first tab? Should we somehow indicate that there is more on other tabs? Maybe don't display tabs that have no results? Or reorder them?

I think I would go with merging this and asking users what they think?

@noln
Copy link

noln commented Jul 19, 2019

Good point, hadn't thought of that! A few approaches come to mind:

  1. Show a couple of tappable TextViews that tell the user that there are other results on the other tabs, which takes the user straight there on tap.
  2. Snackbar to do the same as above.
  3. Update the tab titles to show the number of results returned, or "99+" for large numbers of results.

User feedback would definitely be a good guide for that; could even make it switchable behaviour.

@connyduck
Copy link
Collaborator

I merge this now so more people can try it out, lets see.

Update the tab titles to show the number of results returned

Would be nice, but I think we don't get this info from the api?

Thx again

@connyduck connyduck merged commit 3b1288e into tuskyapp:master Jul 19, 2019
@connyduck
Copy link
Collaborator

Oh no, found another bug: The account list does not stop loading and shows the same account over and over again:

device-2019-07-19-201534

@noln

@noln
Copy link

noln commented Jul 19, 2019

@connyduck 😵

Looking at that, it seems that it's instance-specific so perhaps a server-side issue, as it doesn't occur on the (admittedly Pleroma) instances I've tried with the head of master.

Could you raise an issue against me for that, with details of which instance version you're using please?

screenshot-1563560589989

@connyduck
Copy link
Collaborator

connyduck commented Jul 19, 2019

Ok, i tried debugging this and it looks like it is a bug in Mastodon and only happens when searching for ones own account 🤣
Like, I can send in offset=100 and will still get back my own account

I will open a ticket on their repo

@connyduck
Copy link
Collaborator

mastodon/mastodon#11365

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

Successfully merging this pull request may close these issues.

4 participants