Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,49 @@ struct LoginButton: View {
@State private var logo: Image?
@State private var text = ""
@ScaledMetric(relativeTo: .body) private var height = CGFloat(22)
private let showsProgressView: Bool
private let action: () -> Void

init(
logo: Image? = nil,
text: String = "",
showsProgressView: Bool = false,
action: @escaping () -> Void = {}
) {
self._logo = State(initialValue: logo)
self._text = State(initialValue: text)
self.showsProgressView = showsProgressView
self.action = action
}

var body: some View {
Button {
action()
} label: {
Text(text)
.foregroundStyle(Color.primary)
.font(.system(.body))
.contentShape(.capsule)
.frame(width: 300, height: height + 16)
.overlay {
ZStack(alignment: .leading) {
Capsule()
.stroke(Color.gray, lineWidth: 1)
if let logo = logo {
logo
.resizable()
.scaledToFit()
.frame(width: height, height: height)
.padding(.leading)
}
ZStack {
Text(text)
.opacity(showsProgressView ? 0 : 1)
if showsProgressView {
ProgressView()
}
}
.foregroundStyle(Color.primary)
.font(.system(.body))
.contentShape(.capsule)
.frame(width: 300, height: height + 16)
.overlay {
ZStack(alignment: .leading) {
Capsule()
.stroke(Color.gray, lineWidth: 1)
if let logo, !showsProgressView {
logo
.resizable()
.scaledToFit()
.frame(width: height, height: height)
.padding(.leading)
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,19 @@ struct TodoEditorView: View {
Image(systemName: "info.circle")
}
}
ToolbarTrailingButton {
submit()
if store.isLoading {
if #available(iOS 26.0, *) {
ToolbarSpacer(.fixed, placement: .topBarTrailing)
}
ToolbarItem(placement: .topBarTrailing) {
ProgressView()
}
} else {
ToolbarTrailingButton {
submit()
}
.disabled(!store.isReadyToSubmit)
}
.disabled(!store.isReadyToSubmit || store.isLoading)
}
.alert($store.scope(state: \.alert, action: \.alert))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ extension HomeFeature {
trackAnalyticsEventUseCase.execute(.webPageCreate)
let pages = try await fetchWebPagesUseCase.execute("")
await send(.store(.updateWebPages(pages.map(WebPageItem.init(from:)))))
await send(.store(.setSheet(nil)))
} catch {
await send(.store(.setAlert(isPresented: true, type: .error)))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,6 @@ private extension HomeFeature {
Self.setAlert(&state, isPresented: true, type: .invalidURL)
return .none
}
state.sheet = nil
Self.setAlert(&state, isPresented: false, type: nil)
return addWebPageEffect(normalizedURL)
case .deleteWebPage(let page):
Expand Down
20 changes: 12 additions & 8 deletions Application/DevLogPresentation/Sources/Home/Home/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ struct HomeView: View {
.alert($store.scope(state: \.alert, action: \.alert))
.sheet(item: $store.scope(state: \.sheet, action: \.sheet), content: sheetContent)
.fullScreenCover(item: $store.scope(state: \.fullScreenCover, action: \.fullScreenCover), content: coverContent)
.overlay {
if store.isAppending {
LoadingView()
}
}
}

private var todoSection: some View {
Expand Down Expand Up @@ -234,9 +229,18 @@ struct HomeView: View {
.navigationTitle(Text(String(localized: "home_webpage_input_title")))
.navigationBarTitleDisplayMode(.inline) // 설정 안하면 섹션 위에 내비게이션 large 만큼 영역 먹음
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button(String(localized: "home_add")) {
store.send(.view(.addWebPage))
if store.isAppending {
if #available(iOS 26.0, *) {
ToolbarSpacer(.fixed, placement: .topBarTrailing)
}
ToolbarItem(placement: .topBarTrailing) {
ProgressView()
}
} else {
ToolbarItem(placement: .topBarTrailing) {
Button(String(localized: "home_add")) {
store.send(.view(.addWebPage))
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct LoginFeature {
@ObservableState
struct State: Equatable {
@Presents var alert: AlertState<Never>?
var activeSignInProvider: AuthProvider?
var loading = LoadingFeature.State()

var isLoading: Bool {
Expand Down Expand Up @@ -44,11 +45,15 @@ struct LoginFeature {
case .alert:
break
case .tapSignInButton(let provider):
guard !state.isLoading else { return .none }
state.activeSignInProvider = provider
return signInEffect(provider)
case .signInFailed(let alertType):
state.alert = Self.alertState(for: alertType)
case .loading:
break
if !state.isLoading {
state.activeSignInProvider = nil
}
}
return .none
}
Expand Down
77 changes: 47 additions & 30 deletions Application/DevLogPresentation/Sources/Login/LoginView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,38 +25,55 @@ struct LoginView: View {
}

var body: some View {
ZStack {
VStack {
Spacer()
Image("Primary")
.resizable()
.scaledToFit()
.frame(width: sceneWidth / 5)
Spacer()
VStack(spacing: 20) {
LoginButton(logo: Image("Google"), text: String(localized: "login_google_sign_in")) {
store.send(.tapSignInButton(.google))
}

LoginButton(logo: Image("Github"), text: String(localized: "login_github_sign_in")) {
store.send(.tapSignInButton(.github))
}

LoginButton(logo: Image("Apple"), text: String(localized: "login_apple_sign_in")) {
store.send(.tapSignInButton(.apple))
}
}
.padding(.bottom, 30)
Text(String(localized: "login_terms_notice"))
.font(.caption2)
.foregroundStyle(Color.gray)
.multilineTextAlignment(.center)
.padding(.vertical)
}
if store.isLoading {
LoadingView()
VStack {
Spacer()
Image("Primary")
.resizable()
.scaledToFit()
.frame(width: sceneWidth / 5)
Spacer()
VStack(spacing: 20) {
signInButton(
provider: .google,
logo: Image("Google"),
text: String(localized: "login_google_sign_in")
)

signInButton(
provider: .github,
logo: Image("Github"),
text: String(localized: "login_github_sign_in")
)

signInButton(
provider: .apple,
logo: Image("Apple"),
text: String(localized: "login_apple_sign_in")
)
}
.padding(.bottom, 30)
Text(String(localized: "login_terms_notice"))
.font(.caption2)
.foregroundStyle(Color.gray)
.multilineTextAlignment(.center)
.padding(.vertical)
}
.alert($store.scope(state: \.alert, action: \.alert))
}

private func signInButton(
provider: AuthProvider,
logo: Image,
text: String
) -> some View {
LoginButton(
logo: logo,
text: text,
showsProgressView: store.activeSignInProvider == provider
) {
store.send(.tapSignInButton(provider))
}
.disabled(store.isLoading)
.opacity(store.isLoading ? 0.5 : 1)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct AccountFeature {
var currentProvider: AuthProvider?
var connectedProviders: [AuthProvider] = []
var disconnectedProviders: [AuthProvider] = []
var activeLoadingProvider: AuthProvider?
var loading = LoadingFeature.State()

var isLoading: Bool {
Expand Down Expand Up @@ -56,8 +57,12 @@ struct AccountFeature {
case .onAppear:
return fetchProvidersEffect()
case .linkWithProvider(let provider):
guard !state.isLoading else { return .none }
state.activeLoadingProvider = provider
return linkProviderEffect(provider)
case .unlinkFromProvider(let provider):
guard !state.isLoading else { return .none }
state.activeLoadingProvider = provider
return unlinkProviderEffect(provider)
case .setAlert(let type):
state.alert = Self.alertState(for: type)
Expand All @@ -66,6 +71,10 @@ struct AccountFeature {
state.connectedProviders = allProviders.filter { $0 != currentProvider }
state.disconnectedProviders = AuthProvider.allCases
.filter { !allProviders.contains($0) }
case .loading(.end):
if !state.isLoading {
state.activeLoadingProvider = nil
}
case .loading:
break
}
Expand Down
25 changes: 14 additions & 11 deletions Application/DevLogPresentation/Sources/Settings/AccountView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct AccountView: View {
let providers = AuthProvider.allCases.filter { $0 != store.currentProvider }
ForEach(providers, id: \.self) { provider in
let isConnected = store.connectedProviders.contains(provider)
let showProgressView = store.isLoading && store.activeLoadingProvider == provider
HStack {
providerContent(provider)
Spacer()
Expand All @@ -38,14 +39,21 @@ struct AccountView: View {
Text(isConnected
? String(localized: "account_disconnect")
: String(localized: "account_connect"))
.font(.caption.weight(.semibold))
.foregroundStyle(.white)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(isConnected ? Color.red : .blue)
.clipShape(.capsule)
.font(.caption.weight(.semibold))
.foregroundStyle(.white)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(isConnected ? Color.red : .blue)
.clipShape(.capsule)
}
.buttonStyle(.plain)
.disabled(store.isLoading)
.opacity(showProgressView ? 0 : 1)
.overlay {
if showProgressView {
ProgressView()
}
}
}
}
}
Expand All @@ -55,11 +63,6 @@ struct AccountView: View {
.navigationTitle(String(localized: "nav_account"))
.onAppear { store.send(.onAppear) }
.alert($store.scope(state: \.alert, action: \.alert))
.overlay {
if store.isLoading {
LoadingView()
}
}
}

private func formattedProviderName(_ provider: AuthProvider) -> String {
Expand Down
Loading
Loading