diff --git a/app-ios/App/App.xcodeproj/project.pbxproj b/app-ios/App/App.xcodeproj/project.pbxproj index c7df7a9aa..06f60b6b0 100644 --- a/app-ios/App/App.xcodeproj/project.pbxproj +++ b/app-ios/App/App.xcodeproj/project.pbxproj @@ -459,7 +459,7 @@ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.4; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 0.0.1; PRODUCT_BUNDLE_IDENTIFIER = io.github.droidkaigi.DroidKaigi2024; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; @@ -497,7 +497,7 @@ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.4; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 0.0.1; PRODUCT_BUNDLE_IDENTIFIER = io.github.droidkaigi.DroidKaigi2024; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; diff --git a/app-ios/Sources/AboutFeature/AboutReducer.swift b/app-ios/Sources/AboutFeature/AboutReducer.swift index 596e41bf6..119a9c78d 100644 --- a/app-ios/Sources/AboutFeature/AboutReducer.swift +++ b/app-ios/Sources/AboutFeature/AboutReducer.swift @@ -27,6 +27,9 @@ public struct AboutReducer { case codeOfConductTapped case acknowledgementsTapped case privacyPolicyTapped + case youtubeTapped + case xcomTapped + case mediumTapped } } @@ -34,6 +37,9 @@ public struct AboutReducer { public enum Destination { case codeOfConduct case privacyPolicy + case youtube + case xcom + case medium } @Reducer(state: .equatable) @@ -65,6 +71,15 @@ public struct AboutReducer { case .view(.privacyPolicyTapped): state.destination = .privacyPolicy return .none + case .view(.youtubeTapped): + state.destination = .youtube + return .none + case .view(.xcomTapped): + state.destination = .xcom + return .none + case .view(.mediumTapped): + state.destination = .medium + return .none case .presentation: return .none case .path: diff --git a/app-ios/Sources/AboutFeature/AboutView.swift b/app-ios/Sources/AboutFeature/AboutView.swift index bd6447b4b..22f494675 100644 --- a/app-ios/Sources/AboutFeature/AboutView.swift +++ b/app-ios/Sources/AboutFeature/AboutView.swift @@ -4,6 +4,10 @@ import SwiftUI @ViewAction(for: AboutReducer.self) public struct AboutView: View { @Bindable public var store: StoreOf + + var version: String { + Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "" + } public init(store: StoreOf) { self.store = store @@ -30,6 +34,15 @@ public struct AboutView: View { .sheet(item: $store.scope(state: \.destination?.privacyPolicy, action: \.presentation.privacyPolicy), content: { _ in Text("PrivacyPolicy") }) + .sheet(item: $store.scope(state: \.destination?.youtube, action: \.presentation.youtube), content: { _ in + Text("Youtube") + }) + .sheet(item: $store.scope(state: \.destination?.xcom, action: \.presentation.xcom), content: { _ in + Text("X.com") + }) + .sheet(item: $store.scope(state: \.destination?.medium, action: \.presentation.medium), content: { _ in + Text("Medium") + }) } @ViewBuilder var content: some View { @@ -143,7 +156,48 @@ public struct AboutView: View { .background(Color(.outlineOutlineVariant)) } + + HStack(spacing: 12) { + Button(action: { + send(.youtubeTapped) + }, label: { + Image(systemName: "play.circle") + .resizable() + .aspectRatio(contentMode: .fit) + .foregroundStyle(Color(.surfaceOnSurface)) + }) + .frame(width: 48, height: 48) + Button(action: { + send(.xcomTapped) + }, label: { + Image(systemName: "x.circle") + .resizable() + .aspectRatio(contentMode: .fit) + .foregroundStyle(Color(.surfaceOnSurface)) + }) + .frame(width: 48, height: 48) + + Button(action: { + send(.mediumTapped) + }, label: { + Image(systemName: "m.circle") + .resizable() + .aspectRatio(contentMode: .fit) + .foregroundStyle(Color(.surfaceOnSurface)) + }) + .frame(width: 48, height: 48) + } + .padding(.vertical, 24) + + Text(String(localized: "AppVersion", bundle: .module)) + .font(.body) + .foregroundStyle(Color(.surfaceOnSurface)) + .padding(.bottom, 10) + + Text(version) + .font(.body) + .foregroundStyle(Color(.surfaceOnSurface)) } .padding(.horizontal, 16) } diff --git a/app-ios/Sources/AboutFeature/Localizable.xcstrings b/app-ios/Sources/AboutFeature/Localizable.xcstrings index fb7da6e0e..01c7f6fdc 100644 --- a/app-ios/Sources/AboutFeature/Localizable.xcstrings +++ b/app-ios/Sources/AboutFeature/Localizable.xcstrings @@ -11,6 +11,16 @@ } } }, + "AppVersion" : { + "localizations" : { + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "アプリバージョン" + } + } + } + }, "CodeOfConduct" : { "localizations" : { "ja" : { @@ -100,6 +110,9 @@ } } } + }, + "Medium" : { + }, "Others" : { "localizations" : { @@ -140,6 +153,12 @@ } } } + }, + "X.com" : { + + }, + "Youtube" : { + } }, "version" : "1.0" diff --git a/app-ios/Tests/AboutFeatureTests/AboutFeatureTests.swift b/app-ios/Tests/AboutFeatureTests/AboutFeatureTests.swift index 7fd3083c0..f8e7cac79 100644 --- a/app-ios/Tests/AboutFeatureTests/AboutFeatureTests.swift +++ b/app-ios/Tests/AboutFeatureTests/AboutFeatureTests.swift @@ -64,4 +64,35 @@ final class AboutFeatureTests: XCTestCase { $0.destination = .privacyPolicy } } + + @MainActor + func testTappedYoutube() async { + let store = TestStore(initialState: AboutReducer.State()) { + AboutReducer() + } + await store.send(\.view.youtubeTapped) { + $0.destination = .youtube + } + } + + @MainActor + func testTappedXcom() async { + let store = TestStore(initialState: AboutReducer.State()) { + AboutReducer() + } + await store.send(\.view.xcomTapped) { + $0.destination = .xcom + } + } + + @MainActor + func testTappedMedium() async { + let store = TestStore(initialState: AboutReducer.State()) { + AboutReducer() + } + await store.send(\.view.mediumTapped) { + $0.destination = .medium + } + } + }