add delete solo session
This commit is contained in:
parent
020aa8de5d
commit
854561b5f7
@ -345,6 +345,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Вы выйдете из выбранной сессии." : {
|
||||||
|
"comment" : "Описание подтверждения завершения конкретной сессии"
|
||||||
|
},
|
||||||
"Вы выйдете со всех устройств, кроме текущего." : {
|
"Вы выйдете со всех устройств, кроме текущего." : {
|
||||||
"comment" : "Описание подтверждения завершения сессий"
|
"comment" : "Описание подтверждения завершения сессий"
|
||||||
},
|
},
|
||||||
@ -458,7 +461,7 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
"Завершить" : {
|
"Завершить" : {
|
||||||
"comment" : "Подтверждение завершения других сессий"
|
"comment" : "Кнопка завершения конкретной сессии\nПодтверждение завершения других сессий\nПодтверждение завершения конкретной сессии"
|
||||||
},
|
},
|
||||||
"Завершить другие сессии" : {
|
"Завершить другие сессии" : {
|
||||||
"comment" : "Кнопка завершения других сессий"
|
"comment" : "Кнопка завершения других сессий"
|
||||||
@ -466,6 +469,9 @@
|
|||||||
"Завершить сессии на других устройствах?" : {
|
"Завершить сессии на других устройствах?" : {
|
||||||
"comment" : "Заголовок подтверждения завершения сессий"
|
"comment" : "Заголовок подтверждения завершения сессий"
|
||||||
},
|
},
|
||||||
|
"Завершить эту сессию?" : {
|
||||||
|
"comment" : "Заголовок подтверждения завершения отдельной сессии"
|
||||||
|
},
|
||||||
"Заглушка: Push-уведомления" : {
|
"Заглушка: Push-уведомления" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|||||||
@ -7,6 +7,8 @@ struct ActiveSessionsView: View {
|
|||||||
@State private var revokeInProgress = false
|
@State private var revokeInProgress = false
|
||||||
@State private var activeAlert: SessionsAlert?
|
@State private var activeAlert: SessionsAlert?
|
||||||
@State private var showRevokeConfirmation = false
|
@State private var showRevokeConfirmation = false
|
||||||
|
@State private var sessionPendingRevoke: SessionViewData?
|
||||||
|
@State private var revokingSessionIds: Set<UUID> = []
|
||||||
|
|
||||||
private let sessionsService = SessionsService()
|
private let sessionsService = SessionsService()
|
||||||
private var currentSession: SessionViewData? {
|
private var currentSession: SessionViewData? {
|
||||||
@ -60,7 +62,18 @@ struct ActiveSessionsView: View {
|
|||||||
if !otherSessions.isEmpty {
|
if !otherSessions.isEmpty {
|
||||||
Section(header: Text(String(format: NSLocalizedString("Другие устройства (%d)", comment: "Заголовок секции других устройств с количеством"), otherSessions.count))) {
|
Section(header: Text(String(format: NSLocalizedString("Другие устройства (%d)", comment: "Заголовок секции других устройств с количеством"), otherSessions.count))) {
|
||||||
ForEach(otherSessions) { session in
|
ForEach(otherSessions) { session in
|
||||||
sessionRow(for: session)
|
let isRevoking = isRevoking(session: session)
|
||||||
|
|
||||||
|
sessionRow(for: session, isRevoking: isRevoking)
|
||||||
|
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
sessionPendingRevoke = session
|
||||||
|
} label: {
|
||||||
|
Label(NSLocalizedString("Завершить", comment: "Кнопка завершения конкретной сессии"), systemImage: "trash")
|
||||||
|
}
|
||||||
|
.disabled(isRevoking)
|
||||||
|
}
|
||||||
|
.disabled(isRevoking)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,6 +87,24 @@ struct ActiveSessionsView: View {
|
|||||||
.refreshable {
|
.refreshable {
|
||||||
await loadSessions(force: true)
|
await loadSessions(force: true)
|
||||||
}
|
}
|
||||||
|
.confirmationDialog(
|
||||||
|
NSLocalizedString("Завершить эту сессию?", comment: "Заголовок подтверждения завершения отдельной сессии"),
|
||||||
|
isPresented: Binding(
|
||||||
|
get: { sessionPendingRevoke != nil },
|
||||||
|
set: { if !$0 { sessionPendingRevoke = nil } }
|
||||||
|
),
|
||||||
|
presenting: sessionPendingRevoke
|
||||||
|
) { session in
|
||||||
|
Button(NSLocalizedString("Завершить", comment: "Подтверждение завершения конкретной сессии"), role: .destructive) {
|
||||||
|
sessionPendingRevoke = nil
|
||||||
|
Task { await revoke(session: session) }
|
||||||
|
}
|
||||||
|
Button(NSLocalizedString("Отмена", comment: "Общий текст кнопки отмены"), role: .cancel) {
|
||||||
|
sessionPendingRevoke = nil
|
||||||
|
}
|
||||||
|
} message: { _ in
|
||||||
|
Text(NSLocalizedString("Вы выйдете из выбранной сессии.", comment: "Описание подтверждения завершения конкретной сессии"))
|
||||||
|
}
|
||||||
.alert(item: $activeAlert) { alert in
|
.alert(item: $activeAlert) { alert in
|
||||||
Alert(
|
Alert(
|
||||||
title: Text(alert.title),
|
title: Text(alert.title),
|
||||||
@ -136,7 +167,7 @@ struct ActiveSessionsView: View {
|
|||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func sessionRow(for session: SessionViewData) -> some View {
|
private func sessionRow(for session: SessionViewData, isRevoking: Bool = false) -> some View {
|
||||||
VStack(alignment: .leading, spacing: 10) {
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
HStack(alignment: .top) {
|
HStack(alignment: .top) {
|
||||||
VStack(alignment: .leading, spacing: 6) {
|
VStack(alignment: .leading, spacing: 6) {
|
||||||
@ -157,6 +188,9 @@ struct ActiveSessionsView: View {
|
|||||||
.background(Color.accentColor.opacity(0.15))
|
.background(Color.accentColor.opacity(0.15))
|
||||||
.foregroundColor(.accentColor)
|
.foregroundColor(.accentColor)
|
||||||
.clipShape(Capsule())
|
.clipShape(Capsule())
|
||||||
|
} else if isRevoking {
|
||||||
|
ProgressView()
|
||||||
|
.progressViewStyle(.circular)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,6 +259,34 @@ struct ActiveSessionsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
private func revoke(session: SessionViewData) async {
|
||||||
|
guard !session.isCurrent, !isRevoking(session: session) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
revokingSessionIds.insert(session.id)
|
||||||
|
defer { revokingSessionIds.remove(session.id) }
|
||||||
|
|
||||||
|
do {
|
||||||
|
let message = try await sessionsService.revoke(sessionId: session.id)
|
||||||
|
sessions.removeAll { $0.id == session.id }
|
||||||
|
activeAlert = SessionsAlert(
|
||||||
|
title: NSLocalizedString("Готово", comment: "Заголовок успешного уведомления"),
|
||||||
|
message: message
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
activeAlert = SessionsAlert(
|
||||||
|
title: NSLocalizedString("Ошибка", comment: "Заголовок сообщения об ошибке"),
|
||||||
|
message: error.localizedDescription
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func isRevoking(session: SessionViewData) -> Bool {
|
||||||
|
revokingSessionIds.contains(session.id)
|
||||||
|
}
|
||||||
|
|
||||||
private var revokeOtherSessionsButton: some View {
|
private var revokeOtherSessionsButton: some View {
|
||||||
let primaryColor: Color = revokeInProgress ? .secondary : .red
|
let primaryColor: Color = revokeInProgress ? .secondary : .red
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user