From b75643c697ca0904600697f07f33439a42d447f3 Mon Sep 17 00:00:00 2001 From: deniscerri <64997243+deniscerri@users.noreply.github.com> Date: Sun, 2 Apr 2023 14:07:15 +0200 Subject: [PATCH] added multiple search in searchview using chips --- app/build.gradle | 1 - .../com/deniscerri/ytdlnis/MainActivity.kt | 45 +++---- .../database/repository/ResultRepository.kt | 16 ++- .../database/viewmodel/ResultViewModel.kt | 12 ++ .../ytdlnis/receiver/ShareActivity.kt | 11 +- .../com/deniscerri/ytdlnis/ui/HomeFragment.kt | 120 +++++++++++++----- app/src/main/res/layout/fragment_home.xml | 30 +++++ 7 files changed, 169 insertions(+), 66 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9475301a..b86367d5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,4 +1,3 @@ -import com.android.build.api.dsl.ManagedVirtualDevice plugins { id 'com.android.application' diff --git a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt index 0385d9cb..0490d26f 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/MainActivity.kt @@ -132,34 +132,29 @@ class MainActivity : AppCompatActivity() { val type = intent.type if (Intent.ACTION_SEND == action && type != null) { Log.e(TAG, action) - if (type.equals("application/txt", ignoreCase = true)) { - try { - val uri = if (Build.VERSION.SDK_INT >= 33){ - intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java) - }else{ - intent.getParcelableExtra(Intent.EXTRA_STREAM) - } - val `is` = contentResolver.openInputStream(uri!!) - val textBuilder = StringBuilder() - val reader: Reader = BufferedReader( - InputStreamReader( - `is`, Charset.forName( - StandardCharsets.UTF_8.name() - ) + try { + val uri = if (Build.VERSION.SDK_INT >= 33){ + intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java) + }else{ + intent.getParcelableExtra(Intent.EXTRA_STREAM) + } + val `is` = contentResolver.openInputStream(uri!!) + val textBuilder = StringBuilder() + val reader: Reader = BufferedReader( + InputStreamReader( + `is`, Charset.forName( + StandardCharsets.UTF_8.name() ) ) - var c: Int - while (reader.read().also { c = it } != -1) { - textBuilder.append(c.toChar()) - } - val l = listOf(*textBuilder.toString().split("\n").toTypedArray()) - val lines = LinkedList(l) - (navHostFragment.childFragmentManager.primaryNavigationFragment!! as HomeFragment).handleFileIntent(lines) - } catch (e: Exception) { - e.printStackTrace() + ) + var c: Int + while (reader.read().also { c = it } != -1) { + textBuilder.append(c.toChar()) } - } else { - (navHostFragment.childFragmentManager.primaryNavigationFragment!! as HomeFragment).handleIntent(intent) + val l = listOf(*textBuilder.toString().split("\n").toTypedArray()) + (navHostFragment.childFragmentManager.primaryNavigationFragment!! as HomeFragment).handleFileIntent(l) + } catch (e: Exception) { + e.printStackTrace() } } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt index 45fd02cf..92e180be 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt @@ -52,8 +52,12 @@ class ResultRepository(private val resultDao: ResultDao, private val commandTemp val query = infoUtil.getIDFromYoutubeURL(inputQuery) try { val v = infoUtil.getVideo(query) - if (resetResults) deleteAll() - itemCount.postValue(1) + if (resetResults) { + deleteAll() + itemCount.postValue(1) + }else{ + v!!.playlistTitle = "ytdlnis-Search" + } resultDao.insert(v!!) return arrayListOf(v) } catch (e: Exception) { @@ -87,9 +91,13 @@ class ResultRepository(private val resultDao: ResultDao, private val commandTemp suspend fun getDefault(inputQuery: String, resetResults: Boolean) : ArrayList { val infoUtil = InfoUtil(context) try { - if (resetResults) deleteAll() val items = infoUtil.getFromYTDL(inputQuery) - itemCount.postValue(items.size) + if (resetResults) { + deleteAll() + itemCount.postValue(items.size) + }else{ + items.forEach { it!!.playlistTitle = "ytdlnis-Search" } + } items.forEach { resultDao.insert(it!!) } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt index fa53ec53..d0f6c3da 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt @@ -53,6 +53,18 @@ class ResultViewModel(application: Application) : AndroidViewModel(application) fun getTrending() = viewModelScope.launch(Dispatchers.IO){ repository.updateTrending() } + suspend fun parseQueries(inputQueries: List){ + if (inputQueries.size == 1){ + parseQuery(inputQueries[0], true) + }else { + repository.itemCount.postValue(2) + loadingItems.postValue(true) + inputQueries.forEach { + parseQuery(it, false) + } + loadingItems.postValue(false) + } + } suspend fun parseQuery(inputQuery: String, resetResults: Boolean) : ArrayList { if (resetResults) loadingItems.postValue(true) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt index 684ce99c..63613edd 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt @@ -13,6 +13,7 @@ import android.net.Uri import android.os.Build import android.os.Bundle import android.provider.Settings +import android.util.Log import android.view.Window import android.view.WindowManager import android.widget.TextView @@ -87,8 +88,16 @@ class ShareActivity : AppCompatActivity() { askPermissions() val action = intent.action - val type = intent.type + val type = intent.clipData + Log.e("aa", intent.toString()) if (Intent.ACTION_SEND == action && type != null) { + if (intent.getStringExtra(Intent.EXTRA_TEXT) == null){ + intent.setClass(this, MainActivity::class.java) + startActivity(intent) + finishAffinity() + return + } + val loadingBottomSheet = BottomSheetDialog(this) loadingBottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE) loadingBottomSheet.setContentView(R.layout.please_wait_bottom_sheet) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt index c6a0d875..806a3934 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt @@ -14,6 +14,8 @@ import android.view.View.* import android.widget.* import androidx.constraintlayout.widget.ConstraintLayout import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.core.view.children +import androidx.core.view.forEach import androidx.core.widget.addTextChangedListener import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider @@ -36,6 +38,8 @@ import com.deniscerri.ytdlnis.util.InfoUtil import com.facebook.shimmer.ShimmerFrameLayout import com.google.android.material.appbar.AppBarLayout import com.google.android.material.button.MaterialButton +import com.google.android.material.chip.Chip +import com.google.android.material.chip.ChipGroup import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import com.google.android.material.search.SearchBar @@ -48,7 +52,7 @@ import java.util.* class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickListener { private var inputQuery: String? = null - private var inputQueries: LinkedList? = null + private var inputQueries: MutableList? = null private var inputQueriesLength = 0 private var homeAdapter: HomeAdapter? = null @@ -74,6 +78,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi private var layoutinflater: LayoutInflater? = null private var shimmerCards: ShimmerFrameLayout? = null private var searchBar: SearchBar? = null + private var queriesChipGroup: ChipGroup? = null private var recyclerView: RecyclerView? = null private var uiHandler: Handler? = null private var resultsList: List? = null @@ -118,6 +123,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi //initViews shimmerCards = view.findViewById(R.id.shimmer_results_framelayout) searchBar = view.findViewById(R.id.search_bar) + queriesChipGroup = view.findViewById(R.id.queries) searchSuggestions = view.findViewById(R.id.search_suggestions_scroll_view) searchSuggestionsLinearLayout = view.findViewById(R.id.search_suggestions_linear_layout) searchHistory = view.findViewById(R.id.search_history_scroll_view) @@ -141,7 +147,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi homeAdapter!!.submitList(it) resultsList = it if(resultViewModel.itemCount.value!! > 1 || resultViewModel.itemCount.value!! == -1){ - if (it.size > 1 && it[0].playlistTitle.isNotEmpty() && it[0].playlistTitle != getString(R.string.trendingPlaylist) && it.size > 1){ + if (it.size > 1 && it[0].playlistTitle.isNotEmpty() && it[0].playlistTitle != getString(R.string.trendingPlaylist)){ downloadAllFabCoordinator!!.visibility = VISIBLE }else{ downloadAllFabCoordinator!!.visibility = GONE @@ -185,25 +191,8 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi if (inputQueries != null) { resultViewModel.deleteAll() - inputQueriesLength = inputQueries!!.size - Handler(Looper.getMainLooper()).post { scrollToTop() } - lifecycleScope.launch(){ - withContext(Dispatchers.IO){ - resultViewModel.parseQuery(inputQueries!!.pop()!!, true) - } - - while (!inputQueries!!.isEmpty()) { - inputQuery = inputQueries!!.pop() - withContext(Dispatchers.IO){ - resultViewModel.parseQuery(inputQuery!!, false) - } - } - try { - if (resultsList!!.size > 1 || inputQueriesLength > 1) { - downloadAllFabCoordinator!!.visibility = VISIBLE - } - } catch (ignored: Exception) { - } + lifecycleScope.launch(Dispatchers.IO){ + resultViewModel.parseQueries(inputQueries!!) } } } @@ -213,8 +202,12 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi resultViewModel.checkTrending() } + @SuppressLint("ClickableViewAccessibility") private fun initMenu() { val searchView = requireView().findViewById(R.id.search_view) + val queriesConstraint = requireView().findViewById(R.id.queries_constraint) + val queriesInitStartBtn = queriesConstraint.findViewById(R.id.init_search_query) + infoUtil = InfoUtil(requireContext()) val linkYouCopied = searchView.findViewById(R.id.link_you_copied) searchView.addTransitionListener { view, previousState, newState -> @@ -229,7 +222,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi linkYouCopied.visibility = VISIBLE val textView = linkYouCopied.findViewById(R.id.suggestion_text) textView.text = getString(R.string.link_you_copied) - textView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_language, 0, 0, 0) + textView.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_language, 0, 0, 0) val mb = linkYouCopied.findViewById(R.id.set_search_query_button) mb.visibility = INVISIBLE @@ -255,6 +248,12 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi searchHistoryLinearLayout!!.visibility = GONE linkYouCopied!!.visibility = GONE + if (searchView.editText.text.isEmpty()){ + searchView.editText.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0) + }else{ + searchView.editText.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_plus, 0) + } + lifecycleScope.launch { val suggestions = withContext(Dispatchers.IO){ if (it!!.isEmpty()) { @@ -270,7 +269,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi .inflate(R.layout.search_suggestion_item, null) val textView = v.findViewById(R.id.suggestion_text) textView.text = suggestions[i] - textView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_restore, 0, 0, 0) + textView.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_restore, 0, 0, 0) Handler(Looper.getMainLooper()).post { searchHistoryLinearLayout!!.addView( v @@ -331,6 +330,34 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi false } + searchView.editText.setOnTouchListener(OnTouchListener { v, event -> + try{ + val drawableLeft = 0 + val drawableTop = 1 + val drawableRight = 2 + val drawableBottom = 3 + if (event.action == MotionEvent.ACTION_UP) { + if (event.x > searchView.editText.right - searchView.editText.compoundDrawables[drawableRight].bounds.width() + ) { + val present = queriesChipGroup!!.children.firstOrNull { (it as Chip).text.toString() == searchView.editText.text.toString() } + if (present == null) { + val chip = layoutinflater!!.inflate(R.layout.input_chip, queriesChipGroup, false) as Chip + chip.text = searchView.editText.text + chip.setOnClickListener { + queriesChipGroup!!.removeView(chip) + } + queriesChipGroup!!.addView(chip) + } + if (queriesChipGroup!!.childCount == 0) queriesConstraint.visibility = GONE + else queriesConstraint.visibility = VISIBLE + searchView.editText.setText("") + return@OnTouchListener true + } + } + }catch (ignored: Exception){} + false + }) + searchView.editText.setOnEditorActionListener { textView, i, keyEvent -> initSearch(searchView) true @@ -352,29 +379,52 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi } true } + queriesChipGroup!!.addOnLayoutChangeListener { view, i, i2, i3, i4, i5, i6, i7, i8 -> + if (queriesChipGroup!!.childCount == 0) queriesConstraint.visibility = GONE + else queriesConstraint.visibility = VISIBLE + searchView.editText.setText("") + } + + queriesInitStartBtn.setOnClickListener { + initSearch(searchView) + } } private fun initSearch(searchView: SearchView){ - val inputQuery = searchView.text!!.trim { it <= ' '} - if (inputQuery.isEmpty()) return - searchBar!!.text = searchView.text + + val queryList = mutableListOf() + if (queriesChipGroup!!.childCount > 0){ + queriesChipGroup!!.children.forEach { + val query = (it as Chip).text.toString().trim {it2 -> it2 <= ' '} + if (query.isNotEmpty()){ + queryList.add(query) + } + } + queriesChipGroup!!.removeAllViews() + } + if (searchView.editText.text.isNotBlank()) { + queryList.add(searchView.editText.text.toString()) + } + + if (queryList.isEmpty()) return + if (queryList.size == 1){ + searchBar!!.text = searchView.text + } + searchView.hide() if(!sharedPreferences!!.getBoolean("incognito", false)){ - resultViewModel.addSearchQueryToHistory(inputQuery.toString()) + queryList.forEach { q -> + resultViewModel.addSearchQueryToHistory(q) + } } resultViewModel.deleteAll() lifecycleScope.launch(Dispatchers.IO){ - resultViewModel.parseQuery(inputQuery.toString(), true) + resultViewModel.parseQueries(queryList) } } - fun handleIntent(intent: Intent) { - inputQueries = LinkedList() - inputQueries!!.add(intent.getStringExtra(Intent.EXTRA_TEXT)) - } - - fun handleFileIntent(lines: LinkedList?) { - inputQueries = lines + fun handleFileIntent(lines: List) { + inputQueries = lines.toMutableList() } fun scrollToTop() { diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 65c3dc10..ff8b2607 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -28,6 +28,36 @@ android:layout_height="wrap_content" android:orientation="vertical"> + + + + + + + +