feat: 首次登录
This commit is contained in:
parent
5080b104a4
commit
8044927b51
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 MiB |
BIN
wake/Assets/Images/Gif/BlindLoading.gif
Normal file
BIN
wake/Assets/Images/Gif/BlindLoading.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 MiB |
BIN
wake/Assets/Images/Gif/BlindOpen.gif
Normal file
BIN
wake/Assets/Images/Gif/BlindOpen.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 MiB |
BIN
wake/Assets/Images/Gif/BlindReady.gif
Normal file
BIN
wake/Assets/Images/Gif/BlindReady.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 MiB |
11
wake/Assets/Svg/Tips.svg
Normal file
11
wake/Assets/Svg/Tips.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_7357_2809)">
|
||||||
|
<path d="M3.33325 12.6668V6.00016C3.33325 3.42283 5.42259 1.3335 7.99992 1.3335C10.5773 1.3335 12.6666 3.42283 12.6666 6.00016V12.6668M1.33325 12.6668H14.6666" stroke="black" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.99992 14.6665C8.92039 14.6665 9.66659 13.9203 9.66659 12.9998V12.6665H6.33325V12.9998C6.33325 13.9203 7.07945 14.6665 7.99992 14.6665Z" stroke="black" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_7357_2809">
|
||||||
|
<rect width="16" height="16" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 731 B |
@ -169,7 +169,7 @@ struct ContentView: View {
|
|||||||
LoginView()
|
LoginView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding(.horizontal)
|
||||||
.padding(.top, 20)
|
.padding(.top, 20)
|
||||||
// 标题
|
// 标题
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
|||||||
@ -11,6 +11,7 @@ enum AppRoute: Hashable {
|
|||||||
case blindOutcome(media: MediaType)
|
case blindOutcome(media: MediaType)
|
||||||
case memories
|
case memories
|
||||||
case subscribe
|
case subscribe
|
||||||
|
case userInfo
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
var view: some View {
|
var view: some View {
|
||||||
@ -33,6 +34,8 @@ enum AppRoute: Hashable {
|
|||||||
MemoriesView()
|
MemoriesView()
|
||||||
case .subscribe:
|
case .subscribe:
|
||||||
SubscribeView()
|
SubscribeView()
|
||||||
|
case .userInfo:
|
||||||
|
UserInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,12 @@ private enum MediaURLs {
|
|||||||
static let VideoBlindURL = "https://cdn.memorywake.com/users/7363409620351717377/files/7366658779259211776/AD970D28-9D1E-4817-A245-F11967441B8F.mp4"
|
static let VideoBlindURL = "https://cdn.memorywake.com/users/7363409620351717377/files/7366658779259211776/AD970D28-9D1E-4817-A245-F11967441B8F.mp4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum BlindBoxAnimationPhase {
|
||||||
|
case loading
|
||||||
|
case ready
|
||||||
|
case opening
|
||||||
|
}
|
||||||
|
|
||||||
extension Notification.Name {
|
extension Notification.Name {
|
||||||
static let navigateToMediaViewer = Notification.Name("navigateToMediaViewer")
|
static let navigateToMediaViewer = Notification.Name("navigateToMediaViewer")
|
||||||
}
|
}
|
||||||
@ -71,6 +77,7 @@ struct BlindBoxView: View {
|
|||||||
let mediaType: BlindBoxMediaType
|
let mediaType: BlindBoxMediaType
|
||||||
@State private var showLottieAnimation = true
|
@State private var showLottieAnimation = true
|
||||||
@State private var showScalingOverlay = false
|
@State private var showScalingOverlay = false
|
||||||
|
@State private var animationPhase: BlindBoxAnimationPhase = .loading
|
||||||
@State private var scale: CGFloat = 0.1
|
@State private var scale: CGFloat = 0.1
|
||||||
@State private var videoPlayer: AVPlayer?
|
@State private var videoPlayer: AVPlayer?
|
||||||
@State private var showControls = false
|
@State private var showControls = false
|
||||||
@ -263,20 +270,49 @@ struct BlindBoxView: View {
|
|||||||
.opacity(showScalingOverlay ? 0 : 1)
|
.opacity(showScalingOverlay ? 0 : 1)
|
||||||
.animation(.easeOut(duration: 1.5), value: showScalingOverlay)
|
.animation(.easeOut(duration: 1.5), value: showScalingOverlay)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !showScalingOverlay {
|
if !showScalingOverlay {
|
||||||
VStack(spacing: 20) {
|
VStack(spacing: 20) {
|
||||||
let player = AVPlayer(url: URL(string: MediaURLs.VideoBlindURL)!)
|
switch animationPhase {
|
||||||
VideoPlayer(player: player)
|
case .loading:
|
||||||
.background(TransparentVideoPlayer())
|
GIFView(name: "BlindLoading")
|
||||||
|
.frame(width: 300, height: 300)
|
||||||
|
.onAppear {
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 6) {
|
||||||
|
withAnimation {
|
||||||
|
animationPhase = .ready
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case .ready:
|
||||||
|
ZStack {
|
||||||
|
GIFView(name: "BlindReady")
|
||||||
|
.frame(width: 300, height: 300)
|
||||||
|
|
||||||
|
// Add a transparent overlay to capture taps
|
||||||
|
Color.clear
|
||||||
|
.contentShape(Rectangle()) // Make the entire area tappable
|
||||||
|
.frame(width: 300, height: 300)
|
||||||
|
.onTapGesture {
|
||||||
|
print("点击了盲盒")
|
||||||
|
withAnimation {
|
||||||
|
animationPhase = .opening
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.frame(width: 300, height: 300)
|
.frame(width: 300, height: 300)
|
||||||
.onAppear {
|
|
||||||
player.play()
|
case .opening:
|
||||||
player.isMuted = true
|
GIFView(name: "BlindOpen")
|
||||||
}
|
.frame(width: 300, height: 300)
|
||||||
.onDisappear {
|
.onAppear {
|
||||||
player.pause()
|
self.loadMedia()
|
||||||
}
|
// Start animation after media is loaded
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
|
||||||
|
self.startScalingAnimation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.compositingGroup()
|
.compositingGroup()
|
||||||
.padding()
|
.padding()
|
||||||
@ -298,13 +334,6 @@ struct BlindBoxView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationBarBackButtonHidden(true)
|
.navigationBarBackButtonHidden(true)
|
||||||
.onAppear {
|
|
||||||
self.loadMedia()
|
|
||||||
// Start animation after media is loaded
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
|
|
||||||
self.startScalingAnimation()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -61,11 +61,6 @@ struct LoginView: View {
|
|||||||
}
|
}
|
||||||
.navigationBarBackButtonHidden(true)
|
.navigationBarBackButtonHidden(true)
|
||||||
.navigationBarHidden(true)
|
.navigationBarHidden(true)
|
||||||
.fullScreenCover(isPresented: $isLoggedIn) {
|
|
||||||
NavigationStack {
|
|
||||||
UserInfo()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Views
|
// MARK: - Views
|
||||||
@ -264,6 +259,8 @@ struct LoginView: View {
|
|||||||
self.errorMessage = "登录信息不完整,请重试"
|
self.errorMessage = "登录信息不完整,请重试"
|
||||||
self.showError = true
|
self.showError = true
|
||||||
}
|
}
|
||||||
|
// 跳转到userinfo
|
||||||
|
Router.shared.navigate(to: .userInfo)
|
||||||
|
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
print("❌ [15] 后端认证失败")
|
print("❌ [15] 后端认证失败")
|
||||||
|
|||||||
@ -61,28 +61,23 @@ struct UserInfo: View {
|
|||||||
.background(Color.themeTextWhiteSecondary)
|
.background(Color.themeTextWhiteSecondary)
|
||||||
.zIndex(1) // 确保导航栏在最上层
|
.zIndex(1) // 确保导航栏在最上层
|
||||||
// Dynamic text that changes based on keyboard state
|
// Dynamic text that changes based on keyboard state
|
||||||
HStack(spacing: 20) {
|
HStack(spacing: 6) {
|
||||||
|
SVGImage(svgName: "Tips")
|
||||||
|
.frame(width: 16, height: 16)
|
||||||
|
.padding(.leading,6)
|
||||||
Text("Choose a photo as your avatar, and we'll generate a video mystery box for you.")
|
Text("Choose a photo as your avatar, and we'll generate a video mystery box for you.")
|
||||||
.font(Typography.font(for: .caption))
|
.font(Typography.font(for: .caption))
|
||||||
.foregroundColor(.black)
|
.foregroundColor(.black)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.lineLimit(isKeyboardVisible ? 1 : 2)
|
.padding(3)
|
||||||
.padding(6)
|
|
||||||
.background(
|
|
||||||
LinearGradient(
|
|
||||||
gradient: Gradient(colors: [
|
|
||||||
Color(red: 1.0, green: 0.97, blue: 0.87),
|
|
||||||
.white,
|
|
||||||
Color(red: 1.0, green: 0.97, blue: 0.84)
|
|
||||||
]),
|
|
||||||
startPoint: .topLeading,
|
|
||||||
endPoint: .bottomTrailing
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
.padding(10)
|
|
||||||
.animation(.easeInOut(duration: 0.3), value: isKeyboardVisible)
|
.animation(.easeInOut(duration: 0.3), value: isKeyboardVisible)
|
||||||
.transition(.opacity)
|
.transition(.opacity)
|
||||||
|
.background(
|
||||||
|
Color.themeTextWhite
|
||||||
|
.cornerRadius(12)
|
||||||
|
)
|
||||||
|
.padding(10)
|
||||||
|
|
||||||
// 可滚动的内容区域
|
// 可滚动的内容区域
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
@ -141,7 +136,6 @@ struct UserInfo: View {
|
|||||||
|
|
||||||
// Continue Button
|
// Continue Button
|
||||||
Button(action: {
|
Button(action: {
|
||||||
Router.shared.navigate(to: .blindBox(mediaType: .image))
|
|
||||||
if showUsername {
|
if showUsername {
|
||||||
let parameters: [String: Any] = [
|
let parameters: [String: Any] = [
|
||||||
"username": userName,
|
"username": userName,
|
||||||
|
|||||||
@ -82,33 +82,28 @@ struct MediaUploadView: View {
|
|||||||
.padding(.trailing, 16)
|
.padding(.trailing, 16)
|
||||||
}
|
}
|
||||||
.background(Color.themeTextWhiteSecondary)
|
.background(Color.themeTextWhiteSecondary)
|
||||||
.padding(.horizontal)
|
// .padding(.horizontal)
|
||||||
.zIndex(1) // 确保导航栏显示在最上层
|
.zIndex(1) // 确保导航栏显示在最上层
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 上传提示视图
|
/// 上传提示视图
|
||||||
private var uploadHintView: some View {
|
private var uploadHintView: some View {
|
||||||
HStack {
|
HStack (spacing: 6) {
|
||||||
|
SVGImage(svgName: "Tips")
|
||||||
|
.frame(width: 16, height: 16)
|
||||||
|
.padding(.leading,6)
|
||||||
Text("The upload process will take approximately 2 minutes. Thank you for your patience.")
|
Text("The upload process will take approximately 2 minutes. Thank you for your patience.")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundColor(.black)
|
.foregroundColor(.black)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.padding(3)
|
.padding(3)
|
||||||
.background(
|
|
||||||
LinearGradient(
|
|
||||||
gradient: Gradient(colors: [
|
|
||||||
Color(red: 1.0, green: 0.97, blue: 0.87),
|
|
||||||
.white,
|
|
||||||
Color(red: 1.0, green: 0.97, blue: 0.84)
|
|
||||||
]),
|
|
||||||
startPoint: .topLeading,
|
|
||||||
endPoint: .bottomTrailing
|
|
||||||
)
|
|
||||||
.cornerRadius(8)
|
|
||||||
)
|
|
||||||
.padding(.horizontal)
|
|
||||||
}
|
}
|
||||||
|
.background(
|
||||||
|
Color.themeTextWhite
|
||||||
|
.cornerRadius(6)
|
||||||
|
)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 继续按钮
|
/// 继续按钮
|
||||||
|
|||||||
@ -46,10 +46,10 @@ struct WakeApp: App {
|
|||||||
// 根据登录状态显示不同视图
|
// 根据登录状态显示不同视图
|
||||||
if authState.isAuthenticated {
|
if authState.isAuthenticated {
|
||||||
// 已登录:显示userInfo页面
|
// 已登录:显示userInfo页面
|
||||||
|
LoginView()
|
||||||
|
.environmentObject(authState)
|
||||||
// ContentView()
|
// ContentView()
|
||||||
// .environmentObject(authState)
|
// .environmentObject(authState)
|
||||||
ContentView()
|
|
||||||
.environmentObject(authState)
|
|
||||||
} else {
|
} else {
|
||||||
// 未登录:显示登录界面
|
// 未登录:显示登录界面
|
||||||
LoginView()
|
LoginView()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user