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) } } } }