feat(auth): 콘텐츠 설정에서 본인인증 종료를 지원한다
This commit is contained in:
@@ -21,9 +21,12 @@ struct AuthContentSettingsSheet: View {
|
||||
@Binding var isAdultContentVisible: Bool
|
||||
@Binding var contentType: ContentType
|
||||
let onConfirm: () -> Void
|
||||
let onClose: () -> Void
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
header
|
||||
|
||||
ViewThatFits(in: .vertical) {
|
||||
settingsContent
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
@@ -49,17 +52,42 @@ struct AuthContentSettingsSheet: View {
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
.background(Color.gray900)
|
||||
.accessibilityAction(.escape, onClose)
|
||||
}
|
||||
|
||||
private var settingsContent: some View {
|
||||
VStack(spacing: 0) {
|
||||
private var header: some View {
|
||||
HStack(spacing: 0) {
|
||||
Color.clear
|
||||
.frame(width: AuthContentSettingsLayout.touchHeight, height: AuthContentSettingsLayout.touchHeight)
|
||||
.accessibilityHidden(true)
|
||||
|
||||
Text(I18n.Settings.contentViewSettings)
|
||||
.appFont(size: SodaTypography.heading4.size, weight: .medium)
|
||||
.foregroundColor(.white)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(maxWidth: .infinity, minHeight: AuthContentSettingsLayout.headerHeight)
|
||||
.frame(maxWidth: .infinity)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.accessibilityAddTraits(.isHeader)
|
||||
|
||||
Button(action: onClose) {
|
||||
Image(systemName: "xmark")
|
||||
.font(.system(size: SodaTypography.body2.size, weight: .medium))
|
||||
.foregroundColor(.gray400)
|
||||
.frame(width: AuthContentSettingsLayout.touchHeight, height: AuthContentSettingsLayout.touchHeight)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.borderless)
|
||||
.accessibilityLabel(I18n.Settings.Content.authExitTitle)
|
||||
.accessibilityIdentifier("authContentSettings.close")
|
||||
}
|
||||
.frame(minHeight: AuthContentSettingsLayout.headerHeight)
|
||||
.padding(.top, AuthContentSettingsLayout.topInset)
|
||||
.padding(.horizontal, SodaSpacing.s14)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
|
||||
private var settingsContent: some View {
|
||||
VStack(spacing: 0) {
|
||||
sensitiveContentRow
|
||||
.padding(.top, SodaSpacing.s8)
|
||||
.padding(.bottom, isAdultContentVisible ? SodaSpacing.s14 : SodaSpacing.s8)
|
||||
@@ -83,7 +111,6 @@ struct AuthContentSettingsSheet: View {
|
||||
.padding(.top, isAdultContentVisible ? 0 : SodaSpacing.s8)
|
||||
.padding(.bottom, SodaSpacing.s20)
|
||||
}
|
||||
.padding(.top, AuthContentSettingsLayout.topInset)
|
||||
.padding(.horizontal, SodaSpacing.s14)
|
||||
}
|
||||
|
||||
@@ -193,9 +220,12 @@ private struct AuthContentSettingsToggleStyle: ToggleStyle {
|
||||
|
||||
private struct AuthContentSettingsModifier: ViewModifier {
|
||||
@ObservedObject var viewModel: MyPageViewModel
|
||||
let onCancel: () -> Void
|
||||
@Environment(\.accessibilityReduceMotion) private var reduceMotion
|
||||
@State private var isHostPresented = false
|
||||
@State private var panelProgress: CGFloat = 0
|
||||
@State private var isExitDialogPresented = false
|
||||
@AccessibilityFocusState private var isExitDialogFocused: Bool
|
||||
|
||||
private var callerErrorIsPresented: Binding<Bool> {
|
||||
Binding(
|
||||
@@ -214,6 +244,7 @@ private struct AuthContentSettingsModifier: ViewModifier {
|
||||
}
|
||||
.sodaToast(isPresented: callerErrorIsPresented, message: viewModel.errorMessage, autohideIn: 2)
|
||||
.fullScreenCover(isPresented: $isHostPresented, onDismiss: {
|
||||
dismissExitDialog()
|
||||
panelProgress = 0
|
||||
viewModel.submitPendingAuthVerification()
|
||||
}) {
|
||||
@@ -225,7 +256,8 @@ private struct AuthContentSettingsModifier: ViewModifier {
|
||||
AuthContentSettingsSheet(
|
||||
isAdultContentVisible: $viewModel.authIsAdultContentVisible,
|
||||
contentType: $viewModel.authContentType,
|
||||
onConfirm: viewModel.confirmAuthContentSettings
|
||||
onConfirm: viewModel.confirmAuthContentSettings,
|
||||
onClose: showExitDialog
|
||||
)
|
||||
.padding(.leading, proxy.safeAreaInsets.leading)
|
||||
.padding(.trailing, proxy.safeAreaInsets.trailing)
|
||||
@@ -241,6 +273,8 @@ private struct AuthContentSettingsModifier: ViewModifier {
|
||||
}
|
||||
}
|
||||
.sodaToast(isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 2)
|
||||
.disabled(isExitDialogPresented)
|
||||
.accessibilityHidden(isExitDialogPresented)
|
||||
.modifier(AuthContentSettingsPanelMotion(
|
||||
progress: panelProgress,
|
||||
reduceMotion: reduceMotion,
|
||||
@@ -249,6 +283,11 @@ private struct AuthContentSettingsModifier: ViewModifier {
|
||||
}
|
||||
.ignoresSafeArea(.container, edges: [.horizontal, .bottom])
|
||||
}
|
||||
.overlay {
|
||||
if isExitDialogPresented {
|
||||
exitDialog
|
||||
}
|
||||
}
|
||||
.interactiveDismissDisabled(true)
|
||||
.presentationBackground(.clear)
|
||||
.onAppear {
|
||||
@@ -256,6 +295,7 @@ private struct AuthContentSettingsModifier: ViewModifier {
|
||||
updatePanel()
|
||||
}
|
||||
}
|
||||
.onDisappear(perform: dismissExitDialog)
|
||||
}
|
||||
.onAppear {
|
||||
if viewModel.isShowAuthContentSettings {
|
||||
@@ -263,6 +303,9 @@ private struct AuthContentSettingsModifier: ViewModifier {
|
||||
}
|
||||
}
|
||||
.onChange(of: viewModel.isShowAuthContentSettings) { isPresented in
|
||||
if !isPresented {
|
||||
dismissExitDialog()
|
||||
}
|
||||
if isPresented && !isHostPresented {
|
||||
setHostPresented(true)
|
||||
} else if isHostPresented {
|
||||
@@ -276,6 +319,45 @@ private struct AuthContentSettingsModifier: ViewModifier {
|
||||
}
|
||||
}
|
||||
|
||||
private var exitDialog: some View {
|
||||
SodaV2ActionModal(
|
||||
title: I18n.Settings.Content.authExitTitle,
|
||||
message: I18n.Settings.Content.authExitMessage,
|
||||
button1: SodaV2ActionModalButton(
|
||||
label: I18n.Settings.Content.authExitConfirm,
|
||||
action: confirmExit
|
||||
),
|
||||
button2: SodaV2ActionModalButton(
|
||||
label: I18n.Settings.Content.authExitCancel,
|
||||
action: dismissExitDialog
|
||||
),
|
||||
onDimmedTap: dismissExitDialog
|
||||
)
|
||||
.accessibilityElement(children: .contain)
|
||||
.accessibilityFocused($isExitDialogFocused)
|
||||
.accessibilityAction(.escape, dismissExitDialog)
|
||||
.onAppear {
|
||||
isExitDialogFocused = true
|
||||
}
|
||||
}
|
||||
|
||||
private func showExitDialog() {
|
||||
guard isHostPresented, viewModel.isShowAuthContentSettings, !viewModel.isSubmittingAuth else { return }
|
||||
isExitDialogPresented = true
|
||||
}
|
||||
|
||||
private func dismissExitDialog() {
|
||||
isExitDialogPresented = false
|
||||
isExitDialogFocused = false
|
||||
}
|
||||
|
||||
private func confirmExit() {
|
||||
guard isExitDialogPresented, isHostPresented, viewModel.isShowAuthContentSettings, !viewModel.isSubmittingAuth else { return }
|
||||
dismissExitDialog()
|
||||
viewModel.cancelAuthContentSettings()
|
||||
onCancel()
|
||||
}
|
||||
|
||||
private func setHostPresented(_ isPresented: Bool) {
|
||||
var transaction = Transaction()
|
||||
transaction.disablesAnimations = true
|
||||
@@ -323,19 +405,19 @@ private struct AuthContentSettingsPanelMotion: GeometryEffect {
|
||||
}
|
||||
|
||||
extension View {
|
||||
func authContentSettings(viewModel: MyPageViewModel) -> some View {
|
||||
modifier(AuthContentSettingsModifier(viewModel: viewModel))
|
||||
func authContentSettings(viewModel: MyPageViewModel, onCancel: @escaping () -> Void = {}) -> some View {
|
||||
modifier(AuthContentSettingsModifier(viewModel: viewModel, onCancel: onCancel))
|
||||
}
|
||||
}
|
||||
|
||||
struct AuthContentSettingsSheet_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
AuthContentSettingsSheet(isAdultContentVisible: .constant(true), contentType: .constant(.ALL), onConfirm: {})
|
||||
AuthContentSettingsSheet(isAdultContentVisible: .constant(true), contentType: .constant(.ALL), onConfirm: {}, onClose: {})
|
||||
.frame(width: 402)
|
||||
.previewDisplayName("ON / ALL")
|
||||
|
||||
AuthContentSettingsSheet(isAdultContentVisible: .constant(false), contentType: .constant(.ALL), onConfirm: {})
|
||||
AuthContentSettingsSheet(isAdultContentVisible: .constant(false), contentType: .constant(.ALL), onConfirm: {}, onClose: {})
|
||||
.frame(width: 402)
|
||||
.previewDisplayName("OFF / ALL")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user