-
-
Notifications
You must be signed in to change notification settings - Fork 40
Added a feature to hide notes #947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
ee4250f
2371a25
cfc9ab8
7b4c5ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| package com.philkes.notallyx.presentation.activity.main.fragment | ||
|
|
||
| import android.os.Bundle | ||
| import android.view.View | ||
| import android.view.View.INVISIBLE | ||
| import android.view.View.VISIBLE | ||
| import androidx.lifecycle.LiveData | ||
| import com.philkes.notallyx.R | ||
| import com.philkes.notallyx.data.model.Folder | ||
| import com.philkes.notallyx.data.model.Item | ||
| import com.philkes.notallyx.utils.security.showBiometricOrPinPromptHidden | ||
|
|
||
| open class HiddenFragment : NotallyFragment() { | ||
| override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||
| super.onViewCreated(view, savedInstanceState) | ||
| model.folder.value = Folder.HIDDEN | ||
| } | ||
|
|
||
| override fun getBackground() = R.drawable.label_off | ||
|
|
||
| override fun getObservable(): LiveData<List<Item>> { | ||
| return model.hiddenNotes!! | ||
| } | ||
|
|
||
| override fun onStart() { | ||
| super.onStart() | ||
| hide() | ||
| showBiometricOrPinPromptHidden(this, R.string.hidden_lock_title, onSuccess = { show() }) {} | ||
| } | ||
|
Comment on lines
+25
to
+29
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle failed or cancelled auth before leaving the view blank. Line 27 hides the root, but the failure lambda is a no-op. Any cancel/error path leaves this fragment on an empty screen, and the launcher-null path in 🤖 Prompt for AI Agents |
||
|
|
||
| protected fun show() { | ||
| binding!!.root.visibility = VISIBLE | ||
| } | ||
|
|
||
| protected fun hide() { | ||
| binding!!.root.visibility = INVISIBLE | ||
|
Comment on lines
+31
to
+36
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid
Suggested fix protected fun show() {
- binding!!.root.visibility = VISIBLE
+ binding?.root?.visibility = VISIBLE
}
protected fun hide() {
- binding!!.root.visibility = INVISIBLE
+ binding?.root?.visibility = INVISIBLE
}🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,7 @@ class SearchFragment : NotallyFragment() { | |
| Folder.NOTES -> R.id.Notes | ||
| Folder.DELETED -> R.id.Deleted | ||
| Folder.ARCHIVED -> R.id.Archived | ||
| Folder.HIDDEN -> R.id.Hidden | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify the Hidden chip is missing from fragment_notes.xml
rg -n "android:id.*Hidden" app/src/main/res/layout/Repository: Crustack/NotallyX Length of output: 262 🏁 Script executed: # Find SearchFragment.kt and check lines around 35
fd -e "SearchFragment.kt" app/src/main/java/ --exec cat -n {} \; | head -70Repository: Crustack/NotallyX Length of output: 438 🏁 Script executed: # Find and inspect fragment_notes.xml
fd -e "fragment_notes.xml" app/src/main/res/layout/ --exec cat -n {} \;Repository: Crustack/NotallyX Length of output: 462 🏁 Script executed: # Check if there's any definition of Hidden chip or Folder enum
rg -n "Folder\.HIDDEN|@\+id/Hidden" app/src/main/java/ --type ktRepository: Crustack/NotallyX Length of output: 87 🏁 Script executed: # Find SearchFragment.kt with correct fd syntax
fd . app/src/main/java -name "SearchFragment.kt" | head -1 | xargs -I {} cat -n {}Repository: Crustack/NotallyX Length of output: 291 🏁 Script executed: # Find fragment_notes.xml with correct fd syntax
fd . app/src/main/res/layout -name "fragment_notes.xml" | head -1 | xargs -I {} cat -n {}Repository: Crustack/NotallyX Length of output: 291 🏁 Script executed: # Check for Folder.HIDDEN and Hidden chip references
rg -n "Folder\.HIDDEN|@\+id/Hidden" app/src/main/java/Repository: Crustack/NotallyX Length of output: 1911 🏁 Script executed: # Find and read fragment_notes.xml - fix fd syntax
fd SearchFragment.kt app/src/main/java/ --exec head -50 {} \;Repository: Crustack/NotallyX Length of output: 2119 🏁 Script executed: # Find fragment_notes.xml with correct syntax
find app/src/main/res/layout -name "fragment_notes.xml" -exec cat -n {} \;Repository: Crustack/NotallyX Length of output: 6797 🏁 Script executed: # Also check for any chip definitions with Hidden in their id
rg -n "android:id.*Hidden|<com.google.android.material.chip.Chip" app/src/main/res/layout/Repository: Crustack/NotallyX Length of output: 1983 Missing "Hidden" chip in layout causes broken folder selection. The code references This causes:
Add a Hidden chip to the ChipGroup in Proposed fix for fragment_notes.xml<com.google.android.material.chip.Chip
android:id="@+id/Hidden"
style="@style/FilterChip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hidden" />Add this chip to the 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| binding?.ChipGroup?.apply { | ||
|
|
@@ -40,6 +41,7 @@ class SearchFragment : NotallyFragment() { | |
| R.id.Notes -> model.folder.value = Folder.NOTES | ||
| R.id.Deleted -> model.folder.value = Folder.DELETED | ||
| R.id.Archived -> model.folder.value = Folder.ARCHIVED | ||
| R.id.Hidden -> model.folder.value = Folder.HIDDEN | ||
| } | ||
| } | ||
| check(checked) | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,6 +12,7 @@ import androidx.core.content.ContextCompat | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.fragment.app.Fragment | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import androidx.fragment.app.FragmentActivity | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.philkes.notallyx.R | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.philkes.notallyx.utils.canAuthenticateWithBiometrics | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.crypto.Cipher | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun Activity.showBiometricOrPinPrompt( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -56,6 +57,86 @@ fun Fragment.showBiometricOrPinPrompt( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun showBiometricOrPinPromptHidden( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fragment: Fragment, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| titleResId: Int, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSuccess: () -> Unit, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onFailure: (errorCode: Int?) -> Unit, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| when { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiometricManager.BIOMETRIC_SUCCESS != | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiometricManager.from(fragment.requireContext()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .canAuthenticate( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiometricManager.Authenticators.DEVICE_CREDENTIAL or | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiometricManager.Authenticators.BIOMETRIC_STRONG | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSuccess.invoke() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val promptInfo = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiometricPrompt.PromptInfo.Builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .apply { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setTitle(fragment.getString(titleResId)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setAllowedAuthenticators( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiometricManager.Authenticators.BIOMETRIC_STRONG or | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiometricManager.Authenticators.DEVICE_CREDENTIAL | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setNegativeButtonText(fragment.getString(R.string.cancel)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setAllowedAuthenticators( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiometricManager.Authenticators.BIOMETRIC_STRONG | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val authCallback = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| object : BiometricPrompt.AuthenticationCallback() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| override fun onAuthenticationSucceeded( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result: BiometricPrompt.AuthenticationResult | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super.onAuthenticationSucceeded(result) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSuccess.invoke() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| override fun onAuthenticationFailed() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super.onAuthenticationFailed() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onFailure.invoke(null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| super.onAuthenticationError(errorCode, errString) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onFailure.invoke(errorCode) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val prompt = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BiometricPrompt( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fragment, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ContextCompat.getMainExecutor(fragment.requireContext()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| authCallback, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prompt.authenticate(promptInfo) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fragment.requireContext().canAuthenticateWithBiometrics() != | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| android.hardware.biometrics.BiometricManager.BIOMETRIC_SUCCESS | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSuccess.invoke() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // API 21-22: No biometric support, fallback to PIN/Password | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| promptPinAuthentication(fragment.requireContext(), null, titleResId, onFailure) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSuccess.invoke() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+125
to
+137
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Crash on API 21-22 and security bypass. Two severe issues in this fallback branch:
Proposed fixFor API 21-22, use else -> {
- if (
- fragment.requireContext().canAuthenticateWithBiometrics() !=
- android.hardware.biometrics.BiometricManager.BIOMETRIC_SUCCESS
- ) {
+ val keyguardManager = ContextCompat.getSystemService(
+ fragment.requireContext(),
+ KeyguardManager::class.java
+ )
+ if (keyguardManager?.isKeyguardSecure != true) {
+ // Device has no lock screen - allow access
onSuccess.invoke()
return
}
- // API 21-22: No biometric support, fallback to PIN/Password
- promptPinAuthentication(fragment.requireContext(), null, titleResId, onFailure)
- onSuccess.invoke()
+ // Device is secured but we can't properly handle PIN auth without a launcher
+ // Either require an ActivityResultLauncher parameter, or deny access
+ onFailure.invoke(null)
}Alternatively, add an 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private fun showBiometricOrPinPrompt( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isForDecrypt: Boolean, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context: FragmentActivity, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -127,7 +208,7 @@ private fun showBiometricOrPinPrompt( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private fun promptPinAuthentication( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context: Context, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| activityResultLauncher: ActivityResultLauncher<Intent>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| activityResultLauncher: ActivityResultLauncher<Intent>?, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| titleResId: Int, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onFailure: (errorCode: Int?) -> Unit, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -141,7 +222,7 @@ private fun promptPinAuthentication( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (intent != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| activityResultLauncher.launch(intent) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| activityResultLauncher?.launch(intent) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onFailure.invoke(null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -157,7 +238,7 @@ private fun promptPinAuthentication( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (intent != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| activityResultLauncher.launch(intent) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| activityResultLauncher?.launch(intent) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onFailure.invoke(null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="24dp" | ||
| android:height="24dp" | ||
| android:viewportWidth="960" | ||
| android:viewportHeight="960" | ||
| android:tint="?attr/colorControlNormal"> | ||
|
|
||
| <path | ||
| android:fillColor="@android:color/white" | ||
| android:pathData="M160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L400,160L480,240L800,240Q833,240 856.5,263.5Q880,287 880,320L880,562Q862,548 842,539Q822,530 800,520L800,320L447,320L367,240L160,240L160,720L280,720Q280,738 280,760Q280,782 280,800L160,800Z"/> | ||
|
|
||
| <path | ||
| android:strokeColor="@android:color/white" | ||
| android:strokeWidth="40" | ||
| android:strokeLineCap="round" | ||
| android:pathData="M480,720 Q640,860 800,720 M530,800 L505,850 M640,820 L640,880 M750,800 L775,850"/> | ||
| </vector> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="24dp" | ||
| android:height="24dp" | ||
| android:viewportWidth="960" | ||
| android:viewportHeight="960" | ||
| android:tint="?attr/colorControlNormal"> | ||
| <path | ||
| android:fillColor="@android:color/white" | ||
| android:pathData="M160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L400,160L480,240L800,240Q833,240 856.5,263.5Q880,287 880,320L880,562Q862,548 842,539Q822,530 800,520L800,320Q800,320 800,320Q800,320 800,320L447,320L367,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720L280,720Q280,738 280,760Q280,782 280,800L160,800ZM640,920Q549,920 472,872Q395,824 360,740Q395,656 472,608Q549,560 640,560Q731,560 808,608Q885,656 920,740Q885,824 808,872Q731,920 640,920ZM747.5,814Q798,788 830,740Q798,692 747.5,666Q697,640 640,640Q583,640 532.5,666Q482,692 450,740Q482,788 532.5,814Q583,840 640,840Q697,840 747.5,814ZM597.5,782.5Q580,765 580,740Q580,715 597.5,697.5Q615,680 640,680Q665,680 682.5,697.5Q700,715 700,740Q700,765 682.5,782.5Q665,800 640,800Q615,800 597.5,782.5ZM160,720L160,720Q160,720 160,720Q160,720 160,720L160,240Q160,240 160,240Q160,240 160,240L160,240L160,320L160,320Q160,320 160,320Q160,320 160,320L160,517Q160,499 160,489.5Q160,480 160,480Q160,480 160,544Q160,608 160,720Z"/> | ||
| </vector> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't force-unwrap
hiddenNoteshere.This override is reached from the
super.onViewCreated()call on Line 15, butBaseNoteModel.hiddenNotesis still initialized later inapp/src/main/java/com/philkes/notallyx/presentation/viewmodel/BaseNoteModel.kt:196-200. A cold open of Hidden can therefore crash onmodel.hiddenNotes!!.🤖 Prompt for AI Agents