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
2 changes: 1 addition & 1 deletion Projects/App/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ let appTarget = Target.target(
deploymentTargets: Atcha.v2Deployment,
infoPlist: .extendingDefault(with: [
"CFBundleDisplayName": "앗차",
"UILaunchScreen": [:],
"UILaunchStoryboardName": "LaunchScreen",
"NSAlarmKitUsageDescription": "막차 시간에 맞춰 알람을 울리기 위해 권한이 필요합니다.",
"NSLocationWhenInUseUsageDescription": "현재 위치를 출발지로 사용하기 위해 위치 정보 접근 권한이 필요합니다.",
// 사일런트 푸시(content-available=1) 수신용 — 사용자 알림 권한과 무관.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "Splash_BG.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Splash_BG@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Splash_BG@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "img_Atcha_character.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img_Atcha_character@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img_Atcha_character@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "img_Atcha.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img_Atcha@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img_Atcha@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions Projects/App/Resources/LaunchScreen.storyboard
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="0qB-dO-3U6"/>
<viewControllerLayoutGuide type="bottom" id="2LT-NI-Tm7"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="splashBackground" translatesAutoresizingMaskIntoConstraints="NO" id="09a-iA-Mxf">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="935-rF-KUC">
<rect key="frame" x="146.66666666666666" y="363" width="100" height="126.33333333333331"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="splashCharacter" translatesAutoresizingMaskIntoConstraints="NO" id="csS-KK-yCf">
<rect key="frame" x="0.0" y="0.0" width="100" height="62.333333333333336"/>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="splashLogo" translatesAutoresizingMaskIntoConstraints="NO" id="nnR-L7-YKX">
<rect key="frame" x="0.0" y="74.333333333333314" width="100" height="52"/>
</imageView>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" red="0.074509803921568626" green="0.074509803921568626" blue="0.082352941176470587" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="935-rF-KUC" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="4oV-rM-in1"/>
<constraint firstItem="09a-iA-Mxf" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="FzF-6x-XiG"/>
<constraint firstAttribute="bottom" secondItem="09a-iA-Mxf" secondAttribute="bottom" id="GHy-tu-oxr"/>
<constraint firstAttribute="trailing" secondItem="09a-iA-Mxf" secondAttribute="trailing" id="fXW-wu-UoH"/>
<constraint firstItem="935-rF-KUC" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="nRk-dD-4MT"/>
<constraint firstItem="09a-iA-Mxf" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="xeK-Hf-fno"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-815" y="305"/>
</scene>
</scenes>
<resources>
<image name="splashBackground" width="360" height="800"/>
<image name="splashCharacter" width="59.333332061767578" height="62.333332061767578"/>
<image name="splashLogo" width="100" height="52"/>
</resources>
</document>
43 changes: 32 additions & 11 deletions Projects/App/Sources/SplashViewController.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import DesignSystem
import UIKit

/// Dumb splash screen: logo while the auth bootstrap runs, a retry affordance
/// when it fails. All flow decisions live in AppCoordinator.
/// Dumb splash screen: legacy splash visuals (full-bleed background + character/logo stack)
/// while the auth bootstrap runs, a retry affordance when it fails.
/// All flow decisions live in AppCoordinator.
final class SplashViewController: UIViewController {
var onRetryTapped: (() -> Void)?

private let logoLabel = UILabel()
private let backgroundImageView = UIImageView()
private let characterImageView = UIImageView()
private let logoImageView = UIImageView()
private let logoStackView = UIStackView()
private let activityIndicator = UIActivityIndicatorView(style: .medium)
private let retryStack = UIStackView()
private let messageLabel = UILabel()
Expand All @@ -32,11 +36,23 @@ final class SplashViewController: UIViewController {
private func configureUI() {
view.backgroundColor = DSColor.Background.base

logoLabel.text = "앗차"
logoLabel.font = DSFont.pretendard(.bold, size: 34)
logoLabel.textColor = DSColor.Accent.default
backgroundImageView.image = AtchaV2Asset.splashBackground.image
backgroundImageView.contentMode = .scaleAspectFill
backgroundImageView.clipsToBounds = true

characterImageView.image = AtchaV2Asset.splashCharacter.image
characterImageView.contentMode = .scaleAspectFit
logoImageView.image = AtchaV2Asset.splashLogo.image
logoImageView.contentMode = .scaleAspectFit

logoStackView.axis = .vertical
logoStackView.alignment = .center
logoStackView.spacing = 12
logoStackView.addArrangedSubview(characterImageView)
logoStackView.addArrangedSubview(logoImageView)

activityIndicator.hidesWhenStopped = true
activityIndicator.color = DSColor.Text.primary

messageLabel.font = DSTypography.body1.font
messageLabel.textColor = DSColor.Text.primary
Expand All @@ -54,18 +70,23 @@ final class SplashViewController: UIViewController {
retryStack.addArrangedSubview(messageLabel)
retryStack.addArrangedSubview(retryButton)

for subview in [logoLabel, activityIndicator, retryStack] {
for subview in [backgroundImageView, logoStackView, activityIndicator, retryStack] {
subview.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(subview)
}

NSLayoutConstraint.activate([
logoLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
logoLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -DSSpacing.xl),
backgroundImageView.topAnchor.constraint(equalTo: view.topAnchor),
backgroundImageView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
backgroundImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
backgroundImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
// 런치스크린 storyboard와 동일한 정중앙 배치 — 전환 시 로고가 튀지 않게 유지.
logoStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
logoStackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor),
activityIndicator.topAnchor.constraint(equalTo: logoLabel.bottomAnchor, constant: DSSpacing.lg),
activityIndicator.topAnchor.constraint(equalTo: logoStackView.bottomAnchor, constant: DSSpacing.xl),
retryStack.centerXAnchor.constraint(equalTo: view.centerXAnchor),
retryStack.topAnchor.constraint(equalTo: logoLabel.bottomAnchor, constant: DSSpacing.lg),
retryStack.topAnchor.constraint(equalTo: logoStackView.bottomAnchor, constant: DSSpacing.xl),
retryStack.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: DSSpacing.md),
retryStack.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -DSSpacing.md),
])
Expand Down