..
This commit is contained in:
parent
d1f080ded1
commit
69d93778a4
@ -26,6 +26,7 @@ import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@ -42,8 +43,12 @@ import android.view.KeyEvent.KEYCODE_BUTTON_Y
|
||||
import android.view.KeyEvent.KEYCODE_DPAD_DOWN
|
||||
import android.view.KeyEvent.KEYCODE_DPAD_UP
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.WindowInsets
|
||||
import android.view.WindowManager
|
||||
import android.widget.Button
|
||||
import android.widget.HorizontalScrollView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
@ -489,7 +494,7 @@ internal class LauncherActivity : CommonActivity() {
|
||||
// }
|
||||
super.onNewIntent(intent)
|
||||
}
|
||||
|
||||
var isKeyboardVisible = false
|
||||
|
||||
@SuppressLint("NewApi", "MissingPermission")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -509,6 +514,7 @@ internal class LauncherActivity : CommonActivity() {
|
||||
HeadsetActionButtonReceiver.register(this)
|
||||
|
||||
|
||||
|
||||
binding.tabs.setOnCheckedChangeListener { g, id ->
|
||||
showContents(id)
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ import bums.lunatic.launcher.R
|
||||
import bums.lunatic.launcher.common.letTrue
|
||||
import bums.lunatic.launcher.databinding.LauncherHomeBinding
|
||||
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
||||
import bums.lunatic.launcher.home.SearchBottomSheet.OnSearchListener
|
||||
import bums.lunatic.launcher.home.adapters.RssItemAdapter
|
||||
import bums.lunatic.launcher.home.adapters.SwipeToDeleteCallback
|
||||
import bums.lunatic.launcher.model.RssData
|
||||
@ -272,34 +273,47 @@ internal class RssHome : Fragment() {
|
||||
}
|
||||
}
|
||||
fun searchKeyword() {
|
||||
val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
|
||||
builder.setTitle("Keyword")
|
||||
val viewInflated: View = LayoutInflater.from(requireContext())
|
||||
.inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
|
||||
val input = viewInflated.findViewById<View>(R.id.input) as EditText
|
||||
val privateMode = viewInflated.findViewById<CheckBox>(R.id.private_mode) as CheckBox
|
||||
val addVote = viewInflated.findViewById<CheckBox>(R.id.add_vote) as CheckBox
|
||||
val addRead = viewInflated.findViewById<CheckBox>(R.id.add_read) as CheckBox
|
||||
privateMode.setOnCheckedChangeListener { v,c->
|
||||
binding.geckoWeb.privateMode = c
|
||||
}
|
||||
privateMode.visibility = View.GONE
|
||||
binding.geckoWeb.privateMode = true
|
||||
builder.setView(viewInflated)
|
||||
builder.setPositiveButton(
|
||||
android.R.string.ok,
|
||||
DialogInterface.OnClickListener { dialog, which ->
|
||||
dialog.dismiss()
|
||||
var command = input.editableText?.toString()
|
||||
if (command?.length ?: 0 > 0) {
|
||||
queryInfos(keywords = command!!.split(" ")!!, addVote.isChecked, addRead.isChecked)
|
||||
}
|
||||
})
|
||||
builder.setNegativeButton(
|
||||
android.R.string.cancel,
|
||||
DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
|
||||
// val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
|
||||
// builder.setTitle("Keyword")
|
||||
// val viewInflated: View = LayoutInflater.from(requireContext())
|
||||
// .inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
|
||||
// val input = viewInflated.findViewById<View>(R.id.input) as EditText
|
||||
// val privateMode = viewInflated.findViewById<CheckBox>(R.id.private_mode) as CheckBox
|
||||
// val addVote = viewInflated.findViewById<CheckBox>(R.id.add_vote) as CheckBox
|
||||
// val addRead = viewInflated.findViewById<CheckBox>(R.id.add_read) as CheckBox
|
||||
// privateMode.setOnCheckedChangeListener { v,c->
|
||||
// binding.geckoWeb.privateMode = c
|
||||
// }
|
||||
// privateMode.visibility = View.GONE
|
||||
// binding.geckoWeb.privateMode = true
|
||||
// builder.setView(viewInflated)
|
||||
// builder.setPositiveButton(
|
||||
// android.R.string.ok,
|
||||
// DialogInterface.OnClickListener { dialog, which ->
|
||||
// dialog.dismiss()
|
||||
// var command = input.editableText?.toString()
|
||||
// if (command?.length ?: 0 > 0) {
|
||||
// queryInfos(keywords = command!!.split(" ")!!, addVote.isChecked, addRead.isChecked)
|
||||
// }
|
||||
// })
|
||||
// builder.setNegativeButton(
|
||||
// android.R.string.cancel,
|
||||
// DialogInterface.OnClickListener { dialog, which -> dialog.cancel() })
|
||||
//
|
||||
// builder.show()
|
||||
|
||||
builder.show()
|
||||
val bottomSheet = SearchBottomSheet()
|
||||
bottomSheet.listener = object : OnSearchListener{
|
||||
override fun onSearch(
|
||||
keyword: String,
|
||||
category: List<String>,
|
||||
addReaded: Boolean,
|
||||
addVoted: Boolean
|
||||
) {
|
||||
queryInfos(keywords = keyword.split(" "), category , addReaded, addVoted)
|
||||
}
|
||||
}
|
||||
bottomSheet.show(childFragmentManager, "SearchBottomSheet")
|
||||
}
|
||||
|
||||
|
||||
@ -730,6 +744,7 @@ internal class RssHome : Fragment() {
|
||||
|
||||
fun queryInfos(
|
||||
keywords: List<String>,
|
||||
category: List<String>,
|
||||
includeVote : Boolean = false,
|
||||
includeRead : Boolean = false
|
||||
) {
|
||||
@ -737,6 +752,9 @@ internal class RssHome : Fragment() {
|
||||
var rQ = getRealm().query<RssData>().sort("read", Sort.ASCENDING)
|
||||
if (!includeRead) { rQ = rQ.query("read == $0", 0)}
|
||||
if (!includeVote) { rQ = rQ.query("vote != $0", true)}
|
||||
keywords.forEach {
|
||||
rQ = rQ.query("category != $0", it)
|
||||
}
|
||||
// 사용 예시
|
||||
val (queryStr, queryArgs) = buildMultiFieldOrQuery(
|
||||
listOf("title", "description"),
|
||||
|
||||
@ -0,0 +1,143 @@
|
||||
package bums.lunatic.launcher.home
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Button
|
||||
import android.widget.CheckBox
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RadioGroup
|
||||
import android.widget.Toast
|
||||
import bums.lunatic.launcher.R
|
||||
import bums.lunatic.launcher.model.RssDataType
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
|
||||
class SearchBottomSheet : BottomSheetDialogFragment() {
|
||||
|
||||
private var selectedCategory = HashSet<String>()
|
||||
private val debounceHandler = Handler(Looper.getMainLooper())
|
||||
private var searchRunnable: Runnable? = null
|
||||
private val debounceDelay = 300L // 0.3초 지연
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.bottom_sheet_search, container, false)
|
||||
}
|
||||
|
||||
interface OnSearchListener {
|
||||
fun onSearch(keyword: String, category: List<String>, addReaded : Boolean, addVoted: Boolean)
|
||||
}
|
||||
|
||||
var listener: OnSearchListener? = null
|
||||
private val categoryStates = mutableMapOf<String, Boolean>()
|
||||
|
||||
lateinit var addVote : CheckBox
|
||||
lateinit var addRead : CheckBox
|
||||
lateinit var inputKeyword : EditText
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
inputKeyword = view.findViewById<EditText>(R.id.inputKeyword)
|
||||
val categoryContainer = view.findViewById<LinearLayout>(R.id.categoryContainer)
|
||||
addVote = view.findViewById<CheckBox>(R.id.add_vote) as CheckBox
|
||||
addRead = view.findViewById<CheckBox>(R.id.add_read) as CheckBox
|
||||
addRead.setOnCheckedChangeListener {v,b->triggerSearchWithDebounce(inputKeyword.text.toString())}
|
||||
addRead.setOnCheckedChangeListener {v,b->triggerSearchWithDebounce(inputKeyword.text.toString())}
|
||||
// 카테고리 목록
|
||||
val categories = RssDataType.getAll()
|
||||
categories.forEach { categoryStates[it.name] = true }
|
||||
// 버튼 동적 생성
|
||||
categoryContainer.removeAllViews()
|
||||
for (category in categories) {
|
||||
val btn = Button(requireContext()).apply {
|
||||
text = category.name
|
||||
isAllCaps = false
|
||||
setBackgroundResource(android.R.drawable.btn_default)
|
||||
|
||||
// 초기 색상(활성 상태 색 표시)
|
||||
updateButtonStyle(this, true)
|
||||
|
||||
setOnClickListener {
|
||||
// 상태 반전
|
||||
val current = categoryStates[category.name] ?: true
|
||||
categoryStates[category.name] = !current
|
||||
|
||||
// 스타일 업데이트
|
||||
updateButtonStyle(this, !current)
|
||||
triggerSearchWithDebounce(inputKeyword.text.toString())
|
||||
}
|
||||
}
|
||||
categoryContainer.addView(btn)
|
||||
}
|
||||
|
||||
|
||||
|
||||
inputKeyword.requestFocus()
|
||||
// 키보드 강제 오픈
|
||||
inputKeyword.postDelayed( {
|
||||
val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.showSoftInput(inputKeyword, InputMethodManager.SHOW_IMPLICIT)
|
||||
},150L)
|
||||
|
||||
// EditText 입력 실시간 감지 + debounce
|
||||
inputKeyword.addTextChangedListener(object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
triggerSearchWithDebounce(s.toString())
|
||||
}
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
||||
})
|
||||
// 키보드 "검색" 액션 처리
|
||||
inputKeyword.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
val keyword = inputKeyword.text.toString()
|
||||
if (keyword.isNotEmpty()) {
|
||||
triggerSearchWithDebounce(keyword)
|
||||
dismiss() // 필요 시 닫기
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateButtonStyle(button: Button, isActive: Boolean) {
|
||||
if (isActive) {
|
||||
button.setBackgroundColor(Color.parseColor("#FF9800")) // 활성화 색상
|
||||
button.setTextColor(Color.WHITE)
|
||||
} else {
|
||||
button.setBackgroundColor(Color.LTGRAY) // 비활성화 색상
|
||||
button.setTextColor(Color.DKGRAY)
|
||||
}
|
||||
}
|
||||
|
||||
private fun triggerSearchWithDebounce(keyword: String) {
|
||||
searchRunnable?.let { debounceHandler.removeCallbacks(it) }
|
||||
searchRunnable = Runnable {
|
||||
val disabledCategories = categoryStates.filter { it.value == false }.keys.toList()
|
||||
listener?.onSearch(keyword, disabledCategories.toList(), addRead.isChecked,addVote.isChecked)
|
||||
}
|
||||
debounceHandler.postDelayed(searchRunnable!!, debounceDelay)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
// 전체 창 높이를 키보드에 맞게 조정
|
||||
dialog?.window?.setSoftInputMode(
|
||||
WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE or
|
||||
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -56,7 +56,7 @@ enum class RssDataType {
|
||||
companion object {
|
||||
fun getExcAdt() = arrayListOf(NEWSFEED, REDDIT, DOTAX, FMKORAE, DCINSIDE, RULIWEB, CLIEN, THEQOO, ARCA).map { it.name }
|
||||
fun getAdts() = arrayListOf( REDDIT_NSFW).map { it.name }
|
||||
//, MOST,GURU
|
||||
fun getAll() = arrayListOf(TORRENT, YOUTUBE, NEWSFEED, REDDIT, DOTAX, FMKORAE, DCINSIDE, RULIWEB, CLIEN, THEQOO, ARCA,PRIVATE,REDDIT_NSFW)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
59
app/src/main/res/layout/bottom_sheet_search.xml
Normal file
59
app/src/main/res/layout/bottom_sheet_search.xml
Normal file
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- 검색어 입력 -->
|
||||
<EditText
|
||||
android:id="@+id/inputKeyword"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="검색어 입력"
|
||||
android:imeOptions="actionSearch"
|
||||
android:inputType="text"
|
||||
android:singleLine="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<CheckBox
|
||||
android:layout_weight="1"
|
||||
android:padding="0dp"
|
||||
android:text="add Vote"
|
||||
android:textColor="@color/black"
|
||||
android:id="@+id/add_vote"
|
||||
android:checked="false"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
<CheckBox
|
||||
android:layout_weight="1"
|
||||
android:padding="0dp"
|
||||
android:text="Add Read"
|
||||
android:textColor="@color/black"
|
||||
android:id="@+id/add_read"
|
||||
android:checked="false"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 카테고리 툴바 -->
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/accessoryToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="#F0F0F0"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/categoryContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical" />
|
||||
|
||||
</HorizontalScrollView>
|
||||
</LinearLayout>
|
||||
@ -79,4 +79,7 @@
|
||||
android:layout_height="match_parent"/>
|
||||
</RadioGroup>
|
||||
</HorizontalScrollView>
|
||||
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@ -59,4 +59,26 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<HorizontalScrollView
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:id="@+id/accessoryToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:visibility="gone"
|
||||
android:background="#F0F0F0"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/categoryContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"/>
|
||||
|
||||
</HorizontalScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Loading…
x
Reference in New Issue
Block a user