1.0.0 for iOS
This commit is contained in:
@@ -425,7 +425,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atri.dad.MagicCounter.MagicCounter;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
@@ -459,7 +459,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atri.dad.MagicCounter.MagicCounter;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
|
||||
Binary file not shown.
@@ -112,3 +112,20 @@ struct SettingSlider: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for haptic feedback.
|
||||
*/
|
||||
enum Haptics {
|
||||
static func play(_ style: UIImpactFeedbackGenerator.FeedbackStyle) {
|
||||
guard UserDefaults.standard.bool(forKey: "hapticFeedbackEnabled") else { return }
|
||||
let generator = UIImpactFeedbackGenerator(style: style)
|
||||
generator.impactOccurred()
|
||||
}
|
||||
|
||||
static func notification(_ type: UINotificationFeedbackGenerator.FeedbackType) {
|
||||
guard UserDefaults.standard.bool(forKey: "hapticFeedbackEnabled") else { return }
|
||||
let generator = UINotificationFeedbackGenerator()
|
||||
generator.notificationOccurred(type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ struct ContentView: View {
|
||||
}
|
||||
}
|
||||
.listStyle(.insetGrouped)
|
||||
.navigationTitle("History")
|
||||
.navigationTitle("Games")
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(action: { showSetup = true }) {
|
||||
@@ -73,7 +73,7 @@ struct ContentView: View {
|
||||
}
|
||||
}
|
||||
.tabItem {
|
||||
Label("History", systemImage: "clock.fill")
|
||||
Label("Games", systemImage: "clock.fill")
|
||||
}
|
||||
|
||||
SettingsView()
|
||||
|
||||
@@ -76,7 +76,6 @@ struct GameView: View {
|
||||
.clipShape(Circle())
|
||||
}
|
||||
} else {
|
||||
// Placeholder for balance
|
||||
Color.clear.frame(width: 40, height: 40)
|
||||
}
|
||||
}
|
||||
@@ -85,9 +84,6 @@ struct GameView: View {
|
||||
|
||||
// Players Grid
|
||||
GeometryReader { geometry in
|
||||
// Use adaptive grid with minimum width to handle responsiveness
|
||||
// 320pt minimum ensures 1 column on iPhone Portrait (width ~390)
|
||||
// and 2 columns on iPhone Landscape (width ~844) or iPad
|
||||
let columns = [GridItem(.adaptive(minimum: 320), spacing: 24)]
|
||||
ScrollView {
|
||||
LazyVGrid(columns: columns, spacing: 24) {
|
||||
@@ -128,6 +124,9 @@ struct GameView: View {
|
||||
.presentationDetents([.medium])
|
||||
}
|
||||
.onChange(of: gameState) { newState in
|
||||
if newState.winner != nil {
|
||||
Haptics.notification(.success)
|
||||
}
|
||||
gameManager.updateActiveGame(state: newState)
|
||||
}
|
||||
}
|
||||
@@ -172,6 +171,8 @@ struct PlayerCell: View {
|
||||
let onCommanderTap: () -> Void
|
||||
let onScoop: () -> Void
|
||||
|
||||
@State private var showScoopConfirmation = false
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: 24)
|
||||
@@ -192,12 +193,8 @@ struct PlayerCell: View {
|
||||
.foregroundStyle(.primary)
|
||||
Spacer()
|
||||
|
||||
Menu {
|
||||
Button(role: .destructive, action: onScoop) {
|
||||
Label("Scoop", systemImage: "flag.fill")
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "ellipsis.circle")
|
||||
Button(action: { showScoopConfirmation = true }) {
|
||||
Image(systemName: "flag.fill")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(4)
|
||||
}
|
||||
@@ -257,20 +254,39 @@ struct PlayerCell: View {
|
||||
.opacity(player.isEliminated && !isWinner ? 0.8 : 1)
|
||||
.scaleEffect(isWinner ? 1.05 : 1)
|
||||
.animation(.spring, value: isWinner)
|
||||
.alert("Scoop?", isPresented: $showScoopConfirmation) {
|
||||
Button("Cancel", role: .cancel) { }
|
||||
Button("Scoop", role: .destructive) {
|
||||
Haptics.notification(.warning)
|
||||
onScoop()
|
||||
}
|
||||
} message: {
|
||||
Text("Are you sure you want to scoop?")
|
||||
}
|
||||
}
|
||||
|
||||
private func adjustLife(by amount: Int) {
|
||||
if player.isEliminated { return }
|
||||
Haptics.play(.light)
|
||||
var newPlayer = player
|
||||
newPlayer.life += amount
|
||||
onUpdate(newPlayer)
|
||||
|
||||
if newPlayer.isEliminated && !player.isEliminated {
|
||||
Haptics.notification(.error)
|
||||
}
|
||||
}
|
||||
|
||||
private func adjustPoison(by amount: Int) {
|
||||
if player.isEliminated { return }
|
||||
Haptics.play(.light)
|
||||
var newPlayer = player
|
||||
newPlayer.poison = max(0, newPlayer.poison + amount)
|
||||
onUpdate(newPlayer)
|
||||
|
||||
if newPlayer.isEliminated && !player.isEliminated {
|
||||
Haptics.notification(.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,11 +344,16 @@ struct CommanderDamageView: View {
|
||||
}
|
||||
|
||||
private func adjustCommanderDamage(attackerId: Int, by amount: Int) {
|
||||
Haptics.play(.light)
|
||||
var newPlayer = targetPlayer
|
||||
var damages = newPlayer.commanderDamages
|
||||
let current = damages[attackerId] ?? 0
|
||||
damages[attackerId] = max(0, current + amount)
|
||||
newPlayer.commanderDamages = damages
|
||||
onUpdate(newPlayer)
|
||||
|
||||
if newPlayer.isEliminated && !targetPlayer.isEliminated {
|
||||
Haptics.notification(.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 100 KiB |
BIN
ios/MagicCounter/Logo.icon/Assets/logo 2.png
Normal file
BIN
ios/MagicCounter/Logo.icon/Assets/logo 2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
@@ -7,10 +7,10 @@
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"image-name" : "MagicCounter 2.png",
|
||||
"name" : "MagicCounter 2",
|
||||
"image-name" : "logo 2.png",
|
||||
"name" : "logo 2",
|
||||
"position" : {
|
||||
"scale" : 0.8,
|
||||
"scale" : 0.85,
|
||||
"translation-in-points" : [
|
||||
0,
|
||||
0
|
||||
|
||||
@@ -10,6 +10,12 @@ import SwiftUI
|
||||
@main
|
||||
struct MagicCounterApp: App {
|
||||
@StateObject private var gameManager = GameManager()
|
||||
|
||||
init() {
|
||||
UserDefaults.standard.register(defaults: [
|
||||
"hapticFeedbackEnabled": true
|
||||
])
|
||||
}
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
|
||||
@@ -9,6 +9,7 @@ import SwiftUI
|
||||
|
||||
struct SettingsView: View {
|
||||
@AppStorage("accentColorName") private var accentColorName = "Blue"
|
||||
@AppStorage("hapticFeedbackEnabled") private var hapticFeedbackEnabled = true
|
||||
|
||||
private let colors: [(name: String, color: Color)] = [
|
||||
("Blue", .blue),
|
||||
@@ -44,6 +45,10 @@ struct SettingsView: View {
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
Form {
|
||||
Section("General") {
|
||||
Toggle("Haptic Feedback", isOn: $hapticFeedbackEnabled)
|
||||
}
|
||||
|
||||
Section("Appearance") {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
Text("ACCENT COLOR")
|
||||
|
||||
Reference in New Issue
Block a user