2016-07-05 15:19:51 +02:00
|
|
|
/*
|
|
|
|
* Twidere - Twitter client for Android
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.mariotaku.twidere.activity
|
|
|
|
|
2016-12-04 04:58:03 +01:00
|
|
|
import android.accounts.AccountManager
|
2017-04-03 18:20:59 +02:00
|
|
|
import android.app.Activity
|
|
|
|
import android.content.ActivityNotFoundException
|
2016-07-05 15:19:51 +02:00
|
|
|
import android.content.Context
|
2017-04-03 18:20:59 +02:00
|
|
|
import android.content.Intent
|
2016-07-05 15:19:51 +02:00
|
|
|
import android.database.Cursor
|
|
|
|
import android.graphics.PorterDuff.Mode
|
2017-04-03 18:20:59 +02:00
|
|
|
import android.net.Uri
|
2016-07-05 15:19:51 +02:00
|
|
|
import android.os.Bundle
|
2020-01-26 08:35:15 +01:00
|
|
|
import androidx.loader.app.LoaderManager.LoaderCallbacks
|
|
|
|
import androidx.loader.content.CursorLoader
|
|
|
|
import androidx.loader.content.Loader
|
|
|
|
import androidx.core.view.ViewCompat
|
|
|
|
import androidx.core.view.WindowInsetsCompat
|
|
|
|
import androidx.cursoradapter.widget.CursorAdapter
|
2016-07-05 15:19:51 +02:00
|
|
|
import android.text.Editable
|
|
|
|
import android.text.TextUtils
|
|
|
|
import android.text.TextWatcher
|
|
|
|
import android.view.*
|
|
|
|
import android.view.View.OnClickListener
|
2017-04-03 18:26:35 +02:00
|
|
|
import android.view.inputmethod.InputMethodManager
|
2016-07-05 15:19:51 +02:00
|
|
|
import android.widget.*
|
|
|
|
import android.widget.AdapterView.OnItemClickListener
|
|
|
|
import android.widget.AdapterView.OnItemSelectedListener
|
|
|
|
import kotlinx.android.synthetic.main.activity_quick_search_bar.*
|
2016-12-15 06:11:32 +01:00
|
|
|
import org.mariotaku.kpreferences.get
|
2017-04-03 18:20:59 +02:00
|
|
|
import org.mariotaku.ktextension.empty
|
2017-05-13 08:19:23 +02:00
|
|
|
import org.mariotaku.ktextension.spannable
|
2017-04-03 18:20:59 +02:00
|
|
|
import org.mariotaku.twidere.BuildConfig
|
2016-07-05 15:19:51 +02:00
|
|
|
import org.mariotaku.twidere.R
|
2017-05-13 18:15:52 +02:00
|
|
|
import org.mariotaku.twidere.TwidereConstants.*
|
2016-07-05 15:19:51 +02:00
|
|
|
import org.mariotaku.twidere.adapter.AccountsSpinnerAdapter
|
2017-05-13 18:15:52 +02:00
|
|
|
import org.mariotaku.twidere.annotation.AccountType
|
2016-07-05 15:19:51 +02:00
|
|
|
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEY
|
2017-04-09 07:22:56 +02:00
|
|
|
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_QUERY
|
2016-07-05 15:19:51 +02:00
|
|
|
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.ACTION_NAVIGATION_BACK
|
|
|
|
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.CONTEXT_TAG_NAVIGATION
|
2016-12-15 06:11:32 +01:00
|
|
|
import org.mariotaku.twidere.constant.newDocumentApiKey
|
2017-03-07 10:22:02 +01:00
|
|
|
import org.mariotaku.twidere.constant.profileImageStyleKey
|
2017-05-13 18:15:52 +02:00
|
|
|
import org.mariotaku.twidere.extension.appendQueryParameterIgnoreNull
|
2017-03-02 10:23:34 +01:00
|
|
|
import org.mariotaku.twidere.extension.loadProfileImage
|
2016-12-04 06:45:57 +01:00
|
|
|
import org.mariotaku.twidere.model.AccountDetails
|
2017-01-23 07:56:55 +01:00
|
|
|
import org.mariotaku.twidere.model.SuggestionItem
|
2016-07-05 15:19:51 +02:00
|
|
|
import org.mariotaku.twidere.model.UserKey
|
2016-12-04 04:58:03 +01:00
|
|
|
import org.mariotaku.twidere.model.util.AccountUtils
|
2016-07-05 15:19:51 +02:00
|
|
|
import org.mariotaku.twidere.provider.TwidereDataStore.SearchHistory
|
|
|
|
import org.mariotaku.twidere.provider.TwidereDataStore.Suggestions
|
|
|
|
import org.mariotaku.twidere.util.*
|
|
|
|
import org.mariotaku.twidere.util.EditTextEnterHandler.EnterListener
|
|
|
|
import org.mariotaku.twidere.util.content.ContentResolverUtils
|
2017-09-18 07:28:36 +02:00
|
|
|
import org.mariotaku.twidere.util.promotion.PromotionService
|
2017-04-02 18:35:31 +02:00
|
|
|
import org.mariotaku.twidere.view.ProfileImageView
|
2016-07-05 15:19:51 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Created by mariotaku on 15/1/6.
|
|
|
|
*/
|
2016-07-06 15:21:34 +02:00
|
|
|
class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<Cursor?>,
|
2017-06-25 17:01:33 +02:00
|
|
|
OnItemSelectedListener, OnItemClickListener, SwipeDismissListViewTouchListener.DismissCallbacks {
|
2016-07-05 15:19:51 +02:00
|
|
|
|
|
|
|
private var textChanged: Boolean = false
|
2017-04-03 18:20:59 +02:00
|
|
|
private var hasQrScanner: Boolean = false
|
|
|
|
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
hasQrScanner = run {
|
|
|
|
val scanIntent = Intent(ACTION_ZXING_SCAN)
|
2017-04-03 18:26:35 +02:00
|
|
|
scanIntent.putExtra(EXTRA_ZXING_SCAN_MODE, ZXING_SCAN_MODE_QR_CODE)
|
2017-04-03 18:20:59 +02:00
|
|
|
return@run scanIntent.resolveActivity(packageManager) != null
|
|
|
|
}
|
|
|
|
|
|
|
|
setContentView(R.layout.activity_quick_search_bar)
|
2017-09-18 07:28:36 +02:00
|
|
|
|
|
|
|
promotionService.setupBanner(adContainer, PromotionService.BannerType.QUICK_SEARCH,
|
|
|
|
FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
|
|
|
ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM))
|
|
|
|
|
2017-04-03 18:20:59 +02:00
|
|
|
val am = AccountManager.get(this)
|
|
|
|
val accounts = AccountUtils.getAllAccountDetails(am, AccountUtils.getAccounts(am), true).toList()
|
|
|
|
val accountsSpinnerAdapter = AccountsSpinnerAdapter(this, R.layout.spinner_item_account_icon,
|
2017-09-03 15:23:45 +02:00
|
|
|
requestManager = requestManager)
|
2017-04-03 18:20:59 +02:00
|
|
|
accountsSpinnerAdapter.setDropDownViewResource(R.layout.list_item_simple_user)
|
|
|
|
accountsSpinnerAdapter.addAll(accounts)
|
|
|
|
accountSpinner.adapter = accountsSpinnerAdapter
|
|
|
|
accountSpinner.onItemSelectedListener = this
|
|
|
|
if (savedInstanceState == null) {
|
|
|
|
val intent = intent
|
|
|
|
val accountKey = intent.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
|
|
|
|
var index = -1
|
|
|
|
if (accountKey != null) {
|
|
|
|
index = accountsSpinnerAdapter.findPositionByKey(accountKey)
|
|
|
|
}
|
|
|
|
if (index != -1) {
|
|
|
|
accountSpinner.setSelection(index)
|
|
|
|
}
|
|
|
|
}
|
2017-06-25 17:01:33 +02:00
|
|
|
ViewCompat.setOnApplyWindowInsetsListener(mainContent, this)
|
2017-09-18 07:28:36 +02:00
|
|
|
mainContent.setOnClickListener {
|
|
|
|
finish()
|
|
|
|
}
|
2017-04-03 18:20:59 +02:00
|
|
|
suggestionsList.adapter = SuggestionsAdapter(this)
|
|
|
|
suggestionsList.onItemClickListener = this
|
|
|
|
|
|
|
|
val listener = SwipeDismissListViewTouchListener(suggestionsList, this)
|
|
|
|
suggestionsList.setOnTouchListener(listener)
|
|
|
|
suggestionsList.setOnScrollListener(listener.makeScrollListener())
|
|
|
|
searchSubmit.setOnClickListener(this)
|
|
|
|
|
|
|
|
EditTextEnterHandler.attach(searchQuery, object : EnterListener {
|
|
|
|
override fun shouldCallListener(): Boolean {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onHitEnter(): Boolean {
|
|
|
|
doSearch()
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}, true)
|
|
|
|
searchQuery.addTextChangedListener(object : TextWatcher {
|
|
|
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
|
|
|
textChanged = true
|
|
|
|
updateSubmitButton()
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun afterTextChanged(s: Editable) {
|
|
|
|
supportLoaderManager.restartLoader(0, null, this@QuickSearchBarActivity)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2017-04-09 07:22:56 +02:00
|
|
|
if (savedInstanceState == null) {
|
|
|
|
searchQuery.setText(intent.getStringExtra(EXTRA_QUERY))
|
|
|
|
searchQuery.setSelection(searchQuery.length())
|
|
|
|
}
|
|
|
|
|
2017-04-03 18:20:59 +02:00
|
|
|
supportLoaderManager.initLoader(0, null, this)
|
|
|
|
|
|
|
|
updateSubmitButton()
|
2017-09-18 07:28:36 +02:00
|
|
|
promotionService.loadBanner(adContainer)
|
2017-04-03 18:20:59 +02:00
|
|
|
}
|
2016-07-05 15:19:51 +02:00
|
|
|
|
|
|
|
override fun canDismiss(position: Int): Boolean {
|
2016-07-06 15:21:34 +02:00
|
|
|
val adapter = suggestionsList.adapter as SuggestionsAdapter
|
|
|
|
return adapter.getItemViewType(position) == SuggestionsAdapter.VIEW_TYPE_SEARCH_HISTORY
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun onDismiss(listView: ListView, reverseSortedPositions: IntArray) {
|
2016-07-06 15:21:34 +02:00
|
|
|
val adapter = suggestionsList.adapter as SuggestionsAdapter
|
2016-07-05 15:19:51 +02:00
|
|
|
val ids = LongArray(reverseSortedPositions.size)
|
2020-06-08 23:07:20 +02:00
|
|
|
for (i in reverseSortedPositions.indices) {
|
2016-07-05 15:19:51 +02:00
|
|
|
val position = reverseSortedPositions[i]
|
2016-07-06 15:21:34 +02:00
|
|
|
val item = adapter.getSuggestionItem(position) ?: return
|
2016-07-05 15:19:51 +02:00
|
|
|
ids[i] = item._id
|
|
|
|
}
|
2016-07-06 15:21:34 +02:00
|
|
|
adapter.addRemovedPositions(reverseSortedPositions)
|
2017-02-13 14:33:45 +01:00
|
|
|
ContentResolverUtils.bulkDelete(contentResolver, SearchHistory.CONTENT_URI, SearchHistory._ID,
|
|
|
|
false, ids, null, null)
|
2016-07-05 15:19:51 +02:00
|
|
|
supportLoaderManager.restartLoader(0, null, this)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onClick(v: View) {
|
|
|
|
when (v) {
|
|
|
|
searchSubmit -> {
|
2017-04-03 18:20:59 +02:00
|
|
|
if (searchQuery.empty && hasQrScanner) {
|
2017-04-03 18:26:35 +02:00
|
|
|
val currentFocus = currentFocus
|
|
|
|
if (currentFocus === searchQuery) {
|
|
|
|
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
|
|
|
imm.hideSoftInputFromWindow(currentFocus.windowToken, 0)
|
|
|
|
currentFocus.clearFocus()
|
|
|
|
}
|
|
|
|
|
2017-04-03 18:20:59 +02:00
|
|
|
val scanIntent = Intent(ACTION_ZXING_SCAN)
|
2017-04-03 18:26:35 +02:00
|
|
|
scanIntent.putExtra(EXTRA_ZXING_SCAN_MODE, ZXING_SCAN_MODE_QR_CODE)
|
2017-04-03 18:20:59 +02:00
|
|
|
try {
|
|
|
|
startActivityForResult(scanIntent, REQUEST_SCAN_QR)
|
|
|
|
} catch (e: ActivityNotFoundException) {
|
|
|
|
// Ignore
|
2017-04-14 12:46:14 +02:00
|
|
|
Toast.makeText(this, R.string.message_toast_qr_scanner_not_supported,
|
|
|
|
Toast.LENGTH_SHORT).show()
|
|
|
|
} catch (e: SecurityException) {
|
|
|
|
// Goddamned SAMSUNG again!!!
|
|
|
|
Toast.makeText(this, R.string.message_toast_qr_scanner_not_supported,
|
|
|
|
Toast.LENGTH_SHORT).show()
|
2017-04-03 18:20:59 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
doSearch()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
2020-05-31 08:02:32 +02:00
|
|
|
super.onActivityResult(requestCode, resultCode, data)
|
2017-04-03 18:20:59 +02:00
|
|
|
when (requestCode) {
|
|
|
|
REQUEST_SCAN_QR -> {
|
|
|
|
if (resultCode == Activity.RESULT_OK && data != null) {
|
2017-04-03 18:29:03 +02:00
|
|
|
val scanResult = data.getStringExtra(EXTRA_ZXING_SCAN_RESULT) ?: run {
|
|
|
|
Toast.makeText(this, R.string.message_toast_qr_scanner_not_supported,
|
|
|
|
Toast.LENGTH_SHORT).show()
|
|
|
|
return
|
|
|
|
}
|
2017-04-03 18:20:59 +02:00
|
|
|
val viewIntent = Intent(Intent.ACTION_VIEW, Uri.parse(scanResult)).apply {
|
|
|
|
`package` = BuildConfig.APPLICATION_ID
|
|
|
|
putExtra(EXTRA_ACCOUNT_KEY, selectedAccountDetails?.key)
|
|
|
|
}
|
2017-04-03 18:29:03 +02:00
|
|
|
val componentName = viewIntent.resolveActivity(packageManager) ?: run {
|
|
|
|
Toast.makeText(this, R.string.message_toast_qr_scan_link_not_supported,
|
|
|
|
Toast.LENGTH_SHORT).show()
|
|
|
|
return
|
|
|
|
}
|
2017-04-03 18:20:59 +02:00
|
|
|
viewIntent.component = componentName
|
|
|
|
startActivity(viewIntent)
|
|
|
|
finish()
|
|
|
|
}
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-06 15:21:34 +02:00
|
|
|
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor?> {
|
2017-05-13 18:15:52 +02:00
|
|
|
val account = selectedAccountDetails
|
2016-07-05 15:19:51 +02:00
|
|
|
val builder = Suggestions.Search.CONTENT_URI.buildUpon()
|
|
|
|
builder.appendQueryParameter(QUERY_PARAM_QUERY, ParseUtils.parseString(searchQuery.text))
|
2017-05-13 18:15:52 +02:00
|
|
|
if (account != null) {
|
|
|
|
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_KEY, account.key.toString())
|
|
|
|
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_TYPE, account.type)
|
|
|
|
if (account.type != AccountType.MASTODON) {
|
|
|
|
builder.appendQueryParameterIgnoreNull(QUERY_PARAM_ACCOUNT_HOST, account.key.host)
|
|
|
|
}
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
|
|
|
return CursorLoader(this, builder.build(), Suggestions.Search.COLUMNS, null, null, null)
|
|
|
|
}
|
|
|
|
|
2016-07-06 15:21:34 +02:00
|
|
|
override fun onLoadFinished(loader: Loader<Cursor?>, data: Cursor?) {
|
|
|
|
val adapter = suggestionsList.adapter as SuggestionsAdapter
|
|
|
|
adapter.changeCursor(data)
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
|
|
|
|
2016-07-06 15:21:34 +02:00
|
|
|
override fun onLoaderReset(loader: Loader<Cursor?>) {
|
|
|
|
val adapter = suggestionsList.adapter as SuggestionsAdapter
|
|
|
|
adapter.changeCursor(null)
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
|
|
|
|
2017-06-25 17:01:33 +02:00
|
|
|
|
|
|
|
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
|
|
|
|
super.onApplyWindowInsets(v, insets)
|
2016-07-05 15:19:51 +02:00
|
|
|
updateWindowAttributes()
|
2017-06-25 17:01:33 +02:00
|
|
|
return insets
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
2017-04-23 13:09:16 +02:00
|
|
|
val adapter = suggestionsList.adapter as SuggestionsAdapter
|
|
|
|
val item = adapter.getSuggestionItem(position) ?: return
|
|
|
|
val details = selectedAccountDetails ?: return
|
2016-07-06 15:21:34 +02:00
|
|
|
when (adapter.getItemViewType(position)) {
|
2016-07-05 15:19:51 +02:00
|
|
|
SuggestionsAdapter.VIEW_TYPE_USER_SUGGESTION_ITEM -> {
|
2017-04-23 13:09:16 +02:00
|
|
|
IntentUtils.openUserProfile(this, details.key,
|
2017-04-07 13:05:02 +02:00
|
|
|
UserKey.valueOf(item.extra_id!!), item.summary, null,
|
2017-08-28 06:31:19 +02:00
|
|
|
preferences[newDocumentApiKey], null)
|
2016-07-05 15:19:51 +02:00
|
|
|
finish()
|
|
|
|
}
|
|
|
|
SuggestionsAdapter.VIEW_TYPE_USER_SCREEN_NAME -> {
|
2017-04-23 13:09:16 +02:00
|
|
|
IntentUtils.openUserProfile(this, details.key, null, item.title,
|
2017-08-28 06:31:19 +02:00
|
|
|
null, preferences[newDocumentApiKey], null)
|
2016-07-05 15:19:51 +02:00
|
|
|
finish()
|
|
|
|
}
|
|
|
|
SuggestionsAdapter.VIEW_TYPE_SAVED_SEARCH, SuggestionsAdapter.VIEW_TYPE_SEARCH_HISTORY -> {
|
2017-04-23 13:09:16 +02:00
|
|
|
val query = item.title ?: return
|
|
|
|
IntentUtils.openSearch(this, details.key, query)
|
2017-04-09 07:22:56 +02:00
|
|
|
setResult(RESULT_SEARCH_PERFORMED)
|
2016-07-05 15:19:51 +02:00
|
|
|
finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-16 12:35:54 +02:00
|
|
|
override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) {
|
2016-07-05 15:19:51 +02:00
|
|
|
supportLoaderManager.restartLoader(0, null, this)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onNothingSelected(parent: AdapterView<*>) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
|
|
|
|
val action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState)
|
|
|
|
if (ACTION_NAVIGATION_BACK == action && searchQuery.length() == 0) {
|
|
|
|
if (!textChanged) {
|
|
|
|
onBackPressed()
|
|
|
|
} else {
|
|
|
|
textChanged = false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return super.handleKeyboardShortcutSingle(handler, keyCode, event, metaState)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onResume() {
|
|
|
|
super.onResume()
|
|
|
|
updateWindowAttributes()
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun doSearch() {
|
|
|
|
if (isFinishing) return
|
|
|
|
val query = ParseUtils.parseString(searchQuery.text)
|
|
|
|
if (TextUtils.isEmpty(query)) return
|
2016-12-15 06:11:32 +01:00
|
|
|
val details = selectedAccountDetails ?: return
|
|
|
|
IntentUtils.openSearch(this, details.key, query)
|
2017-04-09 07:22:56 +02:00
|
|
|
setResult(RESULT_SEARCH_PERFORMED)
|
2016-07-05 15:19:51 +02:00
|
|
|
finish()
|
|
|
|
}
|
|
|
|
|
2016-12-15 06:11:32 +01:00
|
|
|
private val selectedAccountDetails: AccountDetails?
|
2016-07-05 15:19:51 +02:00
|
|
|
get() {
|
2016-12-15 06:11:32 +01:00
|
|
|
return accountSpinner.selectedItem as? AccountDetails
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun updateWindowAttributes() {
|
2017-06-25 17:01:33 +02:00
|
|
|
val window = window ?: return
|
2016-07-05 15:19:51 +02:00
|
|
|
val attributes = window.attributes
|
|
|
|
attributes.gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
|
2017-06-28 15:27:47 +02:00
|
|
|
attributes.y = systemWindowsInsets?.top ?: 0
|
2016-07-05 15:19:51 +02:00
|
|
|
window.attributes = attributes
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun setSearchQueryText(query: String?) {
|
|
|
|
searchQuery.setText(query)
|
|
|
|
if (query == null) return
|
|
|
|
searchQuery.setSelection(query.length)
|
|
|
|
}
|
|
|
|
|
2017-04-03 18:20:59 +02:00
|
|
|
private fun updateSubmitButton() {
|
|
|
|
if (searchQuery.empty && hasQrScanner) {
|
|
|
|
searchSubmit.setImageResource(R.drawable.ic_action_qr_scan)
|
|
|
|
} else {
|
|
|
|
searchSubmit.setImageResource(R.drawable.ic_action_search)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-06 15:21:34 +02:00
|
|
|
class SuggestionsAdapter internal constructor(
|
|
|
|
private val activity: QuickSearchBarActivity
|
|
|
|
) : CursorAdapter(activity, null, 0), OnClickListener {
|
2016-07-05 15:19:51 +02:00
|
|
|
|
2017-03-07 10:22:02 +01:00
|
|
|
private val profileImageStyle = activity.preferences[profileImageStyleKey]
|
2017-04-02 18:35:31 +02:00
|
|
|
private val profileImageSize = activity.getString(R.string.profile_image_size)
|
2017-09-03 15:23:45 +02:00
|
|
|
private val requestManager = activity.requestManager
|
2017-03-02 10:23:34 +01:00
|
|
|
private val inflater = LayoutInflater.from(activity)
|
|
|
|
private val userColorNameManager = activity.userColorNameManager
|
2017-09-25 08:37:03 +02:00
|
|
|
private val removedPositions = ArrayList<Int>()
|
2016-07-05 15:19:51 +02:00
|
|
|
|
2017-01-23 07:56:55 +01:00
|
|
|
private var indices: SuggestionItem.Indices? = null
|
2016-07-05 15:19:51 +02:00
|
|
|
|
|
|
|
override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View {
|
|
|
|
when (getActualItemViewType(cursor.position)) {
|
|
|
|
VIEW_TYPE_SEARCH_HISTORY, VIEW_TYPE_SAVED_SEARCH -> {
|
2016-07-07 15:49:36 +02:00
|
|
|
val view = inflater.inflate(R.layout.list_item_suggestion_search, parent, false)
|
2016-07-05 15:19:51 +02:00
|
|
|
val holder = SearchViewHolder(view)
|
|
|
|
holder.edit_query.setOnClickListener(this)
|
|
|
|
view.tag = holder
|
|
|
|
return view
|
|
|
|
}
|
|
|
|
VIEW_TYPE_USER_SUGGESTION_ITEM, VIEW_TYPE_USER_SCREEN_NAME -> {
|
2016-07-07 15:49:36 +02:00
|
|
|
val view = inflater.inflate(R.layout.list_item_suggestion_user, parent, false)
|
2017-04-02 18:35:31 +02:00
|
|
|
view.tag = UserViewHolder(view).apply {
|
|
|
|
icon.style = profileImageStyle
|
|
|
|
}
|
2016-07-05 15:19:51 +02:00
|
|
|
return view
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw UnsupportedOperationException("Unknown viewType")
|
|
|
|
}
|
|
|
|
|
|
|
|
internal fun getSuggestionItem(position: Int): SuggestionItem? {
|
2016-07-07 15:49:36 +02:00
|
|
|
val cursor = (getItem(position) ?: return null) as Cursor
|
2016-07-06 15:21:34 +02:00
|
|
|
val indices = indices ?: return null
|
2016-07-05 15:19:51 +02:00
|
|
|
return SuggestionItem(cursor, indices)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun bindView(view: View, context: Context, cursor: Cursor) {
|
2016-07-06 15:21:34 +02:00
|
|
|
val indices = indices!!
|
2016-07-05 15:19:51 +02:00
|
|
|
when (getActualItemViewType(cursor.position)) {
|
|
|
|
VIEW_TYPE_SEARCH_HISTORY -> {
|
|
|
|
val holder = view.tag as SearchViewHolder
|
2016-07-06 15:21:34 +02:00
|
|
|
val title = cursor.getString(indices.title)
|
2016-07-05 15:19:51 +02:00
|
|
|
holder.edit_query.tag = title
|
2017-05-13 08:19:23 +02:00
|
|
|
holder.text1.spannable = title
|
2016-07-05 15:19:51 +02:00
|
|
|
holder.icon.setImageResource(R.drawable.ic_action_history)
|
|
|
|
}
|
|
|
|
VIEW_TYPE_SAVED_SEARCH -> {
|
|
|
|
val holder = view.tag as SearchViewHolder
|
2016-07-06 15:21:34 +02:00
|
|
|
val title = cursor.getString(indices.title)
|
2016-07-05 15:19:51 +02:00
|
|
|
holder.edit_query.tag = title
|
2017-05-13 08:19:23 +02:00
|
|
|
holder.text1.spannable = title
|
2016-07-05 15:19:51 +02:00
|
|
|
holder.icon.setImageResource(R.drawable.ic_action_save)
|
|
|
|
}
|
|
|
|
VIEW_TYPE_USER_SUGGESTION_ITEM -> {
|
|
|
|
val holder = view.tag as UserViewHolder
|
2016-12-04 06:45:57 +01:00
|
|
|
val userKey = UserKey.valueOf(cursor.getString(indices.extra_id))
|
2017-05-13 08:19:23 +02:00
|
|
|
holder.text1.spannable = userColorNameManager.getUserNickname(userKey,
|
2016-07-06 15:21:34 +02:00
|
|
|
cursor.getString(indices.title))
|
2016-07-05 15:19:51 +02:00
|
|
|
holder.text2.visibility = View.VISIBLE
|
2017-05-13 08:19:23 +02:00
|
|
|
holder.text2.spannable = "@${cursor.getString(indices.summary)}"
|
2016-07-05 15:19:51 +02:00
|
|
|
holder.icon.clearColorFilter()
|
2017-03-07 10:22:02 +01:00
|
|
|
requestManager.loadProfileImage(context, cursor.getString(indices.icon),
|
2017-04-02 18:35:31 +02:00
|
|
|
profileImageStyle, cornerRadius = holder.icon.cornerRadius,
|
|
|
|
cornerRadiusRatio = holder.icon.cornerRadiusRatio,
|
|
|
|
size = profileImageSize).into(holder.icon)
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
|
|
|
VIEW_TYPE_USER_SCREEN_NAME -> {
|
|
|
|
val holder = view.tag as UserViewHolder
|
2017-05-13 08:19:23 +02:00
|
|
|
holder.text1.spannable = "@${cursor.getString(indices.title)}"
|
2016-07-05 15:19:51 +02:00
|
|
|
holder.text2.visibility = View.GONE
|
|
|
|
holder.icon.setColorFilter(holder.text1.currentTextColor, Mode.SRC_ATOP)
|
2017-03-01 15:12:25 +01:00
|
|
|
//TODO cancel image load
|
2016-07-05 15:19:51 +02:00
|
|
|
holder.icon.setImageResource(R.drawable.ic_action_user)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun getItemViewType(position: Int): Int {
|
|
|
|
return getActualItemViewType(getActualPosition(position))
|
|
|
|
}
|
|
|
|
|
|
|
|
fun getActualItemViewType(position: Int): Int {
|
|
|
|
val cursor = super.getItem(position) as Cursor
|
2016-07-06 15:21:34 +02:00
|
|
|
if (indices == null) throw NullPointerException()
|
|
|
|
when (cursor.getString(indices!!.type)) {
|
2016-07-05 15:19:51 +02:00
|
|
|
Suggestions.Search.TYPE_SAVED_SEARCH -> {
|
|
|
|
return VIEW_TYPE_SAVED_SEARCH
|
|
|
|
}
|
|
|
|
Suggestions.Search.TYPE_SCREEN_NAME -> {
|
|
|
|
return VIEW_TYPE_USER_SCREEN_NAME
|
|
|
|
}
|
|
|
|
Suggestions.Search.TYPE_SEARCH_HISTORY -> {
|
|
|
|
return VIEW_TYPE_SEARCH_HISTORY
|
|
|
|
}
|
|
|
|
Suggestions.Search.TYPE_USER -> {
|
|
|
|
return VIEW_TYPE_USER_SUGGESTION_ITEM
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Adapter.IGNORE_ITEM_VIEW_TYPE
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun getViewTypeCount(): Int {
|
|
|
|
return 4
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun onClick(v: View) {
|
|
|
|
when (v.id) {
|
|
|
|
R.id.edit_query -> {
|
2016-07-06 15:21:34 +02:00
|
|
|
activity.setSearchQueryText(v.tag as String)
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-06 15:21:34 +02:00
|
|
|
override fun swapCursor(newCursor: Cursor?): Cursor? {
|
2017-03-04 17:35:14 +01:00
|
|
|
indices = newCursor?.let(SuggestionItem::Indices)
|
2017-06-08 12:45:21 +02:00
|
|
|
removedPositions.clear()
|
2016-07-05 15:19:51 +02:00
|
|
|
return super.swapCursor(newCursor)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun getCount(): Int {
|
2017-09-25 08:37:03 +02:00
|
|
|
return super.getCount() - removedPositions.size
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
|
|
|
|
2016-07-07 15:49:36 +02:00
|
|
|
override fun getItem(position: Int): Any? {
|
2016-07-05 15:19:51 +02:00
|
|
|
return super.getItem(getActualPosition(position))
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun getItemId(position: Int): Long {
|
|
|
|
return super.getItemId(getActualPosition(position))
|
|
|
|
}
|
|
|
|
|
2016-07-06 15:21:34 +02:00
|
|
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
2016-07-05 15:19:51 +02:00
|
|
|
return super.getView(getActualPosition(position), convertView, parent)
|
|
|
|
}
|
|
|
|
|
2016-07-06 15:21:34 +02:00
|
|
|
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
|
2016-07-05 15:19:51 +02:00
|
|
|
return super.getDropDownView(getActualPosition(position), convertView, parent)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun getActualPosition(position: Int): Int {
|
|
|
|
var skipped = 0
|
2017-09-25 08:37:03 +02:00
|
|
|
for (i in 0 until removedPositions.size) {
|
2020-06-08 23:07:20 +02:00
|
|
|
if (position + skipped >= removedPositions[i]) {
|
2016-07-05 15:19:51 +02:00
|
|
|
skipped++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return position + skipped
|
|
|
|
}
|
|
|
|
|
|
|
|
fun addRemovedPositions(positions: IntArray) {
|
|
|
|
for (position in positions) {
|
2017-03-02 10:23:34 +01:00
|
|
|
removedPositions.add(getActualPosition(position))
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
2017-03-02 10:23:34 +01:00
|
|
|
removedPositions.sort()
|
2016-07-05 15:19:51 +02:00
|
|
|
notifyDataSetChanged()
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class SearchViewHolder(view: View) {
|
|
|
|
|
2017-06-19 06:11:28 +02:00
|
|
|
internal val icon: ImageView = view.findViewById(android.R.id.icon)
|
|
|
|
internal val text1: TextView = view.findViewById(android.R.id.text1)
|
|
|
|
internal val edit_query: View = view.findViewById(R.id.edit_query)
|
2016-07-05 15:19:51 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class UserViewHolder(view: View) {
|
|
|
|
|
2017-06-19 06:11:28 +02:00
|
|
|
internal val icon: ProfileImageView = view.findViewById(android.R.id.icon)
|
|
|
|
internal val text1: TextView = view.findViewById(android.R.id.text1)
|
|
|
|
internal val text2: TextView = view.findViewById(android.R.id.text2)
|
2016-07-05 15:19:51 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
|
2020-06-08 23:11:06 +02:00
|
|
|
internal const val VIEW_TYPE_SEARCH_HISTORY = 0
|
|
|
|
internal const val VIEW_TYPE_SAVED_SEARCH = 1
|
|
|
|
internal const val VIEW_TYPE_USER_SUGGESTION_ITEM = 2
|
|
|
|
internal const val VIEW_TYPE_USER_SCREEN_NAME = 3
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-03 18:20:59 +02:00
|
|
|
companion object {
|
|
|
|
const val ACTION_ZXING_SCAN = "com.google.zxing.client.android.SCAN"
|
2017-04-03 18:26:35 +02:00
|
|
|
const val EXTRA_ZXING_SCAN_MODE = "SCAN_MODE"
|
|
|
|
const val EXTRA_ZXING_SCAN_RESULT = "SCAN_RESULT"
|
|
|
|
const val ZXING_SCAN_MODE_QR_CODE = "QR_CODE_MODE"
|
2017-04-03 18:20:59 +02:00
|
|
|
const val REQUEST_SCAN_QR = 101
|
2017-04-09 07:22:56 +02:00
|
|
|
|
|
|
|
const val RESULT_SEARCH_PERFORMED = 2
|
2017-04-03 18:20:59 +02:00
|
|
|
}
|
2016-07-05 15:19:51 +02:00
|
|
|
}
|