Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion RIADigiDoc/Domain/Model/Error/NFC/DecryptError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ extension DecryptError: LocalizedError {
case .containerFileInvalid:
return "Container file is invalid"
case .recipientsEmpty:
return "No recipients found in container"
return "Person or company does not own a valid certificate"
case .cancelled:
return "Operation cancelled by user"
case .unknown(let error):
Expand Down
2 changes: 1 addition & 1 deletion RIADigiDoc/Domain/NFC/OperationDecrypt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public class OperationDecrypt: NFCOperationBase, OperationDecryptProtocol {
OperationDecrypt.logger().error("NFC: \(error.localizedDescription)")
operationError = error
session.invalidate(errorMessage: strings?.technicalErrorMessage ??
"No recipients found")
"Person or company does not own a valid certificate")
return
}

Expand Down
36 changes: 18 additions & 18 deletions RIADigiDoc/Supporting files/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -5197,24 +5197,6 @@
}
}
},
"No recipients found" : {
"comment" : "Text for when no recipients are found",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "No recipients found"
}
},
"et" : {
"stringUnit" : {
"state" : "translated",
"value" : "Adressaati ei leitud"
}
}
}
},
"Not a mobile-id client" : {
"comment" : "Mobile-ID error when user is not found or not active",
"extractionState" : "manual",
Expand Down Expand Up @@ -5394,6 +5376,24 @@
}
}
},
"Person or company does not own a valid certificate" : {
"comment" : "LDAP search message when no results found",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Person or company does not own a valid certificate. It is necessary to have a valid certificate for encryption"
}
},
"et" : {
"stringUnit" : {
"state" : "translated",
"value" : "Isikul või asutusel puudub kehtiv sertifikaat. Krüpteerimiseks on vaja kehtivat sertifikaati"
}
}
}
},
"Personal code" : {
"comment" : "Used in Mobile-ID and Smart-ID textfield views, My eID public data",
"extractionState" : "manual",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ struct EncryptRecipientView: View {

@State private var encryptionButtonEnabled = true

@State private var showNoRecipientsFoundMessage = false

@State private var selectedRecipient: Addressee?
@State private var showRemoveRecipientModal = false

Expand Down Expand Up @@ -65,6 +67,57 @@ struct EncryptRecipientView: View {
var encryptLabel: String {
languageSettings.localized("Encrypt")
}

var noSearchResultsMessage: String {
languageSettings.localized("Person or company does not own a valid certificate")
}

private var addedRecipientsSection: some View {
VStack(alignment: .leading, spacing: Dimensions.Padding.ZeroPadding) {
if noSearchResults {
Text(verbatim: languageSettings.localized("Added recipients"))
} else {
Text(verbatim: languageSettings.localized("Recently added"))
}

Spacer().frame(height: Dimensions.Padding.MSPadding)

if #available(iOS 26.0, *) {
ForEach(addedRecipients.enumerated(), id: \.offset) { index, item in
addedRecipientRow(index: index, item: item)
}
} else {
ForEach(Array(addedRecipients.enumerated()), id: \.offset) { index, item in
addedRecipientRow(index: index, item: item)
}
}
}
.padding(.horizontal, Dimensions.Padding.SPadding)
.listStyle(.plain)
.scrollDisabled(true)
.scrollContentBackground(.hidden)
.listRowSpacing(0)
.listSectionSpacing(.compact)
}

private var filteredRecipientsSection: some View {
VStack {
if #available(iOS 26.0, *) {
ForEach(filteredRecipients.enumerated(), id: \.offset) { index, item in
recipientRow(index: index, item: item)
}
} else {
ForEach(Array(filteredRecipients.enumerated()), id: \.offset) { index, item in
recipientRow(index: index, item: item)
}
}
}
.listStyle(.plain)
.scrollDisabled(true)
.scrollContentBackground(.hidden)
.listRowSpacing(0)
.listSectionSpacing(.compact)
}

var body: some View {
TopBarContainer(
Expand Down Expand Up @@ -114,6 +167,11 @@ struct EncryptRecipientView: View {

Task {
await viewModel.loadRecipients()

if noRecipients {
showNoRecipientsFoundMessage = true
}

isSearchFocused = true
}
}
Expand Down Expand Up @@ -160,64 +218,16 @@ struct EncryptRecipientView: View {
.listStyle(.plain)
.scrollDisabled(true)
.scrollContentBackground(.hidden)
} else if noRecipients {
ContentUnavailableView {
Text(verbatim: languageSettings.localized("No recipients found"))
.font(typography.bodyLarge)
.foregroundStyle(theme.onSurfaceVariant)
}
.listRowSeparator(.hidden)
} else if showNoRecipientsFoundMessage {
emptyStateView(languageSettings.localized("Person or company does not own a valid certificate"))
} else {
VStack {
if #available(iOS 26.0, *) {
ForEach(filteredRecipients.enumerated(), id: \.offset
) { index, item in
recipientRow(index: index, item: item)
}
} else {
ForEach(Array(filteredRecipients.enumerated()), id: \.offset
) { index, item in
recipientRow(index: index, item: item)
}
}
}
.listStyle(.plain)
.scrollDisabled(true)
.scrollContentBackground(.hidden)
.listRowSpacing(0)
.listSectionSpacing(.compact)
filteredRecipientsSection
}

Spacer().frame(height: Dimensions.Padding.MSPadding)

if addedRecipients.count > 0 {
VStack(alignment: .leading, spacing: Dimensions.Padding.ZeroPadding) {
if noSearchResults {
Text(verbatim: languageSettings.localized("Added recipients"))
} else {
Text(verbatim: languageSettings.localized("Recently added"))
}

Spacer().frame(height: Dimensions.Padding.MSPadding)

if #available(iOS 26.0, *) {
ForEach(addedRecipients.enumerated(), id: \.offset
) { index, item in
addedRecipientRow(index: index, item: item)
}
} else {
ForEach(Array(addedRecipients.enumerated()), id: \.offset
) { index, item in
addedRecipientRow(index: index, item: item)
}
}
}
.padding(.horizontal, Dimensions.Padding.SPadding)
.listStyle(.plain)
.scrollDisabled(true)
.scrollContentBackground(.hidden)
.listRowSpacing(0)
.listSectionSpacing(.compact)
addedRecipientsSection
}
}
}
Expand Down Expand Up @@ -297,6 +307,9 @@ struct EncryptRecipientView: View {
addedRecipients = await viewModel.filteredAddedRecipients()
}
}
.onChange(of: viewModel.searchText) { _, _ in
showNoRecipientsFoundMessage = false
}
.onChange(of: viewModel.errorMessage) { _, error in
guard !error.isEmpty else { return }
Toast.show(languageSettings.localized(error))
Expand All @@ -306,7 +319,6 @@ struct EncryptRecipientView: View {
)
}

@ViewBuilder
private func recipientRow(index: Int, item: Addressee) -> some View {
RecipientsView(
recipient: item,
Expand All @@ -329,7 +341,6 @@ struct EncryptRecipientView: View {
.background(theme.surface)
}

@ViewBuilder
private func addedRecipientRow(index: Int, item: Addressee) -> some View {
RecipientsView(
recipient: item,
Expand All @@ -354,6 +365,15 @@ struct EncryptRecipientView: View {
.buttonStyle(.plain)
.background(theme.surface)
}

private func emptyStateView(_ text: String) -> some View {
ContentUnavailableView {
Text(verbatim: text)
.font(typography.bodyLarge)
.foregroundStyle(theme.onSurfaceVariant)
}
.listRowSeparator(.hidden)
}
}

#Preview {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ struct NFCInputView: View {
Text(verbatim: canNumberLocationLabel)
.font(typography.labelMedium)
.foregroundStyle(theme.onSecondaryContainer)
.padding(.vertical, Dimensions.Padding.XXSPadding)
.padding(.bottom, Dimensions.Padding.MPadding)
}
}
.padding(.vertical, Dimensions.Padding.ZeroPadding)
Expand Down
5 changes: 5 additions & 0 deletions RIADigiDoc/UI/Component/Toast/ToastQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ actor ToastQueue {

private var queue: [ToastItem] = []
private var isPresenting = false
private var currentMessage: String? = nil

func enqueue(message: String, duration: TimeInterval, type: ToastType) {
// Avoid consecutive duplicate messages
if message == currentMessage || message == queue.last?.message { return }
queue.append(ToastItem(message: message, duration: duration, type: type))
processQueueIfNeeded()
}
Expand All @@ -34,6 +37,7 @@ actor ToastQueue {
guard !isPresenting, let next = queue.first else { return }

isPresenting = true
currentMessage = next.message
queue.removeFirst()

Task {
Expand All @@ -44,6 +48,7 @@ actor ToastQueue {

private func toastDidFinish() {
isPresenting = false
currentMessage = nil
processQueueIfNeeded()
}
}
Loading