Otter-App-Android-Funkwhale/app/src/main/java/com/github/apognu/otter/activities/SearchActivity.kt

194 lines
6.3 KiB
Kotlin

package com.github.apognu.otter.activities
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.apognu.otter.R
import com.github.apognu.otter.adapters.SearchAdapter
import com.github.apognu.otter.fragments.AlbumsFragment
import com.github.apognu.otter.fragments.ArtistsFragment
import com.github.apognu.otter.models.dao.OtterDatabase
import com.github.apognu.otter.models.dao.toDao
import com.github.apognu.otter.models.domain.Album
import com.github.apognu.otter.models.domain.Artist
import com.github.apognu.otter.models.domain.Track
import com.github.apognu.otter.repositories.AlbumsSearchRepository
import com.github.apognu.otter.repositories.ArtistsSearchRepository
import com.github.apognu.otter.repositories.FavoritesRepository
import com.github.apognu.otter.repositories.TracksSearchRepository
import com.github.apognu.otter.utils.Event
import com.github.apognu.otter.utils.EventBus
import com.github.apognu.otter.utils.untilNetwork
import com.google.android.exoplayer2.offline.Download
import kotlinx.android.synthetic.main.activity_search.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import java.net.URLEncoder
import java.util.*
class SearchActivity(private val database: OtterDatabase, private val favoritesRepository: FavoritesRepository) : AppCompatActivity() {
private lateinit var adapter: SearchAdapter
lateinit var artistsRepository: ArtistsSearchRepository
lateinit var albumsRepository: AlbumsSearchRepository
lateinit var tracksRepository: TracksSearchRepository
var done = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search)
adapter = SearchAdapter(this, SearchResultClickListener(), FavoriteListener()).also {
results.layoutManager = LinearLayoutManager(this)
results.adapter = it
}
search.requestFocus()
}
override fun onResume() {
super.onResume()
lifecycleScope.launch(IO) {
EventBus.get().collect { message ->
when (message) {
is Event.DownloadChanged -> refreshDownloadedTrack(message.download)
}
}
}
artistsRepository = ArtistsSearchRepository(this@SearchActivity, "")
albumsRepository = AlbumsSearchRepository(this@SearchActivity, "")
tracksRepository = TracksSearchRepository(this@SearchActivity, "")
search.setOnQueryTextListener(object : androidx.appcompat.widget.SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(rawQuery: String?): Boolean {
search.clearFocus()
rawQuery?.let {
done = 0
val query = URLEncoder.encode(it, "UTF-8")
artistsRepository.query = query.toLowerCase(Locale.ROOT)
albumsRepository.query = query.toLowerCase(Locale.ROOT)
tracksRepository.query = query.toLowerCase(Locale.ROOT)
search_spinner.visibility = View.VISIBLE
search_empty.visibility = View.GONE
search_no_results.visibility = View.GONE
adapter.artists.clear()
adapter.albums.clear()
adapter.tracks.clear()
adapter.notifyDataSetChanged()
artistsRepository.fetch().untilNetwork(lifecycleScope, IO) { artists, _, _ ->
done++
artists.forEach {
database.artists().run {
insert(it.toDao())
adapter.artists.add(Artist.fromDecoratedEntity(getDecoratedBlocking(it.id)))
}
}
lifecycleScope.launch(Main) {
refresh()
}
}
albumsRepository.fetch().untilNetwork(lifecycleScope, IO) { albums, _, _ ->
done++
albums.forEach {
database.albums().run {
insert(it.toDao())
adapter.albums.add(Album.fromDecoratedEntity(getDecoratedBlocking(it.id)))
}
}
lifecycleScope.launch(Main) {
refresh()
}
}
tracksRepository.fetch().untilNetwork(lifecycleScope, IO) { tracks, _, _ ->
done++
tracks.forEach {
database.tracks().run {
insertWithAssocs(database.artists(), database.albums(), database.uploads(), it)
adapter.tracks.add(Track.fromDecoratedEntity(getDecoratedBlocking(it.id)))
}
}
lifecycleScope.launch(Main) {
refresh()
}
}
}
return true
}
override fun onQueryTextChange(newText: String?) = true
})
}
private fun refresh() {
adapter.notifyDataSetChanged()
if (adapter.artists.size + adapter.albums.size + adapter.tracks.size == 0) {
search_no_results.visibility = View.VISIBLE
} else {
search_no_results.visibility = View.GONE
}
if (done == 3) {
search_spinner.visibility = View.INVISIBLE
}
}
private suspend fun refreshDownloadedTrack(download: Download) {
if (download.state == Download.STATE_COMPLETED) {
/* download.getMetadata()?.let { info ->
adapter.tracks.withIndex().associate { it.value to it.index }.filter { it.key.id == info.id }.toList().getOrNull(0)?.let { match ->
withContext(Dispatchers.Main) {
adapter.tracks[match.second].downloaded = true
adapter.notifyItemChanged(adapter.getPositionOf(SearchAdapter.ResultType.Track, match.second))
}
}
} */
}
}
inner class SearchResultClickListener : SearchAdapter.OnSearchResultClickListener {
override fun onArtistClick(holder: View?, artist: Artist) {
ArtistsFragment.openAlbums(this@SearchActivity, artist)
}
override fun onAlbumClick(holder: View?, album: Album) {
AlbumsFragment.openTracks(this@SearchActivity, album)
}
}
inner class FavoriteListener : SearchAdapter.OnFavoriteListener {
override fun onToggleFavorite(id: Int, state: Boolean) {
when (state) {
true -> favoritesRepository.addFavorite(id)
false -> favoritesRepository.deleteFavorite(id)
}
}
}
}