Skip to content
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

Update UI for Settings and associated views #143

Merged
merged 43 commits into from
Dec 20, 2024
Merged

Conversation

danielnordh
Copy link
Contributor

@danielnordh danielnordh commented Dec 18, 2024

Updates the Settings view and associated subviews.
Follows previous style patterns established in the onboarding PR.

image (not all darkmode screens are shown here)

Summary by CodeRabbit

  • New Features

    • Introduced new views for managing channels, peers, and settings, enhancing user interaction with the Lightning Network.
    • Added functionality for displaying and managing recovery phrases securely.
    • Added a new ChannelAddView for adding channels and a SeedView for displaying recovery phrases.
  • Bug Fixes

    • Improved error handling and user feedback mechanisms across various views.
  • Refactor

    • Renamed and restructured several existing views and view models for clarity and improved organization.
    • Removed redundant properties related to network color management from multiple view models.
    • Updated layout and structure of existing views to enhance usability and accessibility.
    • Enhanced the ChannelDetailView and SettingsView for better user experience.
    • Removed outdated views such as NodeIDView, ChannelsListView, and others to streamline the interface.
  • Documentation

    • Updated previews for new views to assist in development and debugging.

Copy link

coderabbitai bot commented Dec 18, 2024

Walkthrough

This pull request represents a significant refactoring of the LDKNodeMonday application, focusing on restructuring the project's architecture and views. The changes primarily involve renaming the "Profile" section to "Settings," updating various file references, and introducing new views and view models. Several existing views have been removed, streamlining the user interface for managing Lightning Network node settings, peers, channels, and recovery phrases. Additionally, modifications to error handling and code readability have been implemented in several service files.

Changes

File Path Change Summary
LDKNodeMonday.xcodeproj/project.pbxproj Renamed references from Profile to Settings, updated file references for NodeIDViewModel.swift to SettingsViewModel.swift, and NodeIDView.swift to SettingsView.swift. Updated DisconnectView.swift to PeerDetailsView.swift. Removed outdated package reference.
LDKNodeMonday/Service/Lightning Service/LightningNodeService.swift Adjusted error handling and configuration for storedEsploraURL, replaced forced unwrapping with safer error handling.
LDKNodeMonday/Utilities/Constants.swift Added trailing comma in EsploraServerURLNetwork struct.
LDKNodeMonday/View/Home/BitcoinView.swift Updated view references from NodeIDView to SettingsView and initialized PaymentsView with a new view model instance.
LDKNodeMonday/View/Profile/Channel/ChannelAddView.swift Deleted ChannelAddView.swift.
LDKNodeMonday/View/Profile/Channel/ChannelsListView.swift Deleted ChannelsListView.swift.
LDKNodeMonday/View/Profile/Danger/SeedView.swift Deleted SeedView.swift.
LDKNodeMonday/View/Profile/NodeIDView.swift Deleted NodeIDView.swift.
LDKNodeMonday/View/Profile/Peers/DisconnectView.swift Deleted DisconnectView.swift.
LDKNodeMonday/View/Profile/Peers/PeerView.swift Deleted PeerView.swift.
LDKNodeMonday/View/Profile/Peers/PeersListView.swift Deleted PeersListView.swift.
LDKNodeMonday/View/Settings/Channel/ChannelAddView.swift Added new ChannelAddView.swift.
LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift Restructured layout of ChannelDetailView.
LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift Added new ChannelsListView.swift.
LDKNodeMonday/View/Settings/Danger/SeedView.swift Added new SeedView.swift.
LDKNodeMonday/View/Settings/Peers/PeerView.swift Added new PeerView.swift.
LDKNodeMonday/View/Settings/Peers/PeersListView.swift Added new PeersListView.swift.
LDKNodeMonday/View/Settings/SettingsView.swift Added new SettingsView.swift.
LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift Added new PeerDetailsView.swift.
Multiple View Models Removed networkColor property and getColor() method from several view models including ChannelAddViewModel, ChannelDetailViewModel, ChannelsListViewModel, SeedViewModel, DisconnectViewModel, PeerViewModel, and PeersListViewModel. Renamed NodeIDViewModel to SettingsViewModel.

Poem

🐰 Hop, hop, through code's domain,
Refactoring views with lightning's reign,
Profile becomes Settings, clean and bright,
Views dancing in a restructured light!
A rabbit's touch, both swift and neat 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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 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: 12

🧹 Nitpick comments (21)
LDKNodeMonday/Service/Lightning Service/LightningNodeService.swift (1)

Line range hint 1-391: Consider implementing retry mechanisms for network operations.

Given that this is a network-dependent service handling Lightning Network operations, it would be beneficial to add retry mechanisms for network-related operations.

Consider:

  1. Adding retry logic for connection attempts
  2. Implementing exponential backoff for failed operations
  3. Adding circuit breaker patterns for external service calls

Would you like me to provide an example implementation of these patterns?

LDKNodeMonday/View/Settings/Peers/DisconnectView.swift (4)

25-25: Fix comment formatting

Add a space after the comment slashes to comply with SwiftLint guidelines.

-                        //.frame(width: 100)
+                        // .frame(width: 100)
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 25-25: Prefer at least one space after slashes for comments

(comment_spacing)


20-34: Enhance node ID display for better UX

Consider these improvements for better user experience:

  1. Add a copy button for the node ID
  2. Use a monospace font for better readability
  3. Consider showing a shortened version with expansion capability
 List {
     VStack(alignment: .leading) {
         Text("Node ID")
             .font(.subheadline.weight(.medium))
-        Text(viewModel.nodeId.description)
-            .truncationMode(.middle)
-            .lineLimit(1)
-            .font(.caption)
-            .foregroundColor(.secondary)
+        HStack {
+            Text(viewModel.nodeId.description)
+                .truncationMode(.middle)
+                .lineLimit(1)
+                .font(.custom("Menlo", size: 12))
+                .foregroundColor(.secondary)
+            Button(action: {
+                UIPasteboard.general.string = viewModel.nodeId.description
+            }) {
+                Image(systemName: "doc.on.doc")
+                    .font(.caption)
+            }
+        }
     }
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 25-25: Prefer at least one space after slashes for comments

(comment_spacing)


80-88: Enhance preview with multiple scenarios

Consider adding more preview scenarios to test different states:

  • Error state
  • Different node ID lengths
  • Dark/light mode variations
 #if DEBUG
     #Preview {
-        DisconnectView(
-            viewModel: .init(
-                nodeId: "03e39c737a691931dac0f9f9ee803f2ab08f7fd3bbb25ec08d9b8fdb8f51d3a8db"
-            )
-        )
+        Group {
+            DisconnectView(
+                viewModel: .init(
+                    nodeId: "03e39c737a691931dac0f9f9ee803f2ab08f7fd3bbb25ec08d9b8fdb8f51d3a8db"
+                )
+            )
+            DisconnectView(
+                viewModel: {
+                    let vm = DisconnectViewModel(nodeId: "short_id")
+                    vm.disconnectViewError = .init(title: "Error", detail: "Test error")
+                    return vm
+                }()
+            )
+            .preferredColorScheme(.dark)
+        }
     }
 #endif

44-56: Add confirmation dialog for disconnect action

Since disconnecting a peer is a critical operation, consider adding a confirmation dialog before proceeding with the disconnect action.

 Button {
+    guard !viewModel.isDisconnecting else { return }
+    viewModel.showingConfirmationDialog = true
+} label: {
+    Text("Disconnect")
+        .padding()
+}
+.confirmationDialog(
+    "Are you sure you want to disconnect this peer?",
+    isPresented: $viewModel.showingConfirmationDialog,
+    titleVisibility: .visible
+) {
     Button {
         viewModel.disconnect()
         self.presentationMode.wrappedValue.dismiss()
     } label: {
-        Text("Disconnect")
-            .padding()
+        Text("Confirm")
     }
-}
+    Button("Cancel", role: .cancel) { }
+}
LDKNodeMonday/View/Settings/Danger/SeedView.swift (4)

79-87: Improve error handling specificity

The current error handling uses generic fallbacks for unknown errors. Consider:

  1. Using more specific error types
  2. Providing actionable error messages
  3. Adding retry functionality for recoverable errors
-   .alert(isPresented: $showingSeedViewErrorAlert) {
-       Alert(
-           title: Text(viewModel.seedViewError?.title ?? "Unknown"),
-           message: Text(viewModel.seedViewError?.detail ?? ""),
-           dismissButton: .default(Text("OK")) {
-               viewModel.seedViewError = nil
-           }
-       )
-   }
+   .alert(isPresented: $showingSeedViewErrorAlert) {
+       Alert(
+           title: Text(viewModel.seedViewError?.title ?? "Error Accessing Recovery Phrase"),
+           message: Text(viewModel.seedViewError?.detail ?? "Unable to access your recovery phrase. Please ensure your device is secure and try again."),
+           primaryButton: .default(Text("Retry")) {
+               viewModel.getSeed()
+           },
+           secondaryButton: .cancel(Text("Dismiss")) {
+               viewModel.seedViewError = nil
+           }
+       )
+   }

72-75: Enhance accessibility support

While the current implementation includes dynamic type support, consider adding:

  1. VoiceOver labels for critical UI elements
  2. Haptic feedback for important actions
  3. Accessibility hints for better context
-   }.dynamicTypeSize(...DynamicTypeSize.accessibility1)
+   }.dynamicTypeSize(...DynamicTypeSize.accessibility1)
+   .accessibilityElement(children: .contain)
+   .accessibilityLabel("Recovery Phrase View")
+   .accessibilityHint("Contains sensitive recovery information. Please ensure privacy before proceeding.")

92-96: Enhance preview provider with multiple states

Consider adding preview cases for different view states to aid development and testing:

  1. Initial warning state
  2. Shown recovery phrase state
  3. Error state
  4. Copying state
 #if DEBUG
-    #Preview {
-        SeedView(viewModel: .init())
+    #Preview("Warning State") {
+        SeedView(viewModel: .init())
+    }
+    
+    #Preview("Shown Recovery Phrase") {
+        let vm = SeedViewModel()
+        let view = SeedView(viewModel: vm)
+        view.showRecoveryPhrase = true
+        return view
+    }
+    
+    #Preview("Error State") {
+        let vm = SeedViewModel()
+        vm.seedViewError = SeedViewError(title: "Error", detail: "Test error message")
+        return SeedView(viewModel: vm)
     }
 #endif

67-67: Fix comment spacing

Add a space after the double slash for consistent comment formatting.

-    //Spacer()
+    // Spacer()
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 67-67: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View/Settings/Peers/PeersListView.swift (1)

42-53: Consider using a more accessible color scheme for connection status

The connection status indicators only use color secondary which might not be sufficient for users with color vision deficiencies. Consider adding distinct icons or patterns to improve accessibility.

- peer.isConnected
-     ? HStack(alignment: .firstTextBaseline, spacing: 2) {
-         Text("Connected")
-         Image(systemName: "checkmark")
-     }.font(.caption)
-         .foregroundColor(.secondary)
-     : HStack {
-         Text("Not Connected")
-         Image(systemName: "xmark")
-     }.font(.caption)
-         .foregroundColor(.secondary)
+ peer.isConnected
+     ? HStack(alignment: .firstTextBaseline, spacing: 2) {
+         Text("Connected")
+         Image(systemName: "checkmark.circle.fill")
+     }.font(.caption)
+         .foregroundColor(.green)
+     : HStack {
+         Text("Not Connected")
+         Image(systemName: "xmark.circle.fill")
+     }.font(.caption)
+         .foregroundColor(.red)
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 43-43: Using ternary to call Void functions should be avoided

(void_function_in_ternary)

LDKNodeMonday/View/Settings/Peers/PeerView.swift (1)

50-52: Address SwiftLint warnings about unused closure parameters

The onChange modifiers have unused oldValue parameters.

- ).onChange(of: viewModel.nodeId) { oldValue, newValue in
+ ).onChange(of: viewModel.nodeId) { _, newValue in

- ).onChange(of: viewModel.address) { oldValue, newValue in
+ ).onChange(of: viewModel.address) { _, newValue in

Also applies to: 71-73

🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 50-50: Unused parameter in a closure should be replaced with _

(unused_closure_parameter)

LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift (3)

38-79: Consider extracting channel item into a separate view component.

The channel item layout is complex and could benefit from being extracted into a separate view component for better maintainability and reusability.

Consider creating a ChannelListItemView:

struct ChannelListItemView: View {
    let channel: Channel
    let alias: String?
    
    var body: some View {
        HStack(alignment: .center, spacing: 15) {
            // Current layout code...
        }
    }
}

Also consider adding formatting for the capacity values to improve readability:

-Text("Send \(channel.outboundCapacityMsat/1000) sats ")
+Text("Send \(NumberFormatter.localizedString(from: NSNumber(value: channel.outboundCapacityMsat/1000), number: .decimal)) sats")

96-98: Enhance accessibility with VoiceOver support.

While dynamic type support is implemented, consider adding VoiceOver descriptions for better accessibility.

Add accessibility labels to improve VoiceOver support:

 Circle()
     .stroke(lineWidth: 2)
     .frame(width: 40, height: 40)
+    .accessibilityLabel("Channel icon")

 Text("\(channel.channelValueSats) sats")
+    .accessibilityLabel("Channel value: \(channel.channelValueSats) satoshis")

101-107: Enhance toolbar button clarity.

Consider using a more descriptive label for the Add button to improve user understanding.

-Text("Add")
+Text("Add Channel")
LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (2)

26-62: Enhance clipboard operation error handling.

The clipboard operation should handle potential failures and provide appropriate feedback.

 Button {
-    UIPasteboard.general.string = property.value
+    do {
+        try UIPasteboard.general.setString(property.value)
+        lastCopiedItemId = property.name
+    } catch {
+        // Handle clipboard error
+        print("Failed to copy to clipboard: \(error)")
+    }
-    lastCopiedItemId = property.name
     DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
         lastCopiedItemId = nil
     }
 }

70-77: Add loading state during channel closure.

Consider adding a loading state to provide feedback during the channel closure process.

+@State private var isClosing = false

 Button("Close") {
     showingConfirmationAlert = true
 }
 .foregroundColor(.red)
 .padding()
+.disabled(isClosing)

 // In the confirmation action:
 Button("Yes", role: .destructive) {
+    isClosing = true
     viewModel.close()
     refreshFlag = true
     if !showingChannelDetailViewErrorAlert {
         DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
+            isClosing = false
             self.presentationMode.wrappedValue.dismiss()
         }
     }
 }
LDKNodeMonday/View/Settings/SettingsView.swift (3)

31-48: Well-organized settings structure with minor style issues.

The settings form is well-organized with clear sections. However, there are some comment style issues to address.

Fix comment spacing as per SwiftLint:

-// Wallet
+// Wallet

-// Lightning node
+// Lightning node

-// Danger zone
+// Danger zone

52-69: Add visual feedback for node ID copy operation.

Consider adding visual feedback when the node ID is copied to improve user experience.

+@State private var nodeIdCopied = false

 Button {
     UIPasteboard.general.string = viewModel.nodeID
+    nodeIdCopied = true
+    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
+        nodeIdCopied = false
+    }
 } label: {
     Image(systemName: nodeIdCopied ? "checkmark" : "doc.on.doc")
         .resizable()
         .scaledToFit()
         .frame(width: 24, height: 24)
         .foregroundColor(.accentColor)
 }

154-174: Enhance error recovery mechanism.

Consider adding retry functionality for failed operations.

+@State private var retryCount = 0
+let maxRetries = 3

 .onAppear {
     Task {
+        func retryOperation() async {
+            do {
                 viewModel.getNodeID()
                 viewModel.getNetwork()
                 viewModel.getEsploraUrl()
                 viewModel.getColor()
                 await viewModel.getStatus()
+                retryCount = 0
+            } catch {
+                if retryCount < maxRetries {
+                    retryCount += 1
+                    try await Task.sleep(nanoseconds: UInt64(1_000_000_000 * retryCount))
+                    await retryOperation()
+                }
+            }
+        }
+        await retryOperation()
     }
 }
LDKNodeMonday/View/Settings/Channel/ChannelAddView.swift (2)

12-20: LGTM! Well-structured view with proper state management.

The view follows SwiftUI best practices with appropriate property wrappers and clear separation of concerns. Consider adding a documentation comment describing the view's purpose and responsibilities.

Add a documentation comment like:

+/// A view that allows users to add a new Lightning Network channel by providing
+/// node ID, address, and channel capacity information. Supports manual input,
+/// QR code scanning, and clipboard paste functionality.
 struct ChannelAddView: View {

217-237: Enhance QR code scanning error handling.

The error handling could be more specific to help users understand and resolve scanning issues.

Consider enhancing the error handling:

 func handleScan(result: Result<ScanResult, ScanError>) {
     isShowingScanner = false
     switch result {
     case .success(let result):
         let scannedQRCode = result.string.lowercased()
         if let peer = scannedQRCode.parseConnectionInfo() {
             viewModel.nodeId = peer.nodeID
             viewModel.address = peer.address
         } else {
             viewModel.channelAddViewError = .init(
-                title: "QR Parsing Error",
-                detail: "Failed to parse the QR code."
+                title: "Invalid QR Code",
+                detail: "The scanned QR code doesn't contain valid Lightning node connection information. Please ensure you're scanning a Lightning node QR code."
             )
         }
     case .failure(let error):
+        let errorDetail: String
+        switch error {
+        case .badInput:
+            errorDetail = "The camera feed is not working properly."
+        case .badOutput:
+            errorDetail = "Failed to process the scanned image."
+        case .permissionDenied:
+            errorDetail = "Camera access is required to scan QR codes. Please enable it in Settings."
+        default:
+            errorDetail = error.localizedDescription
+        }
         viewModel.channelAddViewError = .init(
             title: "Scan Error",
-            detail: error.localizedDescription
+            detail: errorDetail
         )
     }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ede53bf and 7ea19e1.

📒 Files selected for processing (20)
  • LDKNodeMonday.xcodeproj/project.pbxproj (4 hunks)
  • LDKNodeMonday/Service/Lightning Service/LightningNodeService.swift (1 hunks)
  • LDKNodeMonday/Utilities/Constants.swift (1 hunks)
  • LDKNodeMonday/View/Home/BitcoinView.swift (1 hunks)
  • LDKNodeMonday/View/Home/NetworkSettingsView.swift (1 hunks)
  • LDKNodeMonday/View/Profile/Channel/ChannelAddView.swift (0 hunks)
  • LDKNodeMonday/View/Profile/Channel/ChannelsListView.swift (0 hunks)
  • LDKNodeMonday/View/Profile/Danger/SeedView.swift (0 hunks)
  • LDKNodeMonday/View/Profile/NodeIDView.swift (0 hunks)
  • LDKNodeMonday/View/Profile/Peers/DisconnectView.swift (0 hunks)
  • LDKNodeMonday/View/Profile/Peers/PeerView.swift (0 hunks)
  • LDKNodeMonday/View/Profile/Peers/PeersListView.swift (0 hunks)
  • LDKNodeMonday/View/Settings/Channel/ChannelAddView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Danger/SeedView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/DisconnectView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeerView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeersListView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/SettingsView.swift (1 hunks)
💤 Files with no reviewable changes (7)
  • LDKNodeMonday/View/Profile/Peers/DisconnectView.swift
  • LDKNodeMonday/View/Profile/Channel/ChannelsListView.swift
  • LDKNodeMonday/View/Profile/Danger/SeedView.swift
  • LDKNodeMonday/View/Profile/Peers/PeerView.swift
  • LDKNodeMonday/View/Profile/NodeIDView.swift
  • LDKNodeMonday/View/Profile/Peers/PeersListView.swift
  • LDKNodeMonday/View/Profile/Channel/ChannelAddView.swift
✅ Files skipped from review due to trivial changes (2)
  • LDKNodeMonday/Utilities/Constants.swift
  • LDKNodeMonday/View/Home/NetworkSettingsView.swift
🧰 Additional context used
📓 Learnings (1)
LDKNodeMonday.xcodeproj/project.pbxproj (1)
Learnt from: danielnordh
PR: reez/Monday#131
File: LDKNodeMonday.xcodeproj/project.pbxproj:180-180
Timestamp: 2024-12-05T17:54:34.328Z
Learning: Multiple LDKNode framework references in `LDKNodeMonday.xcodeproj/project.pbxproj` may be intentional when using custom forks or multiple versions of LDKNode, and should not be flagged as duplicates.
🪛 SwiftLint (0.57.0)
LDKNodeMonday/View/Settings/Peers/DisconnectView.swift

[Warning] 25-25: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View/Settings/Channel/ChannelAddView.swift

[Warning] 51-51: Unused parameter in a closure should be replaced with _

(unused_closure_parameter)


[Warning] 72-72: Unused parameter in a closure should be replaced with _

(unused_closure_parameter)

LDKNodeMonday/View/Settings/Danger/SeedView.swift

[Warning] 67-67: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View/Settings/SettingsView.swift

[Warning] 96-96: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 109-109: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 125-125: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 144-144: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View/Settings/Peers/PeersListView.swift

[Warning] 43-43: Using ternary to call Void functions should be avoided

(void_function_in_ternary)

LDKNodeMonday/View/Settings/Peers/PeerView.swift

[Warning] 50-50: Unused parameter in a closure should be replaced with _

(unused_closure_parameter)


[Warning] 71-71: Unused parameter in a closure should be replaced with _

(unused_closure_parameter)

🔇 Additional comments (6)
LDKNodeMonday/Service/Lightning Service/LightningNodeService.swift (1)

27-27: Verify the default Esplora URL configuration.

The default Esplora URL is hardcoded to use LQWD's signet server. This might need to be aligned with the network type to prevent cross-network issues.

Consider:

  1. Making the default URL network-aware using the network parameter
  2. Moving the URL configuration to a configuration file for easier maintenance
  3. Adding a fallback mechanism if the LQWD server is unreachable
-           ?? EsploraServer.lqwd_signet.url
+           ?? {
+               switch self.network {
+                   case .signet:
+                       return EsploraServer.lqwd_signet.url
+                   case .testnet:
+                       return EsploraServer.testnet.url
+                   // Add other network cases
+                   default:
+                       return EsploraServer.default.url
+               }
+           }()
LDKNodeMonday/View/Settings/Peers/DisconnectView.swift (1)

11-15: LGTM! Properties follow SwiftUI best practices

The view properties are well-structured using appropriate property wrappers.

LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift (1)

15-89: LGTM! Well-structured list implementation.

The implementation follows SwiftUI best practices with proper empty state handling, clear sorting logic, and clean navigation structure.

LDKNodeMonday/View/Home/BitcoinView.swift (1)

242-242: LGTM! Clean replacement of NodeIDView with SettingsView.

The change aligns with the PR objectives of updating the Settings view structure.

LDKNodeMonday.xcodeproj/project.pbxproj (2)

461-474: LGTM! Clean project structure update.

The renaming of the Profile group to Settings and associated file reference updates are consistent with the PR objectives.


69-69: LGTM! Proper file reference updates.

The file reference changes for SettingsView.swift are correctly reflected in the project structure.

Also applies to: 150-150, 686-686

LDKNodeMonday/View/Settings/Peers/DisconnectView.swift Outdated Show resolved Hide resolved
LDKNodeMonday/View/Settings/Peers/DisconnectView.swift Outdated Show resolved Hide resolved
LDKNodeMonday/View/Settings/Danger/SeedView.swift Outdated Show resolved Hide resolved
LDKNodeMonday/View/Settings/Peers/PeerView.swift Outdated Show resolved Hide resolved
LDKNodeMonday/View/Settings/Peers/PeerView.swift Outdated Show resolved Hide resolved
LDKNodeMonday/View/Settings/SettingsView.swift Outdated Show resolved Hide resolved
LDKNodeMonday/View/Settings/Channel/ChannelAddView.swift Outdated Show resolved Hide resolved
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: 1

♻️ Duplicate comments (1)
LDKNodeMonday/View/Settings/Peers/PeersListView.swift (1)

77-81: ⚠️ Potential issue

Add error handling for async operations

The async tasks still lack error handling as mentioned in the previous review.

 .onAppear {
     Task {
-        viewModel.listPeers()
-        viewModel.getColor()
+        do {
+            try await viewModel.listPeers()
+            try await viewModel.getColor()
+        } catch {
+            // Handle or propagate error appropriately
+            print("Error updating peers list: \(error)")
+        }
     }
 }
🧹 Nitpick comments (7)
LDKNodeMonday/View/Settings/Peers/PeersListView.swift (2)

42-53: Simplify connection status display logic

The current ternary implementation for connection status is complex and flagged by SwiftLint. Consider extracting this into a separate view component.

- peer.isConnected
-     ? HStack(alignment: .firstTextBaseline, spacing: 2) {
-         Text("Connected")
-         Image(systemName: "checkmark")
-     }.font(.caption)
-         .foregroundColor(.secondary)
-     : HStack {
-         Text("Not Connected")
-         Image(systemName: "xmark")
-     }.font(.caption)
-         .foregroundColor(.secondary)
+ ConnectionStatusView(isConnected: peer.isConnected)

+ struct ConnectionStatusView: View {
+     let isConnected: Bool
+     
+     var body: some View {
+         HStack(alignment: .firstTextBaseline, spacing: 2) {
+             Text(isConnected ? "Connected" : "Not Connected")
+             Image(systemName: isConnected ? "checkmark" : "xmark")
+         }
+         .font(.caption)
+         .foregroundColor(.secondary)
+     }
+ }
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 43-43: Using ternary to call Void functions should be avoided

(void_function_in_ternary)


38-41: Enhance accessibility for node ID display

While the view implements dynamic type sizing, the truncated node ID could be made more accessible.

- Text("\(peer.nodeId) ")
-     .truncationMode(.middle)
-     .lineLimit(1)
-     .font(.subheadline.weight(.medium))
+ Text("\(peer.nodeId) ")
+     .truncationMode(.middle)
+     .lineLimit(1)
+     .font(.subheadline.weight(.medium))
+     .accessibilityLabel("Node ID: \(peer.nodeId)")
+     .accessibilityHint("Tap to view peer details")
LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift (5)

2-2: Update file header comment to match the actual filename

The file header shows "DisconnectView.swift" but the actual filename is "PeerDetailsView.swift".

-//  DisconnectView.swift
+//  PeerDetailsView.swift

11-16: Consider renaming DisconnectViewModel to PeerDetailsViewModel

The current ViewModel name focuses on a single action (disconnect) while the view handles broader peer details functionality. A more appropriate name would better reflect its purpose.

-    @ObservedObject var viewModel: DisconnectViewModel
+    @ObservedObject var viewModel: PeerDetailsViewModel

26-26: Remove commented code

Remove the commented frame modifier if it's no longer needed.

-                        //.frame(width: 100)
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 26-26: Prefer at least one space after slashes for comments

(comment_spacing)


66-74: Enhance error alert implementation

The current error handling could be improved:

  1. Unknown is used as a fallback title
  2. Empty string is used as a fallback detail
  3. Error state might persist after dismissal

Consider using more meaningful fallback messages and ensure proper error state cleanup.

         .alert(isPresented: $showErrorAlert) {
             Alert(
-                title: Text(viewModel.disconnectViewError?.title ?? "Unknown"),
-                message: Text(viewModel.disconnectViewError?.detail ?? ""),
+                title: Text(viewModel.disconnectViewError?.title ?? "Error"),
+                message: Text(viewModel.disconnectViewError?.detail ?? "An unexpected error occurred"),
                 dismissButton: .default(Text("OK")) {
                     viewModel.disconnectViewError = nil
+                    showErrorAlert = false
                 }
             )
         }

88-96: Enhance preview with multiple states

Consider adding previews for different states like loading, error, and different node ID lengths to ensure the UI handles all cases correctly.

 #if DEBUG
     #Preview {
+        NavigationView {
             PeerDetailsView(
                 viewModel: .init(
                     nodeId: "03e39c737a691931dac0f9f9ee803f2ab08f7fd3bbb25ec08d9b8fdb8f51d3a8db"
                 )
             )
+        }
+    }
+    
+    #Preview("Error State") {
+        NavigationView {
+            PeerDetailsView(
+                viewModel: .init(
+                    nodeId: "short_id",
+                    initialError: .init(title: "Error", detail: "Sample error message")
+                )
+            )
+        }
     }
 #endif
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7ea19e1 and eb5b9d9.

📒 Files selected for processing (3)
  • LDKNodeMonday.xcodeproj/project.pbxproj (8 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeersListView.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • LDKNodeMonday.xcodeproj/project.pbxproj
🧰 Additional context used
🪛 SwiftLint (0.57.0)
LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift

[Warning] 26-26: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View/Settings/Peers/PeersListView.swift

[Warning] 43-43: Using ternary to call Void functions should be avoided

(void_function_in_ternary)

🔇 Additional comments (1)
LDKNodeMonday/View/Settings/Peers/PeersListView.swift (1)

11-13: LGTM! Follows SwiftUI MVVM best practices

The view is properly structured with an observed view model for state management.

LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift Outdated Show resolved Hide resolved
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: 2

♻️ Duplicate comments (2)
LDKNodeMonday/View/Settings/Peers/PeerView.swift (1)

124-144: 🛠️ Refactor suggestion

Simplify connection logic

The dismissal logic is redundant as it performs the same action regardless of the error alert state.

 Button("Connect Peer") {
     self.viewModel.isProgressViewShowing = true
     Task {
         await viewModel.connect(
             nodeId: viewModel.nodeId,
             address: viewModel.address
         )
     }
-    if showingPeerViewErrorAlert == true {
-        DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
-            self.presentationMode.wrappedValue.dismiss()
-        }
-    }
-
-    if showingPeerViewErrorAlert == false {
-        DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
-            self.presentationMode.wrappedValue.dismiss()
-        }
-    }
+    DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
+        self.presentationMode.wrappedValue.dismiss()
+    }
 }
LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift (1)

57-62: ⚠️ Potential issue

Improve disconnect operation handling

The current implementation has several potential issues:

  1. No loading state during the disconnect operation
  2. Hardcoded delay for dismissal
  3. No error handling for the dismiss operation

Consider implementing a proper async/await pattern with loading state.

-                viewModel.disconnect()
-
-                DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
-                    self.presentationMode.wrappedValue.dismiss()
-                }
+                Task {
+                    await viewModel.disconnect()
+                    await MainActor.run {
+                        self.presentationMode.wrappedValue.dismiss()
+                    }
+                }
🧹 Nitpick comments (12)
LDKNodeMonday/View/Settings/Peers/PeerView.swift (4)

50-52: Replace unused parameter with underscore

The closure parameter oldValue is unused.

-).onChange(of: viewModel.nodeId) { oldValue, newValue in
+).onChange(of: viewModel.nodeId) { _, newValue in
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 50-50: Unused parameter in a closure should be replaced with _

(unused_closure_parameter)


71-73: Replace unused parameter with underscore

The closure parameter oldValue is unused.

-).onChange(of: viewModel.address) { oldValue, newValue in
+).onChange(of: viewModel.address) { _, newValue in
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 71-71: Unused parameter in a closure should be replaced with _

(unused_closure_parameter)


187-216: Consider moving validation logic to ViewModel

The QR code validation logic could be moved to the ViewModel to maintain better separation of concerns and improve testability.

+// In PeerViewModel
+func validatePeer(_ peer: PeerInfo) -> Bool {
+    return peer.nodeID.count >= 32 && peer.address.contains(":")
+}
+
+func handleInvalidPeer() -> PeerViewError {
+    return .init(
+        title: "Invalid Format",
+        detail: "The scanned QR code contains invalid peer information."
+    )
+}

// In PeerView
func handleScan(result: Result<ScanResult, ScanError>) {
    isShowingScanner = false
    switch result {
    case .success(let result):
        let scannedQRCode = result.string.lowercased()
        if let peer = scannedQRCode.parseConnectionInfo() {
-            guard peer.nodeID.count >= 32,
-                peer.address.contains(":")
-            else {
-                self.viewModel.peerViewError = .init(
-                    title: "Invalid Format",
-                    detail: "The scanned QR code contains invalid peer information."
-                )
+            guard viewModel.validatePeer(peer) else {
+                self.viewModel.peerViewError = viewModel.handleInvalidPeer()
                return
            }
            viewModel.nodeId = peer.nodeID
            viewModel.address = peer.address

220-224: Enhance preview with multiple states

Consider adding more preview states to help with UI development and testing.

 #if DEBUG
     #Preview {
-        PeerView(viewModel: .init())
+        Group {
+            PeerView(viewModel: .init())
+                .previewDisplayName("Default State")
+            
+            PeerView(viewModel: {
+                let vm = PeerViewModel()
+                vm.nodeId = "03a5b467d7f...4c2b099b8250c"
+                vm.address = "172.18.0.2:9735"
+                return vm
+            }())
+            .previewDisplayName("Filled State")
+            
+            PeerView(viewModel: {
+                let vm = PeerViewModel()
+                vm.isProgressViewShowing = true
+                return vm
+            }())
+            .previewDisplayName("Loading State")
+        }
     }
 #endif
LDKNodeMonday/View/Settings/Danger/SeedView.swift (5)

12-19: Consider adding memory security measures for sensitive data

Since this view handles sensitive recovery phrases, consider implementing additional security measures:

  1. Mark sensitive variables with @SecureField
  2. Clear sensitive data when the view disappears
 struct SeedView: View {
     @ObservedObject var viewModel: SeedViewModel
     @State private var showAlert = false
     @State private var showRecoveryPhrase = false
     @State private var isCopied = false
     @State private var showCheckmark = false
     @State private var showingSeedViewErrorAlert = false
+    
+    private func clearSensitiveData() {
+        showRecoveryPhrase = false
+        isCopied = false
+        UIPasteboard.general.string = ""
+    }

24-43: Enhance accessibility for warning message

The warning message should be more accessible:

  1. Add accessibilityLabel for better screen reader support
  2. Consider using semantic .alert role
 Text(
     "Warning! \n\n Never share the recovery phrase. Doing so will put your funds at risk."
 )
 .font(.body)
 .multilineTextAlignment(.center)
 .padding(40)
+.accessibilityLabel("Security Warning")
+.accessibilityAddTraits(.isAlert)

86-94: Enhance error handling and user feedback

Consider improving the error handling:

  1. Add specific error cases instead of using optional strings
  2. Provide more detailed error messages
  3. Add retry functionality where appropriate
 .alert(isPresented: $showingSeedViewErrorAlert) {
     Alert(
-        title: Text(viewModel.seedViewError?.title ?? "Unknown"),
-        message: Text(viewModel.seedViewError?.detail ?? ""),
+        title: Text(viewModel.seedViewError?.title ?? "Error"),
+        message: Text(viewModel.seedViewError?.detail ?? "An unexpected error occurred. Please try again."),
         dismissButton: .default(Text("OK")) {
             viewModel.seedViewError = nil
+            // Consider adding retry logic here if appropriate
         }
     )
 }

99-103: Enhance preview with different states

Consider adding multiple preview states to help with UI development:

  1. Error state
  2. Loading state
  3. Different phrase lengths (12/24 words)
#if DEBUG
struct SeedView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            SeedView(viewModel: .init()) // Default state
            
            SeedView(viewModel: {
                let vm = SeedViewModel()
                vm.seedViewError = .init(title: "Error", detail: "Test error")
                return vm
            }())
            .previewDisplayName("Error State")
            
            // Add more preview cases as needed
        }
    }
}
#endif

74-74: Fix comment spacing

Add a space after the double slash for consistency with Swift style guidelines.

-    //Spacer()
+    // Spacer()
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 74-74: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift (3)

2-2: Update file header to match new filename

The file header still shows the old filename "DisconnectView.swift". Update it to "PeerDetailsView.swift" for consistency.

-//  DisconnectView.swift
+//  PeerDetailsView.swift

25-25: Remove commented-out code

Remove the commented frame modifier as it adds noise to the codebase.

-                        //.frame(width: 100)
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 25-25: Prefer at least one space after slashes for comments

(comment_spacing)


20-36: Consider simplifying the List structure

The current implementation uses a List with a single VStack item. Consider simplifying to just use the VStack directly if there won't be multiple items.

-            List {
                 VStack(alignment: .leading) {
                     Text("Node ID")
                         .font(.subheadline.weight(.medium))
                     Text(viewModel.nodeId.description)
                         .truncationMode(.middle)
                         .lineLimit(1)
                         .font(.caption)
                         .foregroundColor(.secondary)
                 }
                 .padding(.top, 5)
-                .listRowSeparator(.hidden)
-                .listRowBackground(Color.clear)
-            }
-            .listStyle(.plain)
+                .padding(.horizontal)
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 25-25: Prefer at least one space after slashes for comments

(comment_spacing)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between eb5b9d9 and 5310e53.

📒 Files selected for processing (3)
  • LDKNodeMonday/View/Settings/Danger/SeedView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeerView.swift (1 hunks)
🧰 Additional context used
🪛 SwiftLint (0.57.0)
LDKNodeMonday/View/Settings/Danger/SeedView.swift

[Warning] 74-74: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift

[Warning] 25-25: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View/Settings/Peers/PeerView.swift

[Warning] 50-50: Unused parameter in a closure should be replaced with _

(unused_closure_parameter)


[Warning] 71-71: Unused parameter in a closure should be replaced with _

(unused_closure_parameter)

🔇 Additional comments (6)
LDKNodeMonday/View/Settings/Peers/PeerView.swift (2)

1-11: LGTM: Clean imports and structure

The file structure is clean and imports are appropriate for the required functionality.


12-19: LGTM: Well-structured state management

The view's state management follows SwiftUI best practices with appropriate use of property wrappers.

LDKNodeMonday/View/Settings/Danger/SeedView.swift (1)

51-76: LGTM: Clipboard security measures implemented

The implementation includes proper clipboard security measures:

  1. Clears clipboard after 60 seconds
  2. Provides visual feedback
  3. Resets UI state appropriately
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 74-74: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift (3)

10-15: LGTM! Properties are well-structured

The view properties follow SwiftUI best practices with appropriate use of property wrappers.


65-78: LGTM! Well-implemented error handling

The alert implementation follows best practices with:

  • Proper error handling
  • User-friendly error messages
  • Fallback values for unknown errors
  • Clean error state management

87-95: LGTM! Well-structured preview

The preview implementation follows SwiftUI best practices and provides a good sample node ID for development testing.

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 (10)
LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (2)

38-55: Consider extracting magic numbers

The copy feedback implementation is good, but consider extracting the hardcoded 2-second duration to a named constant for better maintainability.

+ private let copyFeedbackDuration: TimeInterval = 2.0
  Button {
      UIPasteboard.general.string = property.value
      lastCopiedItemId = property.name
-     DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
+     DispatchQueue.main.asyncAfter(deadline: .now() + copyFeedbackDuration) {
          lastCopiedItemId = nil
      }
  }

Line range hint 78-107: Consider extracting dismissal delay constant

The alert handling is well-implemented, but consider extracting the hardcoded 0.25-second dismissal delay to a named constant for consistency and maintainability.

+ private let dismissalDelay: TimeInterval = 0.25
  Button("Yes", role: .destructive) {
      viewModel.close()
      refreshFlag = true
      if !showingChannelDetailViewErrorAlert {
-         DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
+         DispatchQueue.main.asyncAfter(deadline: .now() + dismissalDelay) {
              self.presentationMode.wrappedValue.dismiss()
          }
      }
  }
LDKNodeMonday/View/Settings/SettingsView.swift (5)

27-27: Remove unused state variable.

The showGreeting state variable appears to be unused in the view.

-    @State private var showGreeting = true

15-25: Consider grouping related state variables.

Consider organizing state variables into logical groups for better maintainability:

-    @State private var isCopied = false
-    @State private var showCheckmark = false
-    @State private var showingNodeIDErrorAlert = false
-    @State private var isSeedPresented = false
-    @State private var showingStopNodeConfirmation = false
-    @State private var showingDeleteSeedConfirmation = false
-    @State private var showingShowSeedConfirmation = false
-    @State private var showingResetAppConfirmation = false
-    @State private var isViewPeersPresented = false
-    @State private var refreshFlag = false
-    @State private var isPaymentsPresented = false
+    // UI State
+    @State private var isCopied = false
+    @State private var showCheckmark = false
+    @State private var refreshFlag = false
+    
+    // Navigation State
+    @State private var isSeedPresented = false
+    @State private var isViewPeersPresented = false
+    @State private var isPaymentsPresented = false
+    
+    // Alert State
+    @State private var showingNodeIDErrorAlert = false
+    @State private var showingStopNodeConfirmation = false
+    @State private var showingDeleteSeedConfirmation = false
+    @State private var showingShowSeedConfirmation = false
+    @State private var showingResetAppConfirmation = false

60-69: Add visual feedback for copy action.

Consider adding visual feedback when the node ID is copied to improve user experience.

     Button {
         UIPasteboard.general.string = viewModel.nodeID
+        withAnimation {
+            isCopied = true
+            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
+                isCopied = false
+            }
+        }
     } label: {
-        Image(systemName: "doc.on.doc")
+        Image(systemName: isCopied ? "checkmark" : "doc.on.doc")
             .resizable()
             .scaledToFit()
             .frame(width: 24, height: 24)
             .foregroundColor(.accentColor)
     }

144-144: Remove or implement commented code.

Either remove the commented out scrollContentBackground modifier or implement it if needed.

-    //.scrollContentBackground(.hidden) // uncomment if we want white background
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 144-144: Prefer at least one space after slashes for comments

(comment_spacing)


154-161: Add error handling for async operations.

Consider adding error handling for the async operations in onAppear.

     .onAppear {
         Task {
+            do {
                 viewModel.getNodeID()
                 viewModel.getNetwork()
                 viewModel.getEsploraUrl()
-                await viewModel.getStatus()
+                try await viewModel.getStatus()
+            } catch {
+                viewModel.nodeIDError = .init(
+                    title: "Error",
+                    detail: "Failed to fetch node status: \(error.localizedDescription)"
+                )
+            }
         }
     }
LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift (2)

25-25: Remove commented code

The commented frame modifier serves no purpose and should be removed.

-                        //.frame(width: 100)
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 25-25: Prefer at least one space after slashes for comments

(comment_spacing)


66-79: Consider consolidating error alert logic

The error alert setup is split between the alert view modifier and onReceive. Consider combining them into a single error handling view extension.

extension View {
    func errorAlert(error: Binding<MondayError?>) -> some View {
        let showAlert = Binding(
            get: { error.wrappedValue != nil },
            set: { if !$0 { error.wrappedValue = nil } }
        )
        
        return alert(isPresented: showAlert) {
            Alert(
                title: Text(error.wrappedValue?.title ?? "Unknown"),
                message: Text(error.wrappedValue?.detail ?? ""),
                dismissButton: .default(Text("OK"))
            )
        }
    }
}

Usage:

-        .alert(isPresented: $showErrorAlert) {
-            Alert(
-                title: Text(viewModel.disconnectViewError?.title ?? "Unknown"),
-                message: Text(viewModel.disconnectViewError?.detail ?? ""),
-                dismissButton: .default(Text("OK")) {
-                    viewModel.disconnectViewError = nil
-                }
-            )
-        }
-        .onReceive(viewModel.$disconnectViewError) { errorMessage in
-            if errorMessage != nil {
-                showErrorAlert = true
-            }
-        }
+        .errorAlert(error: $viewModel.disconnectViewError)
LDKNodeMonday/View/Settings/Peers/PeersListView.swift (1)

42-53: Refactor connection status view for better readability

The ternary operator for view construction makes the code harder to read. Consider extracting the connection status view into a separate view component.

struct PeerConnectionStatusView: View {
    let isConnected: Bool
    
    var body: some View {
        HStack {
            Text(isConnected ? "Connected" : "Not Connected")
            Image(systemName: isConnected ? "checkmark" : "xmark")
        }
        .font(.caption)
        .foregroundColor(.secondary)
    }
}

Usage:

-                                        peer.isConnected
-                                            ? HStack(alignment: .firstTextBaseline, spacing: 2) {
-                                                Text("Connected")
-                                                Image(systemName: "checkmark")
-                                            }.font(.caption)
-                                                .foregroundColor(.secondary)
-                                            : HStack {
-                                                Text("Not Connected")
-                                                Image(systemName: "xmark")
-                                            }.font(.caption)
-                                                .foregroundColor(.secondary)
+                                        PeerConnectionStatusView(isConnected: peer.isConnected)
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 43-43: Using ternary to call Void functions should be avoided

(void_function_in_ternary)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5310e53 and a076876.

📒 Files selected for processing (15)
  • LDKNodeMonday/View Model/Profile/Channel/ChannelAddViewModel.swift (0 hunks)
  • LDKNodeMonday/View Model/Profile/Channel/ChannelDetailViewModel.swift (0 hunks)
  • LDKNodeMonday/View Model/Profile/Channel/ChannelsListViewModel.swift (0 hunks)
  • LDKNodeMonday/View Model/Profile/Danger/SeedViewModel.swift (0 hunks)
  • LDKNodeMonday/View Model/Profile/NodeIDViewModel.swift (0 hunks)
  • LDKNodeMonday/View Model/Profile/Peer/DisconnectViewModel.swift (1 hunks)
  • LDKNodeMonday/View Model/Profile/Peer/PeerViewModel.swift (0 hunks)
  • LDKNodeMonday/View Model/Profile/Peer/PeersListViewModel.swift (0 hunks)
  • LDKNodeMonday/View/Settings/Channel/ChannelAddView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeerView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeersListView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/SettingsView.swift (1 hunks)
💤 Files with no reviewable changes (7)
  • LDKNodeMonday/View Model/Profile/Channel/ChannelDetailViewModel.swift
  • LDKNodeMonday/View Model/Profile/Danger/SeedViewModel.swift
  • LDKNodeMonday/View Model/Profile/Peer/PeersListViewModel.swift
  • LDKNodeMonday/View Model/Profile/Channel/ChannelAddViewModel.swift
  • LDKNodeMonday/View Model/Profile/Peer/PeerViewModel.swift
  • LDKNodeMonday/View Model/Profile/Channel/ChannelsListViewModel.swift
  • LDKNodeMonday/View Model/Profile/NodeIDViewModel.swift
🚧 Files skipped from review as they are similar to previous changes (3)
  • LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift
  • LDKNodeMonday/View/Settings/Peers/PeerView.swift
  • LDKNodeMonday/View/Settings/Channel/ChannelAddView.swift
🧰 Additional context used
📓 Learnings (1)
LDKNodeMonday/View/Settings/SettingsView.swift (1)
Learnt from: danielnordh
PR: reez/Monday#143
File: LDKNodeMonday/View/Settings/Danger/SeedView.swift:44-49
Timestamp: 2024-12-18T16:56:17.814Z
Learning: In SwiftUI for the LDKNodeMonday project, additional BIP39 validation for the seed mnemonic isn't strictly necessary because the node won't start unless the seed is valid.
🪛 SwiftLint (0.57.0)
LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift

[Warning] 25-25: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View/Settings/Peers/PeersListView.swift

[Warning] 43-43: Using ternary to call Void functions should be avoided

(void_function_in_ternary)

LDKNodeMonday/View/Settings/SettingsView.swift

[Warning] 96-96: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 109-109: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 125-125: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 144-144: Prefer at least one space after slashes for comments

(comment_spacing)

🔇 Additional comments (7)
LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (3)

24-63: LGTM: Improved layout structure

The restructuring from ZStack to VStack with a plain List improves the view hierarchy and follows SwiftUI best practices. The layout is cleaner and more maintainable.


28-36: LGTM: Well-structured text hierarchy

The text styling creates a clear visual hierarchy with:

  • Medium subheadline for property names
  • Secondary-colored caption for values
  • Appropriate truncation for long values

67-77: LGTM: Well-configured navigation and accessibility

The navigation setup includes:

  • Appropriate dynamic type size limits for accessibility
  • Well-placed close button with proper destructive styling
  • Clear navigation title configuration
LDKNodeMonday/View/Settings/SettingsView.swift (1)

91-141: Enhance safety for critical actions.

Consider adding additional safeguards for critical actions in the danger zone.

Also, fix the comment spacing issues in the following lines:

-        Text("Stop Node")  //, systemImage: "exclamationmark.octagon")
+        Text("Stop Node")  // , systemImage: "exclamationmark.octagon")

-        Text("Reset Preferences")  //, systemImage: "minus.diamond")
+        Text("Reset Preferences")  // , systemImage: "minus.diamond")

-        Text("Delete Seed")  //, systemImage: "delete.left")
+        Text("Delete Seed")  // , systemImage: "delete.left")
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 96-96: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 109-109: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 125-125: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View Model/Profile/Peer/DisconnectViewModel.swift (1)

Line range hint 19-35: LGTM! Well-structured async implementation

The async implementation properly:

  • Maintains error handling on the main thread
  • Distinguishes between NodeError and unexpected errors
  • Provides clear error messages to the UI
LDKNodeMonday/View/Settings/Peers/PeerDetailsView.swift (1)

57-62: LGTM! Well-implemented async disconnect flow

The implementation properly:

  • Uses structured concurrency with Task
  • Ensures UI updates on MainActor
  • Handles view dismissal after disconnect
LDKNodeMonday/View/Settings/Peers/PeersListView.swift (1)

77-79: ⚠️ Potential issue

Add error handling for listPeers

The listPeers() call should be marked as async and include error handling.

             .onAppear {
                 Task {
-                    viewModel.listPeers()
+                    do {
+                        try await viewModel.listPeers()
+                    } catch {
+                        // Handle error appropriately
+                        print("Failed to list peers: \(error)")
+                    }
                 }
             }

Likely invalid or redundant comment.

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: 2

♻️ Duplicate comments (1)
LDKNodeMonday/View/Settings/SettingsView.swift (1)

94-144: ⚠️ Potential issue

Enhance safety measures for critical actions.

While basic confirmation dialogs are implemented, critical actions like "Delete Seed" should have stronger safeguards.

Consider implementing a more robust confirmation mechanism:

+ struct DeleteConfirmationView: View {
+     let title: String
+     let action: () -> Void
+     @Binding var isPresented: Bool
+     @State private var confirmText = ""
+     
+     var body: some View {
+         NavigationView {
+             Form {
+                 Section {
+                     TextField("Type DELETE to confirm", text: $confirmText)
+                 } footer: {
+                     Text("This action cannot be undone")
+                 }
+             }
+             .navigationTitle(title)
+             .toolbar {
+                 ToolbarItem(placement: .confirmationAction) {
+                     Button("Confirm") {
+                         if confirmText.uppercased() == "DELETE" {
+                             action()
+                             isPresented = false
+                         }
+                     }
+                     .disabled(confirmText.uppercased() != "DELETE")
+                 }
+                 ToolbarItem(placement: .cancellationAction) {
+                     Button("Cancel") {
+                         isPresented = false
+                     }
+                 }
+             }
+         }
+     }
+ }
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 99-99: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 112-112: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 128-128: Prefer at least one space after slashes for comments

(comment_spacing)

🧹 Nitpick comments (8)
LDKNodeMonday/View/Settings/Peers/PeersListView.swift (3)

42-53: Simplify connection status view logic.

The current ternary implementation is complex and flagged by SwiftLint. Consider extracting this into a separate view component for better readability and maintenance.

-                                        peer.isConnected
-                                            ? HStack(alignment: .firstTextBaseline, spacing: 2) {
-                                                Text("Connected")
-                                                Image(systemName: "checkmark")
-                                            }.font(.caption)
-                                                .foregroundColor(.secondary)
-                                            : HStack {
-                                                Text("Not Connected")
-                                                Image(systemName: "xmark")
-                                            }.font(.caption)
-                                                .foregroundColor(.secondary)
+                                        ConnectionStatusView(isConnected: peer.isConnected)

Add this new view:

struct ConnectionStatusView: View {
    let isConnected: Bool
    
    var body: some View {
        HStack(alignment: .firstTextBaseline, spacing: 2) {
            Text(isConnected ? "Connected" : "Not Connected")
            Image(systemName: isConnected ? "checkmark" : "xmark")
        }
        .font(.caption)
        .foregroundColor(.secondary)
    }
}
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 43-43: Using ternary to call Void functions should be avoided

(void_function_in_ternary)


38-41: Consider adding tooltip for full nodeId.

Since the nodeId is truncated, consider adding a tooltip to show the full value on hover/long press.

 Text("\(peer.nodeId) ")
     .truncationMode(.middle)
     .lineLimit(1)
     .font(.subheadline.weight(.medium))
+    .help(peer.nodeId)  // Shows full nodeId on hover

86-90: Enhance preview with multiple states.

Consider adding previews for different states (empty list, multiple peers, connected/disconnected states) to help during development.

 #if DEBUG
-    #Preview {
-        PeersListView(viewModel: .init())
+    #Preview("Empty State") {
+        PeersListView(viewModel: .init())
+    }
+    
+    #Preview("With Peers") {
+        let vm = PeersListViewModel()
+        vm.peers = [
+            // Add sample peer data
+        ]
+        return PeersListView(viewModel: vm)
     }
 #endif
LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (1)

Line range hint 27-144: Consider consolidating error handling.

The error handling pattern is duplicated across multiple methods (stop, delete, onboarding, getNetwork, getEsploraUrl). Consider extracting the common error handling logic into a reusable method.

+ private func handleError(_ operation: () throws -> Void) {
+     do {
+         try operation()
+     } catch let error as NodeError {
+         let errorString = handleNodeError(error)
+         DispatchQueue.main.async {
+             self.nodeIDError = .init(title: errorString.title, detail: errorString.detail)
+         }
+     } catch {
+         DispatchQueue.main.async {
+             self.nodeIDError = .init(
+                 title: "Unexpected error",
+                 detail: error.localizedDescription
+             )
+         }
+     }
+ }

  func stop() {
-     do {
-         try LightningNodeService.shared.stop()
-     } catch let error as NodeError {
-         let errorString = handleNodeError(error)
-         DispatchQueue.main.async {
-             self.nodeIDError = .init(title: errorString.title, detail: errorString.detail)
-         }
-     } catch {
-         DispatchQueue.main.async {
-             self.nodeIDError = .init(
-                 title: "Unexpected error",
-                 detail: error.localizedDescription
-             )
-         }
-     }
+     handleError { try LightningNodeService.shared.stop() }
  }
LDKNodeMonday/View/Settings/SettingsView.swift (1)

99-99: Fix comment formatting.

Add space after slashes in comments.

- Text("Stop Node")  //, systemImage: "exclamationmark.octagon")
+ Text("Stop Node")  // , systemImage: "exclamationmark.octagon")

Also applies to: 112-112, 128-128

🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 99-99: Prefer at least one space after slashes for comments

(comment_spacing)

LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (3)

27-35: Consider adding accessibility labels for better VoiceOver support.

While the text styling is well-implemented, consider enhancing accessibility by adding explicit accessibility labels that combine the property name and value.

 VStack(alignment: .leading) {
     Text(property.name)
         .font(.subheadline.weight(.medium))
     Text(property.value)
         .font(.caption)
         .foregroundColor(.secondary)
         .truncationMode(.middle)
-        .lineLimit(1)
+        .lineLimit(1)
+        .accessibilityLabel("\(property.name): \(property.value)")
 }

38-61: Optimize animation implementation.

The current animation wrapper placement might cause unnecessary re-renders. Consider moving it to wrap only the changing content.

 Button {
     UIPasteboard.general.string = property.value
     lastCopiedItemId = property.name
     DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
         lastCopiedItemId = nil
     }
 } label: {
     HStack {
-        withAnimation {
-            Image(
-                systemName: lastCopiedItemId == property.name
-                    ? "checkmark" : "doc.on.doc"
-            )
+        Image(
+            systemName: lastCopiedItemId == property.name
+                ? "checkmark" : "doc.on.doc"
+        )
+        .animation(.default, value: lastCopiedItemId)
     }
 }

73-83: Consider standardizing button padding.

The padding on the close button might be excessive and inconsistent with iOS standards.

 Button("Close") {
     showingConfirmationAlert = true
 }
 .foregroundColor(.red)
-.padding()
+.padding(.horizontal)
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a076876 and 742203d.

📒 Files selected for processing (6)
  • LDKNodeMonday.xcodeproj/project.pbxproj (12 hunks)
  • LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeersListView.swift (1 hunks)
  • LDKNodeMonday/View/Settings/SettingsView.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • LDKNodeMonday/View/Settings/Channel/ChannelsListView.swift
  • LDKNodeMonday.xcodeproj/project.pbxproj
🧰 Additional context used
📓 Learnings (1)
LDKNodeMonday/View/Settings/SettingsView.swift (1)
Learnt from: danielnordh
PR: reez/Monday#143
File: LDKNodeMonday/View/Settings/Danger/SeedView.swift:44-49
Timestamp: 2024-12-18T16:56:17.814Z
Learning: In SwiftUI for the LDKNodeMonday project, additional BIP39 validation for the seed mnemonic isn't strictly necessary because the node won't start unless the seed is valid.
🪛 SwiftLint (0.57.0)
LDKNodeMonday/View/Settings/Peers/PeersListView.swift

[Warning] 43-43: Using ternary to call Void functions should be avoided

(void_function_in_ternary)

LDKNodeMonday/View/Settings/SettingsView.swift

[Warning] 99-99: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 112-112: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 128-128: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 147-147: Prefer at least one space after slashes for comments

(comment_spacing)

🔇 Additional comments (6)
LDKNodeMonday/View/Settings/Peers/PeersListView.swift (3)

1-10: LGTM! File structure and imports are appropriate.


77-81: Add error handling for async task.

The async task should handle potential errors to prevent silent failures.

 .onAppear {
     Task {
-        viewModel.listPeers()
+        do {
+            try await viewModel.listPeers()
+        } catch {
+            print("Error listing peers: \(error)")
+            // Consider showing error to user
+        }
     }
 }

11-13: Verify if @StateObject would be more appropriate than @ObservedObject.

Consider using @StateObject instead of @ObservedObject if this view is responsible for the lifecycle of the view model. @StateObject ensures the view model survives view updates.

✅ Verification successful

Let me check the implementation details to understand how PeersListViewModel is created and used.


Keep @ObservedObject as it's correctly used for externally created view model

The current usage of @ObservedObject is appropriate since the view model is created and injected from parent views (SettingsView creates it via .init()). @StateObject would be incorrect here as it's meant for views that own their view model's lifecycle.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other usages of PeersListViewModel to understand ownership
rg -l "PeersListViewModel" --type swift

Length of output: 156


Script:

#!/bin/bash
# Check PeersListViewModel implementation and initialization
rg "PeersListViewModel" -A 5 --type swift

# Also check where PeersListView is used
rg "PeersListView" -A 5 --type swift

Length of output: 4272

LDKNodeMonday/View Model/Profile/SettingsViewModel.swift (1)

12-12: LGTM! Class renaming aligns with new Settings paradigm.

The renaming from NodeIDViewModel to SettingsViewModel better reflects its purpose and responsibilities. The removal of networkColor property simplifies state management.

LDKNodeMonday/View/Settings/SettingsView.swift (1)

145-145: LGTM! Good accessibility consideration.

The use of dynamicTypeSize with an upper limit ensures text remains readable while preventing layout issues.

LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (1)

23-25: LGTM! Clean view hierarchy restructuring.

The switch to VStack with a direct List implementation provides a cleaner and more maintainable structure.

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)
LDKNodeMonday/View/Settings/SettingsView.swift (5)

12-27: Remove unused state variable.

The showGreeting state variable on line 26 is declared but never used in the view.

-    @State private var showGreeting = true

43-49: Move URL manipulation logic to ViewModel.

The URL string manipulation logic should be moved to the ViewModel to maintain separation of concerns and improve reusability.

-    Label("Server", systemImage: "server.rack")
-        .badge(viewModel.esploraURL?.replacingOccurrences(of: "https://", with: "")
-            .replacingOccurrences(
-                of: "http://",
-                with: ""
-            ) ?? "No server")
+    Label("Server", systemImage: "server.rack")
+        .badge(viewModel.formattedEsploraURL)

Add this computed property to your ViewModel:

var formattedEsploraURL: String {
    guard let url = esploraURL else { return "No server" }
    return url.replacingOccurrences(of: "https://", with: "")
        .replacingOccurrences(of: "http://", with: "")
}

43-43: Track technical debt: NetworkSettingsView dependency.

The comment indicates a dependency issue preventing the network settings from being moved to a dedicated view.

Would you like me to create a GitHub issue to track this technical debt?


67-79: Add accessibility label to copy button.

The copy button should have an accessibility label to improve VoiceOver support.

 Button {
     UIPasteboard.general.string = viewModel.nodeID
     showCheckmark = true
     DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
         showCheckmark = false
     }
 } label: {
     Image(systemName: showCheckmark ? "checkmark" : "doc.on.doc")
         .resizable()
         .scaledToFit()
         .frame(width: 20, height: 20)
         .foregroundColor(showCheckmark ? .secondary : .accentColor)
+        .accessibilityLabel(showCheckmark ? "Copied" : "Copy node ID")
 }

190-194: Enhance preview with different states.

Consider adding multiple preview states to help visualize different scenarios.

#if DEBUG
#Preview("Default") {
    SettingsView(viewModel: .init())
}

#Preview("With Error") {
    let viewModel = SettingsViewModel()
    viewModel.nodeIDError = .init(title: "Error", detail: "Something went wrong")
    return SettingsView(viewModel: viewModel)
}

#Preview("Node Running") {
    let viewModel = SettingsViewModel()
    // Set necessary state for running node
    return SettingsView(viewModel: viewModel)
}
#endif
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 742203d and 4b31901.

📒 Files selected for processing (1)
  • LDKNodeMonday/View/Settings/SettingsView.swift (1 hunks)
🧰 Additional context used
📓 Learnings (1)
LDKNodeMonday/View/Settings/SettingsView.swift (1)
Learnt from: danielnordh
PR: reez/Monday#143
File: LDKNodeMonday/View/Settings/Danger/SeedView.swift:44-49
Timestamp: 2024-12-18T16:56:17.814Z
Learning: In SwiftUI for the LDKNodeMonday project, additional BIP39 validation for the seed mnemonic isn't strictly necessary because the node won't start unless the seed is valid.
🪛 SwiftLint (0.57.0)
LDKNodeMonday/View/Settings/SettingsView.swift

[Warning] 107-107: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 120-120: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 136-136: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 155-155: Prefer at least one space after slashes for comments

(comment_spacing)

🔇 Additional comments (3)
LDKNodeMonday/View/Settings/SettingsView.swift (3)

1-11: LGTM!

The imports are appropriate for the functionality required by this view.


102-152: Enhance safety measures for critical actions.

The current implementation uses simple confirmation alerts for dangerous actions. Consider implementing stronger safeguards as previously suggested.

🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 107-107: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 120-120: Prefer at least one space after slashes for comments

(comment_spacing)


[Warning] 136-136: Prefer at least one space after slashes for comments

(comment_spacing)


165-172: Add error handling for async operations.

The async operations in onAppear lack proper error handling.

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

♻️ Duplicate comments (2)
LDKNodeMonday/View/Settings/SettingsView.swift (2)

99-152: 🛠️ Refactor suggestion

Enhance safety for critical actions in the danger zone.

Consider adding stronger safeguards for critical actions by requiring explicit confirmation.

struct DeleteConfirmationView: View {
    @Binding var isPresented: Bool
    @State private var confirmText = ""
    let actionType: String
    let onConfirm: () -> Void
    
    var body: some View {
        VStack {
            Text("Type '\(actionType)' to confirm")
                .font(.headline)
            TextField("Confirmation", text: $confirmText)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            HStack {
                Button("Cancel") {
                    isPresented = false
                }
                Button("Confirm") {
                    if confirmText.uppercased() == actionType.uppercased() {
                        onConfirm()
                        isPresented = false
                    }
                }
                .disabled(confirmText.uppercased() != actionType.uppercased())
                .foregroundColor(.red)
            }
        }
        .padding()
    }
}

170-175: 🛠️ Refactor suggestion

Consider comprehensive error handling for async operations.

The onAppear block contains multiple async operations that should be properly handled for errors.

 Task {
+    do {
-        viewModel.getNodeID()
-        viewModel.getNetwork()
-        viewModel.getEsploraUrl()
-        await viewModel.getStatus()
+        try await viewModel.getNodeID()
+        try await viewModel.getNetwork()
+        try await viewModel.getEsploraUrl()
+        try await viewModel.getStatus()
+    } catch {
+        viewModel.nodeIDError = .init(
+            title: "Initialization Error",
+            detail: error.localizedDescription
+        )
+    }
 }
🧹 Nitpick comments (4)
LDKNodeMonday/View/Settings/SettingsView.swift (4)

21-21: Remove unused state variable.

The showGreeting state variable appears to be unused in the view.

-    @State private var showGreeting = true

40-46: Move URL formatting logic to ViewModel.

Consider moving the URL formatting logic to the ViewModel to maintain separation of concerns and improve reusability.

// In SettingsViewModel
+ var formattedServerURL: String {
+     esploraURL?
+         .replacingOccurrences(of: "https://", with: "")
+         .replacingOccurrences(of: "http://", with: "") ?? "No server"
+ }

// In SettingsView
- .badge(
-     viewModel.esploraURL?.replacingOccurrences(of: "https://", with: "")
-         .replacingOccurrences(
-             of: "http://",
-             with: ""
-         ) ?? "No server"
- )
+ .badge(viewModel.formattedServerURL)

67-69: Improve timer management.

Consider using a more robust approach for managing the copy feedback timer to prevent potential memory leaks.

+ @State private var feedbackTimer: Timer?

- DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
-     showCheckmark = false
- }
+ feedbackTimer?.invalidate()
+ feedbackTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { _ in
+     showCheckmark = false
+ }

Don't forget to invalidate the timer when the view disappears:

.onDisappear {
    feedbackTimer?.invalidate()
}

194-198: Enhance preview with different states.

Consider adding more preview scenarios to help during development.

 #if DEBUG
-    #Preview {
-        SettingsView(viewModel: .init())
+    #Preview("Default") {
+        SettingsView(viewModel: .init())
+    }
+    
+    #Preview("With Error") {
+        let viewModel = SettingsViewModel()
+        viewModel.nodeIDError = .init(title: "Error", detail: "Test error message")
+        return SettingsView(viewModel: viewModel)
     }
 #endif
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4b31901 and 1134ed1.

📒 Files selected for processing (1)
  • LDKNodeMonday/View/Settings/SettingsView.swift (1 hunks)
🧰 Additional context used
📓 Learnings (1)
LDKNodeMonday/View/Settings/SettingsView.swift (1)
Learnt from: danielnordh
PR: reez/Monday#143
File: LDKNodeMonday/View/Settings/Danger/SeedView.swift:44-49
Timestamp: 2024-12-18T16:56:17.814Z
Learning: In SwiftUI for the LDKNodeMonday project, additional BIP39 validation for the seed mnemonic isn't strictly necessary because the node won't start unless the seed is valid.
🪛 SwiftLint (0.57.0)
LDKNodeMonday/View/Settings/SettingsView.swift

[Warning] 159-159: Prefer at least one space after slashes for comments

(comment_spacing)

🔇 Additional comments (1)
LDKNodeMonday/View/Settings/SettingsView.swift (1)

8-10: LGTM: Imports are appropriate and well-organized.

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: 1

🧹 Nitpick comments (1)
LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (1)

19-19: Remove redundant nil initialization

The explicit nil initialization is redundant for Optional variables in Swift.

-    @State private var lastCopiedItemId: String? = nil
+    @State private var lastCopiedItemId: String?
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 19-19: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1134ed1 and 6466a98.

📒 Files selected for processing (2)
  • LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (2 hunks)
  • LDKNodeMonday/View/Settings/Peers/PeerView.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • LDKNodeMonday/View/Settings/Peers/PeerView.swift
🧰 Additional context used
🪛 SwiftLint (0.57.0)
LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift

[Warning] 19-19: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

🔇 Additional comments (3)
LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (3)

15-15: LGTM: State management for channel closure

The addition of isClosing state variable improves the handling of channel closure state.


26-69: LGTM: Well-structured list implementation

The list implementation follows SwiftUI best practices with:

  • Proper truncation for long values
  • Visual feedback for copy operations
  • Accessibility considerations with font sizing

74-84: LGTM: Improved navigation and accessibility

The changes improve the UI by:

  • Limiting dynamic type size for better layout control
  • Moving the close button to the navigation bar following iOS guidelines

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

♻️ Duplicate comments (2)
LDKNodeMonday/View/Settings/SettingsView.swift (2)

98-155: 🛠️ Refactor suggestion

Enhance safety measures for critical actions.

The current implementation uses basic confirmation alerts for critical actions. Consider implementing stronger safeguards.

struct SafetyConfirmationAlert: View {
    @Binding var isPresented: Bool
    let title: String
    let message: String
    let confirmationText: String
    @State private var userInput = ""
    let onConfirm: () -> Void
    
    var body: some View {
        VStack(spacing: 16) {
            Text(title).font(.headline)
            Text(message)
            Text("Type '\(confirmationText)' to confirm")
                .foregroundColor(.secondary)
            TextField("Confirmation", text: $userInput)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            HStack {
                Button("Cancel") {
                    isPresented = false
                }
                Button("Confirm") {
                    if userInput.uppercased() == confirmationText.uppercased() {
                        onConfirm()
                        isPresented = false
                    }
                }
                .disabled(userInput.uppercased() != confirmationText.uppercased())
                .foregroundColor(.red)
            }
        }
        .padding()
    }
}

168-175: ⚠️ Potential issue

Add error handling for initialization operations.

The onAppear block contains multiple async operations that should be wrapped in error handling.

  .onAppear {
      Task {
+         do {
              viewModel.getNodeID()
              viewModel.getNetwork()
              viewModel.getEsploraUrl()
              await viewModel.getStatus()
+         } catch {
+             viewModel.nodeIDError = .init(
+                 title: "Initialization Error",
+                 detail: error.localizedDescription
+             )
+         }
      }
  }
🧹 Nitpick comments (6)
LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (3)

19-19: Remove redundant nil initialization

The explicit nil initialization of lastCopiedItemId is redundant as Optional variables are automatically initialized to nil.

-    @State private var lastCopiedItemId: String? = nil
+    @State private var lastCopiedItemId: String?
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 19-19: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)


40-44: Improve copy feedback implementation

Consider using SwiftUI's native animation and a configuration constant for the feedback duration.

+    private let copyFeedbackDuration: TimeInterval = 2.0
     
     Button {
         UIPasteboard.general.string = property.value
-        lastCopiedItemId = property.name
-        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
+        withAnimation {
+            lastCopiedItemId = property.name
+        }
+        withAnimation(.easeInOut(duration: copyFeedbackDuration)) {
             lastCopiedItemId = nil
-        }
+        }
     }

82-82: Consider using semantic colors for destructive actions

Instead of hardcoding the color red, consider using the system's semantic color for destructive actions.

-    .foregroundColor(.red)
+    .foregroundColor(.red.opacity(0.85))  // or consider using .tint(.red) for better system integration
LDKNodeMonday/View/Settings/SettingsView.swift (3)

38-44: Consider extracting URL formatting logic.

The nested string replacements could be simplified for better maintainability.

-                        .badge(
-                            viewModel.esploraURL?.replacingOccurrences(of: "https://", with: "")
-                                .replacingOccurrences(
-                                    of: "http://",
-                                    with: ""
-                                ) ?? "No server"
-                        )
+                        .badge(viewModel.formattedServerURL ?? "No server")

// Add to SettingsViewModel:
+ var formattedServerURL: String? {
+     guard let url = esploraURL else { return nil }
+     return url.replacingOccurrences(of: "^(https?://)", with: "", options: .regularExpression)
+ }

63-68: Consider canceling previous copy timer.

The current implementation might lead to unexpected behavior if the user taps the copy button multiple times quickly.

+ @State private var copyTimer: Timer?

  Button {
      UIPasteboard.general.string = viewModel.nodeID
      showCheckmark = true
+     copyTimer?.invalidate()
-     DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
-         showCheckmark = false
-     }
+     copyTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { _ in
+         showCheckmark = false
+     }
  }

158-158: Fix comment spacing.

Add a space after the double slash for consistency with Swift style guidelines.

- //.scrollContentBackground(.hidden) // uncomment if we want white background
+ // .scrollContentBackground(.hidden) // uncomment if we want white background
🧰 Tools
🪛 SwiftLint (0.57.0)

[Warning] 158-158: Prefer at least one space after slashes for comments

(comment_spacing)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6466a98 and 6f61d67.

📒 Files selected for processing (2)
  • LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (2 hunks)
  • LDKNodeMonday/View/Settings/SettingsView.swift (1 hunks)
🧰 Additional context used
📓 Learnings (1)
LDKNodeMonday/View/Settings/SettingsView.swift (1)
Learnt from: danielnordh
PR: reez/Monday#143
File: LDKNodeMonday/View/Settings/Danger/SeedView.swift:44-49
Timestamp: 2024-12-18T16:56:17.814Z
Learning: In SwiftUI for the LDKNodeMonday project, additional BIP39 validation for the seed mnemonic isn't strictly necessary because the node won't start unless the seed is valid.
🪛 SwiftLint (0.57.0)
LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift

[Warning] 19-19: Initializing an optional variable with nil is redundant

(redundant_optional_initialization)

LDKNodeMonday/View/Settings/SettingsView.swift

[Warning] 158-158: Prefer at least one space after slashes for comments

(comment_spacing)

🔇 Additional comments (2)
LDKNodeMonday/View/Settings/Channel/ChannelDetailView.swift (1)

100-107: Previous review comment about channel closure implementation still applies

The current implementation was previously discussed and approved by the developer.

LDKNodeMonday/View/Settings/SettingsView.swift (1)

12-20: LGTM! Well-structured view properties.

The view properties follow SwiftUI best practices with proper use of property wrappers and clear naming conventions.

Copy link
Owner

@reez reez left a comment

Choose a reason for hiding this comment

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

This looks great!

Thanks for adding screenshots side by side and light+dark mode, always helps a bunch.

I like some of the details in here like the ChannelDetailsFormatted where you can use isCopyable in ChannelDetailView.

Thanks for formatting and removing some unneeded code now like getColor() etc.

Good stuff!

@reez reez merged commit b2db00f into reez:main Dec 20, 2024
1 check passed
@danielnordh danielnordh deleted the ux/settings branch December 20, 2024 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants