add onboarding tutorial + icon
This commit is contained in:
1 parent
3bad6ffe14
commit
2a81e09858
21 files changed
+406
-15
No files matched your search
@@ -14,22 +14,9 @@
|
||||
6F09B79D2DEB694B00CDE89C /* Pocket Poster.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Pocket Poster.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
6F09B7F72DEBBFEB00CDE89C /* Exceptions for "Pocket Poster" folder in "Pocket Poster" target */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
"Pocket-Poster-Info.plist",
|
||||
);
|
||||
target = 6F09B79C2DEB694B00CDE89C /* Pocket Poster */;
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
6F09B79F2DEB694B00CDE89C /* Pocket Poster */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
6F09B7F72DEBBFEB00CDE89C /* Exceptions for "Pocket Poster" folder in "Pocket Poster" target */,
|
||||
);
|
||||
path = "Pocket Poster";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "pocketposter-2.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
@@ -12,6 +13,7 @@
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "pocketposter-transparent.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 870 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 509 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "0.500",
|
||||
"red" : "0.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.500",
|
||||
"green" : "0.000",
|
||||
"red" : "0.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "1.000",
|
||||
"red" : "0.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "0.000",
|
||||
"red" : "0.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Screenshot 2025-05-31 at 20.52.14.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 2.1 MiB |
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "pocketposter-transparent.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 509 KiB |
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Screenshot 2025-05-31 at 20.51.24.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 230 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "2019-11-26-shortcuts.jpg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,19 @@ import SwiftUI
|
||||
|
||||
@main
|
||||
struct Pocket_PosterApp: App {
|
||||
@AppStorage("finishedTutorial") var finishedTutorial: Bool = false
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
Group {
|
||||
if finishedTutorial {
|
||||
ContentView()
|
||||
} else {
|
||||
OnBoardingView()
|
||||
}
|
||||
}
|
||||
.transition(.opacity)
|
||||
.animation(.easeOut(duration: 0.5), value: finishedTutorial)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,7 @@ struct ContentView: View {
|
||||
}
|
||||
.alert("Success!", isPresented: $showSuccessAlert) {
|
||||
Button("OK") {
|
||||
PosterBoardManager.runShortcut(named: "PosterBoard") // shortcut url: https://www.icloud.com/shortcuts/9035ef1d51c247dba8c9861dc10b4aa7
|
||||
PosterBoardManager.runShortcut(named: "PosterBoard")
|
||||
}
|
||||
} message: {
|
||||
Text(lastError ?? "???")
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// OnBoardingCardButtons.swift
|
||||
// Pocket Poster
|
||||
//
|
||||
// Created by lemin on 5/31/25.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct OnBoardingCardButtons: View {
|
||||
@AppStorage("finishedTutorial") var finishedTutorial: Bool?
|
||||
|
||||
@Binding var idx: Int
|
||||
@Binding var isAnimating: Bool
|
||||
|
||||
var showDismiss: Bool
|
||||
var showFinish: Bool
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
// MARK: Dismiss Button
|
||||
if showDismiss {
|
||||
Button(action: {
|
||||
playFinishAnimation()
|
||||
}) {
|
||||
HStack(spacing: 8) {
|
||||
Image(systemName: "x.circle")
|
||||
.imageScale(.large)
|
||||
|
||||
Text("Skip")
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 10)
|
||||
.background(
|
||||
Capsule().strokeBorder(Color.white, lineWidth: 1.25)
|
||||
)
|
||||
}
|
||||
.accentColor(Color.white)
|
||||
.accessibilityIdentifier("OnBoardingSkip")
|
||||
}
|
||||
|
||||
// MARK: Next Button
|
||||
Button(action: {
|
||||
if showFinish {
|
||||
playFinishAnimation()
|
||||
} else {
|
||||
// move to next
|
||||
isAnimating = false
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
|
||||
idx += 1
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
|
||||
isAnimating = true
|
||||
})
|
||||
})
|
||||
}
|
||||
}) {
|
||||
HStack(spacing: 8) {
|
||||
Text(showFinish ? "Finish" : "Next")
|
||||
|
||||
Image(systemName: showFinish ? "checkmark.circle" : "arrow.right.circle")
|
||||
.imageScale(.large)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 10)
|
||||
.background(
|
||||
Capsule().strokeBorder(Color.white, lineWidth: 1.25)
|
||||
)
|
||||
}
|
||||
.accentColor(Color.white)
|
||||
.accessibilityIdentifier("OnBoardingNext")
|
||||
}
|
||||
}
|
||||
|
||||
func playFinishAnimation() {
|
||||
isAnimating = false
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
|
||||
finishedTutorial = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct OnBoardingCardView: View {
|
||||
var info: OnBoardingPage
|
||||
var pageCount: Int
|
||||
@Binding var idx: Int
|
||||
|
||||
@State private var isAnimating: Bool = false
|
||||
@State private var imgCornerRadius: CGFloat = 10.0
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 20) {
|
||||
// Image
|
||||
Image(info.image)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.clipShape(RoundedRectangle(cornerRadius: imgCornerRadius))
|
||||
.shadow(color: Color(red: 0, green: 0, blue: 0, opacity: 0.15), radius: 8, x: 6, y: 8)
|
||||
.scaleEffect(isAnimating ? 1.0 : 0.6)
|
||||
|
||||
// Title
|
||||
Text(info.title)
|
||||
.foregroundColor(Color.white)
|
||||
.multilineTextAlignment(.center)
|
||||
.font(.largeTitle)
|
||||
.fontWeight(.heavy)
|
||||
.shadow(color: Color(red: 0, green: 0, blue: 0, opacity: 0.15), radius: 2, x: 2, y: 2)
|
||||
|
||||
// Description
|
||||
Text(info.description)
|
||||
.foregroundColor(Color.white)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal, 16)
|
||||
.frame(maxWidth: 480)
|
||||
|
||||
// Link Button
|
||||
if let url = info.link, let linkName = info.linkName {
|
||||
Link(destination: url) {
|
||||
HStack(spacing: 8) {
|
||||
Image(systemName: "link.circle")
|
||||
.imageScale(.large)
|
||||
|
||||
Text(linkName)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 10)
|
||||
.background(
|
||||
Capsule().strokeBorder(Color.white, lineWidth: 1.25)
|
||||
)
|
||||
}
|
||||
.accentColor(Color.white)
|
||||
}
|
||||
|
||||
OnBoardingCardButtons(idx: $idx, isAnimating: $isAnimating, showDismiss: idx == 0, showFinish: idx == pageCount-1)
|
||||
}
|
||||
.opacity(isAnimating ? 1.0 : 0.0)
|
||||
.animation(.easeOut(duration: 0.5), value: isAnimating)
|
||||
.onAppear {
|
||||
isAnimating = true
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.vertical, 25)
|
||||
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
|
||||
.background(LinearGradient(gradient: Gradient(colors: info.gradientColors), startPoint: .top, endPoint: .bottom).ignoresSafeArea())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// OnBoardingPage.swift
|
||||
// Pocket Poster
|
||||
//
|
||||
// Created by lemin on 5/31/25.
|
||||
//
|
||||
|
||||
import SwiftUICore
|
||||
|
||||
struct OnBoardingPage: Identifiable {
|
||||
var id = UUID()
|
||||
var title: String
|
||||
var description: String
|
||||
var image: String
|
||||
var link: URL?
|
||||
var linkName: String?
|
||||
var gradientColors: [Color]
|
||||
|
||||
init(title: String, description: String, image: String, link: URL? = nil, linkName: String? = nil, gradientColors: [Color] = [Color("WelcomeLight"), Color("WelcomeDark")]) {
|
||||
self.id = UUID()
|
||||
self.title = title
|
||||
self.description = description
|
||||
self.image = image
|
||||
self.link = link
|
||||
self.linkName = linkName
|
||||
self.gradientColors = gradientColors
|
||||
}
|
||||
}
|
||||
|
||||
let onBoardingCards: [OnBoardingPage] = [
|
||||
.init(
|
||||
title: "Welcome to Pocket Poster!",
|
||||
description: "Here is a tutorial to help you get started with the app.",
|
||||
image: "Logo"
|
||||
),
|
||||
.init(
|
||||
title: "Install the Shortcut",
|
||||
description: "To apply, you will need a shortcut that opens PosterBoard.",
|
||||
image: "Shortcuts",
|
||||
link: URL(string: "https://www.icloud.com/shortcuts/9035ef1d51c247dba8c9861dc10b4aa7"),
|
||||
linkName: "Get Shortcut"
|
||||
),
|
||||
.init(
|
||||
title: "Install Nugget",
|
||||
description: "To get the app bundle id, Nugget is required.\n\nOn your computer, download Nugget from the GitHub.",
|
||||
image: "Nugget",
|
||||
link: URL(string: "https://github.com/leminlimez/Nugget/releases/latest"),
|
||||
linkName: "Open GitHub"
|
||||
),
|
||||
.init(
|
||||
title: "Enjoy!",
|
||||
description: "You can find wallpapers on the official Cowabun.ga website.",
|
||||
image: "Cowabunga",
|
||||
link: URL(string: "https://cowabun.ga/wallpapers"),
|
||||
linkName: "Find Wallpapers"
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// OnBoardingView.swift
|
||||
// Pocket Poster
|
||||
//
|
||||
// Created by lemin on 5/31/25.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct OnBoardingView: View {
|
||||
@State var currentIndex: Int = 0
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
OnBoardingCardView(info: onBoardingCards[currentIndex], pageCount: onBoardingCards.count, idx: $currentIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user