<commit_before>//
//  ViewError.swift
//  ZamzamUI
//
//  Created by <NAME> on 2019-12-17.
//  Copyright © 2020 Zamzam Inc. All rights reserved.
//

import Foundation.NSUUID
import SwiftUI
import ZamzamCore

/// Model container for global view errors.
public struct ViewError: Error, Identifiable, Equatable {
    public let id = UUID()
    public let title: String
    public let message: String?
    public let action: Action?

    public init(
        title: String,
        message: String? = nil,
        action: Action? = nil
    ) {
        self.title = title
        self.message = message
        self.action = action
    }

    public init(
        from error: Error,
        message: String? = nil,
        action: Action? = nil
    ) {
        self.init(
            title: error.localizedDescription,
            message: message,
            action: action
        )
    }
}

// MARK: - Types

public extension ViewError {
    struct Action: Equatable {
        public let title: String
        public let completion: () -> Void

        public init(_ title: String, completion: @escaping () -> Void) {
            self.title = title
            self.completion = completion
        }

        public static func == (lhs: Self, rhs: Self) -> Bool {
            lhs.title == rhs.title
        }
    }
}

// MARK: - Conversions

public extension Alert {
    /// Creates an alert from the view error.
    init(from error: ViewError) {
        let titleText: Text = Text(error.title)

        let messageText: Text? = {
            guard let message = error.message else { return nil }
            return Text(message)
        }()

        guard let action = error.action else {
            self.init(title: titleText, message: messageText)
            return
        }

        let primaryButton: Alert.Button = .default(
            Text(action.title),
            action: action.completion
        )

        self.init(
            title: titleText,
            message: messageText,
            primaryButton: primaryButton,
            secondaryButton: .cancel()
        )
    }
}

private struct AlertModifier: ViewModifier {
    @Binding var error: ViewError?

    func body(content: Content) -> some View {
        content.alert(item: $error, content: Alert.init)
    }
}

public extension View {
    func alert(error: Binding<ViewError?>) -> some View {
        modifier(AlertModifier(error: error))
    }
}<commit_msg>Expose view error secondary action<commit_after>//
//  ViewError.swift
//  ZamzamUI
//
//  Created by <NAME> on 2019-12-17.
//  Copyright © 2020 Zamzam Inc. All rights reserved.
//

import Foundation.NSUUID
import SwiftUI
import ZamzamCore

/// Model container for global view errors.
public struct ViewError: Error, Equatable, Identifiable {
    public let id = UUID()
    public let title: String
    public let message: String?
    public let action: Action?
    public let secondaryAction: Action?

    public init(
        title: String,
        message: String? = nil,
        action: Action? = nil,
        secondaryAction: Action? = nil
    ) {
        self.title = title
        self.message = message
        self.action = action
        self.secondaryAction = secondaryAction
    }

    public init(
        from error: Error,
        message: String? = nil,
        action: Action? = nil,
        secondaryAction: Action? = nil
    ) {
        self.init(
            title: error.localizedDescription,
            message: message,
            action: action,
            secondaryAction: secondaryAction
        )
    }
}

// MARK: - Types

public extension ViewError {
    struct Action: Equatable {
        public let title: String
        public let completion: () -> Void

        public init(_ title: String, completion: @escaping () -> Void) {
            self.title = title
            self.completion = completion
        }

        public static func == (lhs: Self, rhs: Self) -> Bool {
            lhs.title == rhs.title
        }
    }
}

// MARK: - Conversions

public extension Alert {
    /// Creates an alert from the view error.
    init(from error: ViewError) {
        let titleText: Text = Text(error.title)

        let messageText: Text? = {
            guard let message = error.message else { return nil }
            return Text(message)
        }()

        guard let action = error.action else {
            self.init(title: titleText, message: messageText)
            return
        }

        let primaryButton: Alert.Button = .default(
            Text(action.title),
            action: action.completion
        )

        let secondaryButton: Alert.Button = {
            guard let action = error.secondaryAction else {
                return .cancel()
            }

            return .cancel(
                Text(action.title),
                action: action.completion
            )
        }()

        self.init(
            title: titleText,
            message: messageText,
            primaryButton: primaryButton,
            secondaryButton: secondaryButton
        )
    }
}

private struct AlertModifier: ViewModifier {
    @Binding var error: ViewError?

    func body(content: Content) -> some View {
        content.alert(item: $error, content: Alert.init)
    }
}

public extension View {
    func alert(error: Binding<ViewError?>) -> some View {
        modifier(AlertModifier(error: error))
    }
}
{'fraction_non_alphanumeric': 0.09402183971867481, 'fraction_numerical': 0.004441976679622432, 'mean_word_length': 1.8234064785788924, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3383778', 'n_tokens_mistral': 1500, 'n_tokens_neox': 1425, 'n_words': 443}