..
This commit is contained in:
parent
d1f080ded1
commit
69d93778a4
@ -26,6 +26,7 @@ import android.content.Intent
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.graphics.Rect
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
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_DOWN
|
||||||
import android.view.KeyEvent.KEYCODE_DPAD_UP
|
import android.view.KeyEvent.KEYCODE_DPAD_UP
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
|
import android.view.View
|
||||||
import android.view.WindowInsets
|
import android.view.WindowInsets
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.HorizontalScrollView
|
||||||
|
import android.widget.LinearLayout
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
@ -489,7 +494,7 @@ internal class LauncherActivity : CommonActivity() {
|
|||||||
// }
|
// }
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
}
|
}
|
||||||
|
var isKeyboardVisible = false
|
||||||
|
|
||||||
@SuppressLint("NewApi", "MissingPermission")
|
@SuppressLint("NewApi", "MissingPermission")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -509,6 +514,7 @@ internal class LauncherActivity : CommonActivity() {
|
|||||||
HeadsetActionButtonReceiver.register(this)
|
HeadsetActionButtonReceiver.register(this)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
binding.tabs.setOnCheckedChangeListener { g, id ->
|
binding.tabs.setOnCheckedChangeListener { g, id ->
|
||||||
showContents(id)
|
showContents(id)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,6 +49,7 @@ import bums.lunatic.launcher.R
|
|||||||
import bums.lunatic.launcher.common.letTrue
|
import bums.lunatic.launcher.common.letTrue
|
||||||
import bums.lunatic.launcher.databinding.LauncherHomeBinding
|
import bums.lunatic.launcher.databinding.LauncherHomeBinding
|
||||||
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
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.RssItemAdapter
|
||||||
import bums.lunatic.launcher.home.adapters.SwipeToDeleteCallback
|
import bums.lunatic.launcher.home.adapters.SwipeToDeleteCallback
|
||||||
import bums.lunatic.launcher.model.RssData
|
import bums.lunatic.launcher.model.RssData
|
||||||
@ -272,34 +273,47 @@ internal class RssHome : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun searchKeyword() {
|
fun searchKeyword() {
|
||||||
val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
|
// val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
|
||||||
builder.setTitle("Keyword")
|
// builder.setTitle("Keyword")
|
||||||
val viewInflated: View = LayoutInflater.from(requireContext())
|
// val viewInflated: View = LayoutInflater.from(requireContext())
|
||||||
.inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
|
// .inflate(R.layout.text_inpu_password, binding.root as ViewGroup?, false)
|
||||||
val input = viewInflated.findViewById<View>(R.id.input) as EditText
|
// val input = viewInflated.findViewById<View>(R.id.input) as EditText
|
||||||
val privateMode = viewInflated.findViewById<CheckBox>(R.id.private_mode) as CheckBox
|
// val privateMode = viewInflated.findViewById<CheckBox>(R.id.private_mode) as CheckBox
|
||||||
val addVote = viewInflated.findViewById<CheckBox>(R.id.add_vote) as CheckBox
|
// val addVote = viewInflated.findViewById<CheckBox>(R.id.add_vote) as CheckBox
|
||||||
val addRead = viewInflated.findViewById<CheckBox>(R.id.add_read) as CheckBox
|
// val addRead = viewInflated.findViewById<CheckBox>(R.id.add_read) as CheckBox
|
||||||
privateMode.setOnCheckedChangeListener { v,c->
|
// privateMode.setOnCheckedChangeListener { v,c->
|
||||||
binding.geckoWeb.privateMode = c
|
// binding.geckoWeb.privateMode = c
|
||||||
}
|
// }
|
||||||
privateMode.visibility = View.GONE
|
// privateMode.visibility = View.GONE
|
||||||
binding.geckoWeb.privateMode = true
|
// binding.geckoWeb.privateMode = true
|
||||||
builder.setView(viewInflated)
|
// builder.setView(viewInflated)
|
||||||
builder.setPositiveButton(
|
// builder.setPositiveButton(
|
||||||
android.R.string.ok,
|
// android.R.string.ok,
|
||||||
DialogInterface.OnClickListener { dialog, which ->
|
// DialogInterface.OnClickListener { dialog, which ->
|
||||||
dialog.dismiss()
|
// dialog.dismiss()
|
||||||
var command = input.editableText?.toString()
|
// var command = input.editableText?.toString()
|
||||||
if (command?.length ?: 0 > 0) {
|
// if (command?.length ?: 0 > 0) {
|
||||||
queryInfos(keywords = command!!.split(" ")!!, addVote.isChecked, addRead.isChecked)
|
// queryInfos(keywords = command!!.split(" ")!!, addVote.isChecked, addRead.isChecked)
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
builder.setNegativeButton(
|
// builder.setNegativeButton(
|
||||||
android.R.string.cancel,
|
// android.R.string.cancel,
|
||||||
DialogInterface.OnClickListener { dialog, which -> dialog.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(
|
fun queryInfos(
|
||||||
keywords: List<String>,
|
keywords: List<String>,
|
||||||
|
category: List<String>,
|
||||||
includeVote : Boolean = false,
|
includeVote : Boolean = false,
|
||||||
includeRead : Boolean = false
|
includeRead : Boolean = false
|
||||||
) {
|
) {
|
||||||
@ -737,6 +752,9 @@ internal class RssHome : Fragment() {
|
|||||||
var rQ = getRealm().query<RssData>().sort("read", Sort.ASCENDING)
|
var rQ = getRealm().query<RssData>().sort("read", Sort.ASCENDING)
|
||||||
if (!includeRead) { rQ = rQ.query("read == $0", 0)}
|
if (!includeRead) { rQ = rQ.query("read == $0", 0)}
|
||||||
if (!includeVote) { rQ = rQ.query("vote != $0", true)}
|
if (!includeVote) { rQ = rQ.query("vote != $0", true)}
|
||||||
|
keywords.forEach {
|
||||||
|
rQ = rQ.query("category != $0", it)
|
||||||
|
}
|
||||||
// 사용 예시
|
// 사용 예시
|
||||||
val (queryStr, queryArgs) = buildMultiFieldOrQuery(
|
val (queryStr, queryArgs) = buildMultiFieldOrQuery(
|
||||||
listOf("title", "description"),
|
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 {
|
companion object {
|
||||||
fun getExcAdt() = arrayListOf(NEWSFEED, REDDIT, DOTAX, FMKORAE, DCINSIDE, RULIWEB, CLIEN, THEQOO, ARCA).map { it.name }
|
fun getExcAdt() = arrayListOf(NEWSFEED, REDDIT, DOTAX, FMKORAE, DCINSIDE, RULIWEB, CLIEN, THEQOO, ARCA).map { it.name }
|
||||||
fun getAdts() = arrayListOf( REDDIT_NSFW).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"/>
|
android:layout_height="match_parent"/>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@ -59,4 +59,26 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</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>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
Loading…
x
Reference in New Issue
Block a user