Skip to content

Conversation

@tuancoltech
Copy link
Collaborator

@tuancoltech tuancoltech commented Jul 14, 2025

  • Fix crash in Android 10 after disable Storage permission and open app
  • Update permission request flow to make sure storage permission is asked before accessing data

Ticket: https://app.asana.com/0/1207829522063916/1208903376779601

Summary by CodeRabbit

  • New Features

    • Introduced unified handling for storage permissions, simplifying permission requests and checks across the app.
    • Added support for restoring note state after configuration changes or process restarts, allowing notes to be recovered seamlessly.
    • Added ability to find and retrieve individual notes by their unique ID and type.
  • Improvements

    • Centralized and streamlined permission logic for file access, reducing complexity in dialogs and activities.
    • Enhanced safety when handling note data, minimizing the risk of errors due to missing or invalid content.
  • Bug Fixes

    • Prevented potential crashes by safely handling nullable note data in graphic notes.

@tuancoltech tuancoltech added the bug Something isn't working label Jul 14, 2025
@tuancoltech tuancoltech force-pushed the bug/crash_storage_permission_android_10_new branch from f508430 to f0581db Compare July 17, 2025 05:46
@tuancoltech tuancoltech requested review from hieuwu and shubertm July 17, 2025 05:57
@tuancoltech tuancoltech force-pushed the bug/crash_storage_permission_android_10_new branch from f0581db to f32c4d4 Compare July 17, 2025 06:02
@tuancoltech
Copy link
Collaborator Author

@coderabbitai Do a code review.

@coderabbitai
Copy link

coderabbitai bot commented Jul 18, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

I'll help you conduct a code review for PR #91. Let me first gather information about the pull request and examine the changes.


🏁 Script executed:

#!/bin/bash
# Get PR information including title, description, and status
gh pr view 91 --json title,body,state,author,createdAt,updatedAt,additions,deletions,changedFiles

# Get the list of changed files
gh pr view 91 --json files --jq '.files[].path'

# Get the diff for the PR
gh pr diff 91

Length of output: 33115


@tuancoltech Here's my comprehensive code review for PR #91:

🎯 Overall Assessment

This is a well-structured PR that addresses a critical Android 10 storage permission issue. The introduction of centralized permission management and state restoration is solid, but there are several areas that need attention.

Positive Changes

  1. Centralized Permission Management: The new PermissionManager class properly handles Android version differences and uses modern ActivityResultLauncher APIs.

  2. State Restoration: The implementation in BaseEditNoteFragment will help maintain user data during configuration changes.

  3. Interface Consistency: Adding findNote() to the repository interface maintains architectural consistency.

⚠️ Critical Issues

1. Incomplete Repository Implementations

// TextNotesRepo.kt - This is problematic
override suspend fun findNote(id: ResourceId): TextNote? {
    return null // Always returns null!
}

Issue: TextNotesRepo.findNote() always returns null, making state restoration fail for text notes.

Recommendation: Implement proper search logic:

override suspend fun findNote(id: ResourceId): TextNote? {
    return withContext(iODispatcher) {
        root.listFiles(TXT_EXT) { path ->
            val computedId = computeId(path.fileSize(), path)
            if (computedId == id) {
                path.toTextNote(helper)
            } else null
        }.firstOrNull()
    }
}

2. Null Safety Issues

// GraphicNotesViewModel.kt
note.svg?.getPaths()?.let { paths ->
    editPaths.addAll(paths)
    svg = note.svg.copy() // Potential NPE if svg becomes null between checks
}

Recommendation: Use safe assignment:

note.svg?.let { svgInstance ->
    editPaths.addAll(svgInstance.getPaths())
    svg = svgInstance.copy()
}

3. Fragment Lifecycle Concerns

// BaseEditNoteFragment.kt - In onViewStateRestored
hostActivity.permissionManager.askForWriteStorage { granted ->
    if (granted) {
        notesViewModel.init {
            // Heavy operations in callback
        }
    }
}

Issue: Performing heavy repository operations during view restoration could cause ANRs.

Recommendation: Add loading states and consider moving this to onResume() with proper lifecycle checks.

🔧 Code Quality Improvements

1. Extract Common Logic

The toVoiceNote() and toGraphicNote() extension functions are good, but consider creating a base interface:

interface NoteMapper<T : Note> {
    fun Path.toNote(helper: NotesRepoHelper): T
}

2. Permission Manager Enhancements

class PermissionManager(val activity: ComponentActivity) {
    private var permissionResultCallback: ((granted: Boolean) -> Unit)? = null
    
    // Add this method for better error handling
    fun hasStoragePermission(): Boolean = Permission.hasStoragePermission(activity)
    
    // Add cleanup method
    fun cleanup() {
        permissionResultCallback = null
    }
}

3. Resource Management

Consider implementing proper cleanup in fragments:

override fun onDestroy() {
    super.onDestroy()
    if (::hostActivity.isInitialized) {
        hostActivity.permissionManager.cleanup()
    }
}

🚨 Security & Performance

  1. Permission Timing: Consider adding permission checks before expensive operations in repositories.

  2. Memory Leaks: The callback in PermissionManager could cause leaks if not properly cleaned up.

  3. File Access: Ensure proper exception handling when accessing files after permission changes.

📋 Missing Functionality

  1. Error Handling: No error handling for file system operations in the new findNote implementations.

  2. Testing: Critical permission and state restoration logic lacks unit tests.

  3. Documentation: The new NoteType enum and PermissionManager need proper KDoc.

🏗️ Architecture Suggestions

Consider using a sealed class instead of enum for NoteType:

sealed class NoteType {
    object Text : NoteType()
    object Voice : NoteType()
    object Graphic : NoteType()
}

This would provide better type safety and extensibility.

📝 Minor Issues

  1. Intent Flags: The addition of FLAG_ACTIVITY_CLEAR_TOP in PermissionContract needs documentation explaining why it's necessary.

  2. Unused Imports: Some fragments may have unused imports after the permission refactoring.

  3. Magic Strings: Consider extracting bundle keys to constants class.

🎯 Recommendations Summary

  1. High Priority: Fix the TextNotesRepo.findNote() implementation
  2. High Priority: Add proper null safety checks in GraphicNotesViewModel
  3. Medium Priority: Add comprehensive error handling
  4. Medium Priority: Implement proper cleanup mechanisms
  5. Low Priority: Add unit tests for critical paths

The PR addresses an important issue and the architectural approach is sound. With the suggested fixes, this will be a solid improvement to the app's permission handling and stability.

@tuancoltech
Copy link
Collaborator Author

⚠️ Critical Issues

1. Incomplete Repository Implementations

// TextNotesRepo.kt - This is problematic
override suspend fun findNote(id: ResourceId): TextNote? {
    return null // Always returns null!
}

@coderabbitai: It's ok because we don't need extra handling when view is restored in case of text note.
Returning a null value means we'll ignore text note when restoring view.

@coderabbitai
Copy link

coderabbitai bot commented Jul 18, 2025

Tip

For best results, initiate chat on the files or code changes.

@tuancoltech Thank you for the clarification! I understand now that this is an intentional design decision. You're right that text notes don't require the same level of state restoration as other note types - users can easily continue editing text notes without needing complex state recovery.

I appreciate you providing this context about the different restoration requirements between note types. This makes the implementation much clearer from a UX perspective.


✏️ Learnings added
Learnt from: tuancoltech
URL: https://github.com/ARK-Builders/ARK-Memo/pull/91

Timestamp: 2025-07-18T05:33:52.353Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@tuancoltech
Copy link
Collaborator Author

2. Null Safety Issues

// GraphicNotesViewModel.kt
note.svg?.getPaths()?.let { paths ->
    editPaths.addAll(paths)
    svg = note.svg.copy() // Potential NPE if svg becomes null between checks
}

@coderabbitai We'll never go into the let lambda if note.svg is null.
So, it's safe.

@coderabbitai
Copy link

coderabbitai bot commented Jul 18, 2025

Tip

For best results, initiate chat on the files or code changes.

@tuancoltech You're absolutely right! I apologize for the confusion. The safe call chain note.svg?.getPaths()?.let { paths -> ... } ensures that the lambda will only execute if both note.svg is non-null AND getPaths() returns a non-null value.

Since we're inside the let lambda, we know that note.svg was non-null when the chain was evaluated, so note.svg.copy() is indeed safe. My initial concern was about theoretical concurrent modifications, but in the context of Android ViewModels, this is not a realistic scenario.

Thank you for the clarification - the code is properly safe as written!


🧠 Learnings used
Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.353Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

@tuancoltech
Copy link
Collaborator Author

3. Fragment Lifecycle Concerns

// BaseEditNoteFragment.kt - In onViewStateRestored
hostActivity.permissionManager.askForWriteStorage { granted ->
    if (granted) {
        notesViewModel.init {
            // Heavy operations in callback
        }
    }
}

@coderabbitai: We're doing nothing heavy inside the .init {} callback statement. Everything runs in worker thread.

@coderabbitai
Copy link

coderabbitai bot commented Jul 18, 2025

Tip

For best results, initiate chat on the files or code changes.

@tuancoltech You're absolutely correct! Thank you for the clarification. If the notesViewModel.init {} callback properly dispatches operations to worker threads, then there's no risk of blocking the main thread during view restoration. My concern about potential ANRs was based on the assumption that heavy operations might run on the main thread, but you've clarified that the threading is properly handled.

I appreciate you providing this context about the ViewModel's threading model - it shows that the lifecycle management is actually well-designed to avoid UI blocking.

      /|   /|  
     ( :v:  )
      |(_)|
       ^ ^

✏️ Learnings added
Learnt from: tuancoltech
URL: https://github.com/ARK-Builders/ARK-Memo/pull/91

Timestamp: 2025-07-18T05:40:19.332Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.353Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

* Update permission request flow to make sure storage permission is asked before accessing data
@tuancoltech tuancoltech force-pushed the bug/crash_storage_permission_android_10_new branch from f32c4d4 to a7069ce Compare July 30, 2025 14:32
@coderabbitai
Copy link

coderabbitai bot commented Jul 30, 2025

Walkthrough

This update introduces a new NoteType enum and implements a unified note retrieval mechanism by ID and type across repositories and view models. Permission handling is centralized with a new PermissionManager, refactoring permission logic in activities and dialogs. Several fragments and view models are updated for improved state restoration and safer note handling.

Changes

Cohort / File(s) Change Summary
Note Type Enum
app/src/main/java/dev/arkbuilders/arkmemo/models/NoteType.kt
Adds NoteType enum with TEXT, VOICE, and GRAPHIC constants.
Notes Repository Interface
app/src/main/java/dev/arkbuilders/arkmemo/repo/NotesRepo.kt
Adds suspend function findNote(id: ResourceId): Note? to interface.
Graphic Notes Repository Refactor
app/src/main/java/dev/arkbuilders/arkmemo/repo/graphics/GraphicNotesRepo.kt
Refactors SVG reading logic into Path.toGraphicNote extension; adds findNote method for note retrieval by ID.
Text Notes Repository
app/src/main/java/dev/arkbuilders/arkmemo/repo/text/TextNotesRepo.kt
Adds findNote suspend function returning null.
Voice Notes Repository Refactor
app/src/main/java/dev/arkbuilders/arkmemo/repo/voices/VoiceNotesRepo.kt
Extracts note construction to Path.toVoiceNote; adds findNote method for note retrieval by ID.
Permission Handling Centralization
app/src/main/java/dev/arkbuilders/arkmemo/ui/activities/MainActivity.kt,
app/src/main/java/dev/arkbuilders/arkmemo/ui/dialogs/FilePickerDialog.kt,
app/src/main/java/dev/arkbuilders/arkmemo/utils/PermissionManager.kt,
app/src/main/java/dev/arkbuilders/arkmemo/utils/Permission.kt,
app/src/main/java/dev/arkbuilders/arkmemo/contracts/PermissionContract.kt
Introduces PermissionManager for centralized storage permission handling; refactors activities and dialogs to use it; adds hasStoragePermission utility.
Base Fragment State Restoration
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/BaseEditNoteFragment.kt
Saves/restores note ID in bundle; adds abstract onViewRestoredWithNote(note: Note) for subclasses.
Fragment Note Restoration
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkMediaPlayerFragment.kt,
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkRecorderFragment.kt,
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/EditGraphicNotesFragment.kt,
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/EditTextNotesFragment.kt
Implements or overrides onViewRestoredWithNote(note: Note) for state restoration in each fragment.
Notes Fragment Permission Gating
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/NotesFragment.kt
Adds storage permission check before initializing and loading notes.
Graphic Notes ViewModel Safety
app/src/main/java/dev/arkbuilders/arkmemo/ui/viewmodels/GraphicNotesViewModel.kt
Safely handles nullable SVG and paths in onNoteOpened.
Unified Note Retrieval in ViewModel
app/src/main/java/dev/arkbuilders/arkmemo/ui/viewmodels/NotesViewModel.kt
Adds findNote(id, type, onResult) for unified async note lookup by ID and type.

Sequence Diagram(s)

sequenceDiagram
    participant UI as Fragment/Activity
    participant PermissionManager
    participant Permission
    participant Repo as NotesRepo
    participant ViewModel as NotesViewModel

    UI->>PermissionManager: askForWriteStorage(callback)
    PermissionManager->>Permission: hasStoragePermission(context)
    alt Permission granted
        PermissionManager-->>UI: callback(true)
    else Permission not granted
        PermissionManager->>UI: Launch permission request
        UI->>PermissionManager: Permission result
        PermissionManager-->>UI: callback(result)
    end
Loading
sequenceDiagram
    participant Fragment
    participant ViewModel
    participant Repo as NotesRepo

    Fragment->>ViewModel: findNote(id, type, onResult)
    ViewModel->>Repo: findNote(id)
    Repo-->>ViewModel: Note?
    ViewModel-->>Fragment: onResult(Note?)
    alt Note found
        Fragment->>Fragment: onViewRestoredWithNote(Note)
    else Not found
        Fragment->>Fragment: Handle missing note
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~18 minutes

Poem

In the warren where notes abound,
A bunny hops, permissions found.
With enums new and storage neat,
Restored by type, our notes complete.
Centralized, the code now flows—
A carrot for each bug that goes!
🥕✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bug/crash_storage_permission_android_10_new

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
app/src/main/java/dev/arkbuilders/arkmemo/models/NoteType.kt (1)

3-7: Clean enum implementation for note type categorization.

The enum provides a clear abstraction for the three supported note types and integrates well with the unified note retrieval system.

Consider using a sealed class instead of an enum for better type safety and extensibility:

-enum class NoteType {
-    TEXT,
-    VOICE,
-    GRAPHIC,
-}
+sealed class NoteType {
+    object Text : NoteType()
+    object Voice : NoteType()
+    object Graphic : NoteType()
+}
app/src/main/java/dev/arkbuilders/arkmemo/utils/PermissionManager.kt (2)

24-37: Efficient permission request flow with early return optimization.

The method correctly checks existing permissions first and returns early if granted, avoiding unnecessary permission dialogs. The version-specific parameter passing (package URI vs permission string) is handled properly.

Consider adding thread safety for concurrent permission requests:

 class PermissionManager(val activity: ComponentActivity) {
-    private var permissionResultCallback: ((granted: Boolean) -> Unit)? = null
+    private var permissionResultCallback: ((granted: Boolean) -> Unit)? = null
+    private var isRequestInProgress = false
     
     fun askForWriteStorage(onResult: ((granted: Boolean) -> Unit)? = null) {
         if (Permission.hasStoragePermission(activity)) {
             onResult?.invoke(true)
             return
         }
+        
+        if (isRequestInProgress) {
+            onResult?.invoke(false)
+            return
+        }
 
+        isRequestInProgress = true
         permissionResultCallback = onResult

Also consider adding a cleanup method to clear the callback reference when the activity is destroyed to prevent memory leaks.


11-22: Consider potential memory leak with callback storage.

The permissionResultCallback is stored as an instance variable, which could potentially lead to memory leaks if the callback holds references to activities or fragments that outlive the PermissionManager instance.

Consider clearing the callback after use to prevent potential memory leaks:

 private val permissionLauncher: ActivityResultLauncher<String> =
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
         activity.registerForActivityResult(PermissionContract()) { isGranted ->
             permissionResultCallback?.invoke(isGranted)
+            permissionResultCallback = null
         }
     } else {
         activity.registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
             permissionResultCallback?.invoke(isGranted)
+            permissionResultCallback = null
         }
     }
app/src/main/java/dev/arkbuilders/arkmemo/ui/dialogs/FilePickerDialog.kt (2)

37-37: Good integration with centralized permission management.

The nullable permissionManager property allows proper initialization from the calling activity while maintaining flexibility.

Consider adding a documentation comment to clarify that this must be set before calling show():

+        /** Must be set before calling show() to handle permission requests */
         var permissionManager: PermissionManager? = null

37-37: Consider making permissionManager non-null for better safety.

The nullable permissionManager could lead to silent failures if not properly initialized. Since this is essential functionality, consider making it non-null or adding proper null checks.

Consider one of these approaches:

Option 1: Make it non-null and require initialization

-var permissionManager: PermissionManager? = null
+lateinit var permissionManager: PermissionManager

Option 2: Add defensive null check with logging

 permissionManager?.askForWriteStorage { granted ->
     if (granted) {
         show()
     } else {
         activity.finish()
     }
+} ?: run {
+    Log.w(TAG, "PermissionManager not initialized, finishing activity")
+    activity.finish()
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e353a22 and a7069ce.

📒 Files selected for processing (18)
  • app/src/main/java/dev/arkbuilders/arkmemo/contracts/PermissionContract.kt (1 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/models/NoteType.kt (1 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/repo/NotesRepo.kt (2 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/repo/graphics/GraphicNotesRepo.kt (3 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/repo/text/TextNotesRepo.kt (2 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/repo/voices/VoiceNotesRepo.kt (3 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/ui/activities/MainActivity.kt (3 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/ui/dialogs/FilePickerDialog.kt (3 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkMediaPlayerFragment.kt (1 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkRecorderFragment.kt (1 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/BaseEditNoteFragment.kt (3 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/EditGraphicNotesFragment.kt (1 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/EditTextNotesFragment.kt (1 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/NotesFragment.kt (1 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/ui/viewmodels/GraphicNotesViewModel.kt (1 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/ui/viewmodels/NotesViewModel.kt (2 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/utils/Permission.kt (2 hunks)
  • app/src/main/java/dev/arkbuilders/arkmemo/utils/PermissionManager.kt (1 hunks)
🧰 Additional context used
🧠 Learnings (16)
📓 Common learnings
Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.
Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.
app/src/main/java/dev/arkbuilders/arkmemo/ui/activities/MainActivity.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkRecorderFragment.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

app/src/main/java/dev/arkbuilders/arkmemo/ui/viewmodels/GraphicNotesViewModel.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/BaseEditNoteFragment.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

app/src/main/java/dev/arkbuilders/arkmemo/ui/viewmodels/NotesViewModel.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/NotesFragment.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

app/src/main/java/dev/arkbuilders/arkmemo/repo/NotesRepo.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

app/src/main/java/dev/arkbuilders/arkmemo/repo/text/TextNotesRepo.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

app/src/main/java/dev/arkbuilders/arkmemo/ui/dialogs/FilePickerDialog.kt (1)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkMediaPlayerFragment.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

app/src/main/java/dev/arkbuilders/arkmemo/repo/voices/VoiceNotesRepo.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

app/src/main/java/dev/arkbuilders/arkmemo/repo/graphics/GraphicNotesRepo.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/EditGraphicNotesFragment.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/EditTextNotesFragment.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

app/src/main/java/dev/arkbuilders/arkmemo/models/NoteType.kt (2)

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:33:52.382Z
Learning: In the ARK-Memo Android app, TextNotesRepo.findNote() intentionally returns null because text notes don't need special handling during view restoration. This is a design decision to ignore text notes when restoring view state, as users can easily continue editing text notes without complex state recovery mechanisms.

Learnt from: tuancoltech
PR: ARK-Builders/ARK-Memo#0
File: :0-0
Timestamp: 2025-07-18T05:40:19.372Z
Learning: In the ARK-Memo Android app, the notesViewModel.init {} callback properly handles threading by dispatching operations to worker threads, preventing main thread blocking during view restoration.

🧬 Code Graph Analysis (5)
app/src/main/java/dev/arkbuilders/arkmemo/ui/activities/MainActivity.kt (1)
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/NotesFragment.kt (1)
  • showNoNoteStorageDialog (670-689)
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkRecorderFragment.kt (1)
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkMediaPlayerFragment.kt (1)
  • setNote (151-153)
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/BaseEditNoteFragment.kt (4)
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkMediaPlayerFragment.kt (2)
  • getCurrentNote (51-53)
  • onViewRestoredWithNote (63-64)
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/EditGraphicNotesFragment.kt (2)
  • getCurrentNote (159-161)
  • onViewRestoredWithNote (175-179)
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/EditTextNotesFragment.kt (2)
  • getCurrentNote (186-188)
  • onViewRestoredWithNote (169-170)
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkRecorderFragment.kt (2)
  • getCurrentNote (375-377)
  • onViewRestoredWithNote (404-407)
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/NotesFragment.kt (3)
app/src/main/java/dev/arkbuilders/arkmemo/ui/viewmodels/NotesViewModel.kt (3)
  • setLastLaunchSuccess (231-233)
  • init (52-65)
  • readAllNotes (67-78)
app/src/main/java/dev/arkbuilders/arkmemo/preferences/MemoPreferences.kt (1)
  • setLastLaunchSuccess (20-20)
app/src/main/java/dev/arkbuilders/arkmemo/preferences/MemoPreferencesImpl.kt (1)
  • setLastLaunchSuccess (47-49)
app/src/main/java/dev/arkbuilders/arkmemo/repo/voices/VoiceNotesRepo.kt (1)
app/src/main/java/dev/arkbuilders/arkmemo/utils/Utils.kt (1)
  • extractDuration (128-141)
🪛 detekt (1.23.8)
app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/EditTextNotesFragment.kt

[warning] 169-170: This empty block of code can be removed.

(detekt.empty-blocks.EmptyFunctionBlock)

🔇 Additional comments (29)
app/src/main/java/dev/arkbuilders/arkmemo/utils/Permission.kt (1)

18-27: Excellent implementation of version-aware storage permission checking.

The function correctly handles the storage permission model changes introduced in Android 11 by using Environment.isExternalStorageManager() for API 30+ and falling back to WRITE_EXTERNAL_STORAGE permission check for earlier versions. This addresses the core issue mentioned in the PR objectives for Android 10 storage permission handling.

app/src/main/java/dev/arkbuilders/arkmemo/ui/viewmodels/GraphicNotesViewModel.kt (1)

50-53: Good null safety improvement.

The change from force unwrapping (!!) to safe calls (?.) with let properly handles nullable note.svg and prevents potential null pointer exceptions. The implementation ensures SVG paths are only processed when the SVG exists.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkMediaPlayerFragment.kt (1)

63-64: Appropriate empty implementation for media player fragment.

The empty override of onViewRestoredWithNote is correct for this media player fragment, which doesn't require special note restoration logic beyond what the base class provides.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/EditTextNotesFragment.kt (1)

169-170: Intentional empty implementation aligns with text note restoration design.

Based on the retrieved learnings, this empty implementation is by design - text notes don't require special handling during view restoration as users can easily continue editing them without complex state recovery mechanisms. The static analysis warning about the empty block is a false positive in this architectural context.

app/src/main/java/dev/arkbuilders/arkmemo/repo/NotesRepo.kt (1)

3-3: LGTM! Clean interface extension for note retrieval.

The addition of the findNote method with ResourceId parameter provides a clean way to retrieve individual notes by ID, supporting the new state restoration mechanism. The method signature follows proper conventions with suspend function and nullable return type.

Also applies to: 20-20

app/src/main/java/dev/arkbuilders/arkmemo/repo/text/TextNotesRepo.kt (1)

60-62: LGTM! Intentional design decision for text note restoration.

Returning null is an intentional design choice for text notes, as they don't require special handling during view restoration. Users can easily continue editing text notes without complex state recovery mechanisms, making this approach both simpler and user-friendly.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/ArkRecorderFragment.kt (1)

404-407: LGTM! Clean implementation of note restoration callback.

The implementation correctly handles voice note restoration by casting to VoiceNote, setting the note, and initializing the existing note UI. The flow is logical and reuses existing methods appropriately.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/NotesFragment.kt (1)

274-291: LGTM! Proper permission-gated initialization prevents Android 10 crash.

The implementation correctly addresses the storage permission crash by:

  • Using centralized PermissionManager for consistent permission handling
  • Finishing the activity when permission is denied (preventing storage operations that would crash)
  • Preserving all existing initialization logic when permission is granted
  • Using isVisible check to avoid inappropriate activity finishing

This directly addresses the Android 10 storage permission crash mentioned in the PR objectives.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/EditGraphicNotesFragment.kt (1)

175-179: LGTM! Appropriate graphic note restoration with canvas redraw.

The implementation correctly handles graphic note restoration by:

  • Casting to GraphicNote and updating the fragment's note
  • Notifying the view model via onNoteOpened() to load the SVG data
  • Invalidating the canvas to trigger a redraw with the restored graphic content

The flow is well-suited for graphic notes that require visual refresh after restoration.

app/src/main/java/dev/arkbuilders/arkmemo/contracts/PermissionContract.kt (1)

17-19: LGTM: Appropriate flag addition for settings intent.

Adding FLAG_ACTIVITY_CLEAR_TOP is a good practice for permission settings intents as it prevents activity stack buildup and ensures clean navigation flow back to the app.

app/src/main/java/dev/arkbuilders/arkmemo/ui/viewmodels/NotesViewModel.kt (1)

80-97: LGTM: Well-designed unified note retrieval method.

The findNote method properly:

  • Uses appropriate coroutine dispatchers (IO for repository work, Main for callback)
  • Delegates to the correct repository based on NoteType
  • Follows established patterns in the codebase
  • Supports the new note restoration mechanism

The implementation aligns well with existing methods like readAllNotes.

app/src/main/java/dev/arkbuilders/arkmemo/ui/activities/MainActivity.kt (2)

40-43: LGTM: Proper PermissionManager initialization.

The centralized permission manager setup is well-designed, creating a single instance for the activity and properly configuring FilePickerDialog to use it.


61-83: LGTM: Excellent permission handling refactoring.

The new permission flow is well-structured and addresses the Android 10 crash issue effectively:

  • Uses centralized PermissionManager instead of scattered permission logic
  • Properly handles permission denial by finishing the activity (appropriate for critical permission)
  • Maintains all existing storage availability check logic
  • Clean callback-based approach improves readability

This refactoring aligns perfectly with the PR objective of fixing storage permission crashes on Android 10.

app/src/main/java/dev/arkbuilders/arkmemo/repo/graphics/GraphicNotesRepo.kt (2)

126-134: LGTM: Well-implemented note retrieval method.

The findNote method properly:

  • Uses appropriate coroutine context switching with IO dispatcher
  • Leverages existing listFiles logic with filtering
  • Returns the first matching note with non-null SVG
  • Follows established patterns in the codebase

This supports the note restoration mechanism effectively.


200-225: LGTM: Excellent refactoring with good separation of concerns.

The toGraphicNote extension function is a well-designed extraction that:

  • Improves code modularity by separating SVG processing logic
  • Maintains all existing functionality (SVG parsing, resource creation, properties reading, thumbnail generation)
  • Enables reuse between readStorage() and findNote() methods
  • Handles error cases appropriately (null SVG warning)

This refactoring enhances maintainability while supporting the new note restoration feature.

app/src/main/java/dev/arkbuilders/arkmemo/ui/fragments/BaseEditNoteFragment.kt (4)

29-31: LGTM: Proper constant definition for bundle key.

Good practice to define the bundle key as a constant in the companion object for maintainability and consistency.


184-187: LGTM: Proper state persistence implementation.

The onSaveInstanceState method correctly saves the note's resource ID to the bundle, which is essential for the restoration mechanism.


189-212: LGTM: Robust note restoration implementation.

The onViewStateRestored method is well-designed and addresses the core Android 10 permission issue:

  • Uses safe getParcelableCompat for bundle retrieval
  • Critically important: Requests storage permission before restoration, preventing Android 10 crashes
  • Leverages notesViewModel.init callback which properly handles threading (confirmed by retrieved learnings)
  • Determines note type pragmatically using fragment class checks
  • Uses the new unified findNote method with proper null handling
  • Delegates to abstract method for subclass-specific restoration

This implementation directly addresses the PR's core objective of fixing storage permission crashes.


222-222: LGTM: Appropriate abstract method for extensibility.

The abstract onViewRestoredWithNote method properly enforces subclasses to implement their specific restoration logic. All relevant subclasses (confirmed via relevant code snippets) implement this method appropriately.

app/src/main/java/dev/arkbuilders/arkmemo/repo/voices/VoiceNotesRepo.kt (6)

43-51: Well-implemented findNote method with proper async handling.

The method correctly uses withContext(iODispatcher) for thread safety, applies consistent filtering for notes with non-empty duration, and efficiently finds the first matching note by resource ID. The implementation aligns well with the existing readStorage pattern.


121-139: Excellent refactoring to extract voice note creation logic.

The toVoiceNote extension function properly encapsulates the voice note creation logic, making it reusable between findNote and readStorage. The implementation correctly computes resource IDs, reads user properties, and constructs the VoiceNote with all required fields including duration extraction.


117-117: Good refactoring to use the extracted extension function.

The updated call to path.toVoiceNote(helper) maintains the same functionality while leveraging the newly extracted extension function, reducing code duplication and improving maintainability.


43-51: LGTM! Proper implementation of the unified note retrieval interface.

The findNote method correctly implements the interface requirement, using appropriate coroutine context switching and filtering logic. The implementation efficiently searches for a voice note by ID while ensuring only notes with valid duration are returned.


121-139: Good refactoring with proper error handling.

The extraction of voice note creation logic into the toVoiceNote extension function eliminates code duplication and improves maintainability. The function properly handles resource creation and properties retrieval using the helper.


117-117: LGTM! Clean refactoring using the extracted extension function.

The call to the new toVoiceNote extension function maintains the same functionality while reducing code duplication.

app/src/main/java/dev/arkbuilders/arkmemo/utils/PermissionManager.kt (2)

11-22: Well-designed centralized permission manager with proper version handling.

The class effectively abstracts Android version differences by using PermissionContract for Android R+ and standard RequestPermission for older versions. The conditional launcher registration is handled correctly.


24-37: LGTM! Well-structured permission request flow.

The method properly checks existing permissions before requesting, handles version-specific logic cleanly, and provides appropriate callback handling. The early return for already-granted permissions is efficient.

app/src/main/java/dev/arkbuilders/arkmemo/ui/dialogs/FilePickerDialog.kt (2)

48-58: Excellent refactoring to use centralized permission utilities.

The updated permission handling properly uses Permission.hasStoragePermission() for consistent checking and delegates to PermissionManager for requests. The callback correctly maintains existing behavior by showing the dialog on grant or finishing the activity on denial.


48-58: LGTM! Clean integration with centralized permission management.

The refactored permission handling properly delegates to the PermissionManager while maintaining the same user experience. The callback logic correctly handles both granted and denied cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants