This commit is contained in:
lunaticbum 2024-08-25 14:45:57 +09:00
parent 281ae10712
commit e1ec3c12d2
8 changed files with 141 additions and 163 deletions

View File

@ -364,11 +364,10 @@ internal class AppDrawer : Fragment() {
// appsAdapter?.updateGravity(settingsPrefs!!.getInt(KEY_DRAW_ALIGN, Gravity.CENTER))
// }
contactAdapter?.updateData(contactList)
openSearch()
setKeyboardPadding()
// openSearch()
// setKeyboardPadding()
contactList.sortBy { it.name }
contactAdapter?.updateData(contactList)
/* pop up the keyboard */

View File

@ -96,11 +96,10 @@ internal class AppsAdapter(
/* update app list */
fun updateData(newList: List<Packages>) {
val diffUtilResult = DiffUtil.calculateDiff(AppsDiffUtil(oldList, newList))
//
diffUtilResult.dispatchUpdatesTo(this)
oldList.clear()
oldList.addAll(newList)
diffUtilResult.dispatchUpdatesTo(this)
newList.size.let {
appsCount.text = it.toString()
appsSize = it

View File

@ -89,11 +89,9 @@ internal class ContactAdapter (
/* update app list */
fun updateData(newList: List<SimpleContact>) {
val diffUtilResult = DiffUtil.calculateDiff(ContactDiffUtil(oldList, newList))
diffUtilResult.dispatchUpdatesTo(this)
oldList.clear()
oldList.addAll(newList)
diffUtilResult.dispatchUpdatesTo(this)
newList.size.let {
appsSize = it
}

View File

@ -35,6 +35,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LiveData
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.PeriodicWorkRequestBuilder
@ -77,6 +78,11 @@ internal class LauncherHome : Fragment() {
private lateinit var settingsPrefs: SharedPreferences
private lateinit var batteryReceiver: BatteryReceiver
private var shouldResume = true
companion object {
var missedCalls = hashMapOf<String, MissedCall>()
var callList = arrayListOf<MissedCall>()
var smsList = arrayListOf<RecentSmsLog>()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
@ -84,68 +90,34 @@ internal class LauncherHome : Fragment() {
fragManager = lActivity!!.supportFragmentManager
settingsPrefs = requireContext().getSharedPreferences(PREFS_SETTINGS, 0)
batteryReceiver = BatteryReceiver(binding.batteryProgress)
mMissedCallsAdapter = MissedCallsAdapter(callList, requireContext())
mSmsLogsAdapter = SmsLogsAdapter(smsList, requireContext())
binding.favAppsGroup.visibility = View.GONE
mWorkManager = WorkManager.getInstance(lActivity!!.application);
mWorkManager = WorkManager.getInstance(requireContext())
mWorkManager?.cancelAllWork()
mWorkManager?.enqueue(PeriodicWorkRequestBuilder<RecentSmsGetter>(30, TimeUnit.MINUTES).addTag("RecentSmsGetter").build())
mWorkManager?.enqueue(PeriodicWorkRequestBuilder<MissedCallGetter>(30, TimeUnit.MINUTES).addTag("MissedCallGetter").build())
mSmsWorkInfo = mWorkManager?.getWorkInfosByTagLiveData("RecentSmsGetter");
mSavedWorkInfo = mWorkManager?.getWorkInfosByTagLiveData("MissedCallGetter");
getOutputWorkInfo().observeForever {
BLog.LOGE("getOutputWorkInfo.last() >>> ${it.size}")
BLog.LOGE("getOutputWorkInfo.last() >>> ${it.first().outputData.size()}")
BLog.LOGE("getOutputWorkInfo.last() >>> ${it.last().outputData.size()}")
it.last()?.outputData?.keyValueMap?.forEach { t, u ->
try {
if (u is String) {
Gson().fromJson(u,MissedCall::class.java)?.let {
callList.add(it)
}
}
} catch (e : Exception) {
} finally {
showTodoList()
}
}
mWorkManager?.enqueue(PeriodicWorkRequestBuilder<RecentSmsGetter>(30, TimeUnit.SECONDS).addTag("RecentSmsGetter").build())
mWorkManager?.enqueueUniquePeriodicWork("MissedCallGetter",ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,PeriodicWorkRequestBuilder<MissedCallGetter>(30, TimeUnit.SECONDS).addTag("MissedCallGetter").build())
mWorkManager?.getWorkInfosByTagLiveData("RecentSmsGetter")?.observeForever {
if (binding.recentSms.isChecked) chooseAdpater()
BLog.LOGE("smsList.size >>> ${smsList.size}")
it.clear()
}
getSmsInfos().observeForever {
BLog.LOGE("getSmsInfos.last() >>> ${it.size}")
BLog.LOGE("getSmsInfos.last() >>> ${it.first().outputData.size()}")
BLog.LOGE("getSmsInfos.last() >>> ${it.last().outputData.size()}")
it.last()?.outputData?.keyValueMap?.forEach { t, u ->
try {
if (u is String) {
BLog.LOGE("getSmsInfos() u >>> ${u}")
Gson().fromJson(u,RecentSmsLog::class.java)?.let {
smsList.add(it)
BLog.LOGE("getSmsInfos() u -> it >>> ${it}")
}
}
} catch (e : Exception) {
} finally {
showTodoList()
}
}
mWorkManager?.getWorkInfosByTagLiveData("MissedCallGetter")?.observeForever {
if (binding.missedCalls.isChecked) chooseAdpater()
it.clear()
}
BLog.LOGE("onCreateView()")
return binding.root
}
private var mSavedWorkInfo: LiveData<List<WorkInfo>>? = null
private var mSmsWorkInfo: LiveData<List<WorkInfo>>? = null
fun getOutputWorkInfo(): LiveData<List<WorkInfo>> {
return mSavedWorkInfo!!
}
lateinit var mMissedCallsAdapter : MissedCallsAdapter
lateinit var mSmsLogsAdapter : SmsLogsAdapter
fun getSmsInfos(): LiveData<List<WorkInfo>> {
return mSmsWorkInfo!!
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -155,7 +127,6 @@ internal class LauncherHome : Fragment() {
todosGestures()
BLog.LOGE("onViewCreated()")
// mWorkManager.
/* refresh the to-do list after getting back from TodoManager */
fragManager.addOnBackStackChangedListener {
@ -168,62 +139,58 @@ internal class LauncherHome : Fragment() {
false
}
}
binding.missedCalls.setOnClickListener {
binding.missedCalls.isChecked = true
BLog.LOGE("binding.missedCalls >> ${binding.missedCalls.isChecked}")
try {
BLog.LOGE("callList >>> ${callList.size}")
binding.notes.layoutManager = LinearLayoutManager(requireContext())
binding.notes.adapter = MissedCallsAdapter(callList, requireContext())
(binding.notes.adapter as? MissedCallsAdapter)?.notifyDataSetChanged()
} catch (e : Exception) {
}}
chooseAdpater()
}
binding.recentSms.setOnClickListener {
binding.recentSms.isChecked = true
BLog.LOGE("binding.recentSms >> ${binding.recentSms.isChecked}")
try {
BLog.LOGE("callList >>> ${smsList.size}")
binding.notes.layoutManager = LinearLayoutManager(requireContext())
binding.notes.adapter = SmsLogsAdapter(smsList, requireContext())
(binding.notes.adapter as? SmsLogsAdapter)?.notifyDataSetChanged()
} catch (e : Exception) {
}
chooseAdpater()
}
binding.summaryChoose.setOnCheckedChangeListener { group, checkedId ->
if (binding.missedCalls.isChecked) {
if (callList.size > 0 && isAdded && isResumed && isVisible) {
try {
BLog.LOGE("callList >>> ${callList.size}")
binding.notes.adapter = MissedCallsAdapter(callList, requireContext())
binding.notes.invalidate()
} catch (e : Exception) {
chooseAdpater()
}
}
fun chooseAdpater () {
if (binding.missedCalls.isChecked) {
if (missedCalls.size > 0 && isAdded && isResumed && isVisible) {
try {
callList.clear()
BLog.LOGE("chooseAdpater callList >>> ${callList.size}")
BLog.LOGE("chooseAdpater callList missedCalls >>> ${missedCalls.values.size}")
binding.mainList.adapter = mMissedCallsAdapter
missedCalls.forEach { t, u ->
callList.add(u)
}.apply {
mMissedCallsAdapter.updateData(callList)
}
} catch (e : Exception) {
}
} else if(binding.recentSms.isChecked){
//binding.notes.adapter = TodoAdapter(null, requireContext())
if (smsList.size > 0 && isAdded && isResumed && isVisible) {
try {
BLog.LOGE("callList >>> ${callList.size}")
binding.notes.adapter = SmsLogsAdapter(smsList, requireContext())
binding.notes.invalidate()
} catch (e : Exception) {
}
} else if(binding.recentSms.isChecked){
if (smsList.size > 0 && isAdded && isResumed && isVisible) {
try {
BLog.LOGE("chooseAdpater smsList >>> ${smsList.size}")
binding.mainList.adapter = mSmsLogsAdapter
mSmsLogsAdapter.updateData(smsList)
} catch (e : Exception) {
}
}
}
}
}
override fun onResume() {
super.onResume()
BLog.LOGE("onResume()")
if (shouldResume) {
/* register battery changes */
requireContext().registerReceiver(batteryReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
/* time and date */
binding.time.textLocale = Locale.US
binding.date.textLocale = Locale.US
@ -234,17 +201,15 @@ internal class LauncherHome : Fragment() {
binding.time.format12Hour = timeFormat
binding.date.format12Hour = dateFormat
}
/* show weather */
WeatherExecutor(settingsPrefs).generateWeatherString(binding.weather)
chooseAdpater()
}
}
private var mWorkManager: WorkManager? = null
var callList = arrayListOf<MissedCall>()
var smsList = arrayListOf<RecentSmsLog>()
@ -348,7 +313,7 @@ internal class LauncherHome : Fragment() {
override fun onLongPress(targetView: View,fingers: Int): Boolean {
if (view?.equals(binding.batteryProgress) ?: false) {
lActivity!!.startActivity(Intent(requireContext(), SettingsActivity::class.java))
} else if (view?.equals(binding.notes) ?: false) {
} else if (view?.equals(binding.mainList) ?: false) {
when (settingsPrefs.getBoolean(KEY_TODO_LOCK, false)) {
false -> launchTodoManager()
/* show authentication screen if lock is on */
@ -450,7 +415,7 @@ internal class LauncherHome : Fragment() {
/* gestures on to-do area */
@SuppressLint("ClickableViewAccessibility")
private fun todosGestures() {
binding.notes.setOnTouchListener(SimpleFingerGestures(context = requireContext(), binding.notes , mFingerGestureListener))
binding.mainList.setOnTouchListener(SimpleFingerGestures(context = requireContext(), binding.mainList , mFingerGestureListener))
// binding.notes.setOnTouchListener(object : SwipeTouchListener(requireContext()) {
// /* open TodoManager on long click */
// override fun onLongClick() {
@ -507,29 +472,7 @@ internal class LauncherHome : Fragment() {
// .addToBackStack("").commit()
}
/* to-do list */
private fun showTodoList() {
if (binding.missedCalls.isChecked) {
if (callList.size > 0 && isAdded && isResumed && isVisible) {
try {
BLog.LOGE("callList >>> ${callList.size}")
binding.notes.adapter = MissedCallsAdapter(callList, requireContext())
} catch (e : Exception) {
}
}
} else if(binding.recentSms.isChecked){
//binding.notes.adapter = TodoAdapter(null, requireContext())
if (smsList.size > 0 && isAdded && isResumed && isVisible) {
try {
BLog.LOGE("callList >>> ${callList.size}")
binding.notes.adapter = SmsLogsAdapter(smsList, requireContext())
} catch (e : Exception) {
}
}
}
}
/* get time format string */
private val timeFormat: String? get() {

View File

@ -24,6 +24,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialog
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
@ -33,6 +34,7 @@ import rasel.lunar.launcher.databinding.TodoDialogBinding
import rasel.lunar.launcher.helpers.UniUtils.Companion.copyToClipboard
import rasel.lunar.launcher.home.MissedCall
import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.RecentSmsLog
import java.util.*
import kotlin.collections.ArrayList
@ -110,4 +112,26 @@ internal class MissedCallsAdapter(
// }
}
fun updateData(newList: ArrayList<MissedCall>) {
val diffUtilResult = DiffUtil.calculateDiff(MissedCallDiffUtil(callList, newList))
diffUtilResult.dispatchUpdatesTo(this)
// callList.clear()
// callList.addAll(newList)
}
}
internal class MissedCallDiffUtil(
private val oldList: List<MissedCall>, private val newList: List<MissedCall>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].date == newList[newItemPosition].date
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition] == newList[newItemPosition]
}

View File

@ -24,10 +24,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialog
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R
import rasel.lunar.launcher.apps.AppsAdapter.Companion.appsSize
import rasel.lunar.launcher.apps.AppsDiffUtil
import rasel.lunar.launcher.apps.Packages
import rasel.lunar.launcher.databinding.ListItemBinding
import rasel.lunar.launcher.databinding.TodoDialogBinding
import rasel.lunar.launcher.helpers.UniUtils.Companion.copyToClipboard
@ -51,14 +55,14 @@ internal class SmsLogsAdapter(
}
override fun getItemCount(): Int {
BLog.LOGE("smsList.size >>> ${smsList.size}")
BLog.LOGE("SmsLogsAdapter smsList.size >>> ${smsList.size}")
return smsList.size
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: SmsLogHolder, position: Int) {
val todo = smsList[position]
BLog.LOGE("smsList >>> ${smsList[position]}")
BLog.LOGE("SmsLogsAdapter smsList >>> ${smsList[position]}")
holder.view.itemText.text = "\u25CF ${todo.person} ${todo.addr} , ${todo.body} : ${todo.pstDate} : ${todo.type}"
/* multiline texts are enabled for TodoManager */
@ -75,6 +79,15 @@ internal class SmsLogsAdapter(
inner class SmsLogHolder(var view: ListItemBinding) : RecyclerView.ViewHolder(view.root)
fun updateData(newList: List<RecentSmsLog>) {
BLog.LOGE("SmsLogsAdapter smsList newList >> ${newList.size}")
val diffUtilResult = DiffUtil.calculateDiff(SmsDiffUtil(smsList, newList))
diffUtilResult.dispatchUpdatesTo(this)
BLog.LOGE("SmsLogsAdapter smsList smsList >> ${smsList.size}")
// smsList.clear()
// smsList.addAll(newList)
}
/* update dialog */
private fun updateDialog(position: Int) {
// val bottomSheetDialog = BottomSheetDialog(lActivity!!, R.style.BottomSheetDialog)
@ -113,3 +126,17 @@ internal class SmsLogsAdapter(
}
}
internal class SmsDiffUtil(
private val oldList: List<RecentSmsLog>, private val newList: List<RecentSmsLog>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].rcvDate == newList[newItemPosition].rcvDate
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].rcvDate == newList[newItemPosition].rcvDate
}

View File

@ -7,8 +7,11 @@ import android.provider.Telephony
import androidx.work.Data
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import com.google.gson.Gson
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.home.LauncherHome.Companion.missedCalls
import rasel.lunar.launcher.home.LauncherHome.Companion.smsList
import rasel.lunar.launcher.home.MissedCall
import java.text.SimpleDateFormat
import java.util.Date
@ -16,29 +19,28 @@ import java.util.Date
class MissedCallGetter : Worker {
constructor(context: Context, workerParams: WorkerParameters) : super(context, workerParams) {
}
@SuppressLint("RestrictedApi")
override fun doWork(): Result {
var resultData = Data.Builder()
var dateParam = Date(System.currentTimeMillis() - (1000 * 60 * 60 * 24)).time.toString()
lActivity?.contentResolver?.query(
var managedCursor =lActivity?.contentResolver?.query(
CallLog.Calls.CONTENT_URI, arrayOf(
CallLog.Calls.NUMBER,
CallLog.Calls.TYPE,
CallLog.Calls.DATE,
CallLog.Calls.DURATION,
CallLog.Calls.CACHED_NAME,
), CallLog.Calls.DATE + "> ? AND " + CallLog.Calls.TYPE + " > ?", arrayOf<String>(dateParam, "2"), CallLog.Calls.DATE + " desc")?.let { managedCursor ->
), CallLog.Calls.DATE + "> ? AND " + CallLog.Calls.TYPE + " > ?", arrayOf<String>(dateParam, "2"), CallLog.Calls.DATE + " desc")
if(managedCursor != null && managedCursor.isClosed == false) {
try {
val number = managedCursor.getColumnIndex(CallLog.Calls.NUMBER)
val type = managedCursor.getColumnIndex(CallLog.Calls.TYPE)
val date = managedCursor.getColumnIndex(CallLog.Calls.DATE)
val duration = managedCursor.getColumnIndex(CallLog.Calls.DURATION)
val name = managedCursor.getColumnIndex(CallLog.Calls.CACHED_NAME)
var missedCalls = hashMapOf<String, MissedCall>()
missedCalls.clear()
while (managedCursor.moveToNext()) {
val phNumber = managedCursor.getString(number) // mobile number
val callType = managedCursor.getString(type) // call type
@ -96,9 +98,7 @@ class MissedCallGetter : Worker {
}
missedCalls.forEach { t, u ->
resultData.put(t, u.toJson())
}
} catch (e: Exception) {
@ -106,7 +106,7 @@ class MissedCallGetter : Worker {
managedCursor.close()
}
}
return Result.success(resultData.build());
return Result.success()
}
}
@ -119,12 +119,13 @@ class RecentSmsGetter : Worker {
}
@SuppressLint("RestrictedApi")
override fun doWork(): Result {
BLog.LOGE("phNumber == onStart")
var resultData = Data.Builder()
var resultData = workDataOf("" to "")
var dateParam = Date(System.currentTimeMillis() - (1000 * 60 * 60 * 24 * 3)).time.toString()
lActivity?.contentResolver?.query(
val managedCursor = lActivity?.contentResolver?.query(
Telephony.Sms.CONTENT_URI, arrayOf(
Telephony.Sms.ADDRESS,
Telephony.Sms.TYPE,
@ -132,22 +133,21 @@ class RecentSmsGetter : Worker {
Telephony.Sms.DATE_SENT,
Telephony.Sms.BODY,
Telephony.Sms.PERSON,
), Telephony.Sms.DATE + ">= ? OR " + Telephony.Sms.DATE_SENT + " >= ?", arrayOf<String>(dateParam, dateParam), Telephony.Sms.DEFAULT_SORT_ORDER)?.let { managedCursor ->
), Telephony.Sms.DATE + ">= ? OR " + Telephony.Sms.DATE_SENT + " >= ?", arrayOf<String>(dateParam, dateParam), Telephony.Sms.DEFAULT_SORT_ORDER)
if (managedCursor != null && managedCursor.isClosed == false) {
try {
BLog.LOGE("phNumber == onResult")
val address = managedCursor.getColumnIndex(Telephony.Sms.ADDRESS)
val type = managedCursor.getColumnIndex(Telephony.Sms.TYPE)
val date = managedCursor.getColumnIndex(Telephony.Sms.DATE)
val sendDate = managedCursor.getColumnIndex(Telephony.Sms.DATE_SENT)
val bodyIdx = managedCursor.getColumnIndex(Telephony.Sms.BODY)
val name = managedCursor.getColumnIndex(Telephony.Sms.PERSON)
var missedCalls = arrayListOf<RecentSmsLog>()
while (managedCursor.moveToNext()) {
val phNumber = managedCursor.getString(address) // mobile number
val callType = managedCursor.getString(type) // call type
val reciveDate = managedCursor.getString(date) // call date
val sendedDate = managedCursor.getString(sendDate) // call date
val smsBody = managedCursor.getString(bodyIdx)
val smsBody = managedCursor.getString(bodyIdx).replace("\n"," ")
val callerName = managedCursor.getString(name)
var dir: String = ""
@ -161,14 +161,6 @@ class RecentSmsGetter : Worker {
Telephony.Sms.MESSAGE_TYPE_FAILED -> {dir = "MESSAGE_TYPE_FAILED"}
Telephony.Sms.MESSAGE_TYPE_QUEUED -> {dir = "MESSAGE_TYPE_QUEUED"}
}
BLog.LOGE("phNumber == ${phNumber}\n" +
" dir == ${dir}\n" +
" reciveDate == ${reciveDate}\n" +
" sendedDate == ${sendedDate}\n" +
" smsBody == ${smsBody}\n" +
" callerName == ${callerName}\n")
var log = RecentSmsLog(
phNumber,
dir,
@ -177,22 +169,17 @@ class RecentSmsGetter : Worker {
smsBody,
callerName ?: ""
)
BLog.LOGE("resultData put ${phNumber +"_"+ reciveDate} >>> ${log.toJson()}")
resultData.put(phNumber +"_"+ reciveDate, log.toJson())
BLog.LOGE("RecentSmsGetter resultData put ${phNumber +"_"+ reciveDate} >>> ${log.toJson()}")
smsList.add(log)
}
// resultData.put()
} catch (e: Exception) {
} finally {
managedCursor.close()
}
}
return Result.success(resultData.build());
return Result.success()
}
}

View File

@ -73,7 +73,7 @@
app:layout_constraintLeft_toLeftOf="parent"
android:orientation="horizontal"
app:layout_constraintRight_toRightOf="parent"
android:layout_height="wrap_content"
android:layout_height="40dp"
app:layout_constraintTop_toBottomOf="@+id/batteryProgress"
>
<RadioButton
@ -104,8 +104,8 @@
android:layout_height="wrap_content"/>
</RadioGroup>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/notes"
android:layout_width="@dimen/zero"
android:id="@+id/mainList"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="never"
android:padding="20dp"
@ -120,6 +120,7 @@
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/favAppsGroup"
android:layout_width="@dimen/zero"
android:visibility="gone"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/twentyTwo"
android:layout_marginBottom="@dimen/twelve"
@ -127,5 +128,5 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/notes" />
app:layout_constraintTop_toBottomOf="@+id/mainList" />
</androidx.constraintlayout.widget.ConstraintLayout>