Compare commits
80 Commits
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 354 KiB |
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
@ -1,41 +0,0 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Emre on 17/12/2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
|
||||
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 681 B |
@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x3C",
|
||||
"green" : "0x3C",
|
||||
"red" : "0x3C"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xFF",
|
||||
"green" : "0xFF",
|
||||
"red" : "0xFF"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Group 107 (1).png",
|
||||
"filename" : "allCoinBlack.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 681 B After Width: | Height: | Size: 681 B |
Before Width: | Height: | Size: 986 B After Width: | Height: | Size: 986 B |
@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Vector (1).png",
|
||||
"filename" : "blueFlame.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 832 B After Width: | Height: | Size: 832 B |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "GiftEarn.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 32 KiB |
@ -1,6 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Gift.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
After Width: | Height: | Size: 61 KiB |
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "globe.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Mask group (3).png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 5.0 MiB |
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "PinkAllCoin.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 693 B |
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "PinkBadge.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1008 B After Width: | Height: | Size: 1008 B |
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "pinkFlame.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "UserPink.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 843 B |
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Trophy.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 975 B |
@ -0,0 +1,168 @@
|
||||
//
|
||||
// BinaryBetLine.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Lucas Delanier on 10/06/2024.
|
||||
//
|
||||
|
||||
|
||||
import SwiftUI
|
||||
import Model
|
||||
|
||||
struct BinaryBetLine: View {
|
||||
|
||||
@State var showInfos: Bool = false
|
||||
var bet: BetDetail
|
||||
|
||||
var value: CGFloat {
|
||||
let totalParticipations = bet.participations.count
|
||||
let numberOfYes = bet.participations.filter { $0.answer.uppercased() == "YES" }.count
|
||||
let numberOfNo = bet.participations.filter { $0.answer.uppercased() == "NO" }.count
|
||||
if(numberOfNo == 0 && numberOfYes == 0){
|
||||
return 0.5
|
||||
}
|
||||
|
||||
return totalParticipations > 0 ? CGFloat(numberOfYes) / CGFloat(totalParticipations) : 0.0
|
||||
}
|
||||
|
||||
var yesParticipations: [Participation] {
|
||||
bet.participations.filter { $0.answer.uppercased() == "YES" }
|
||||
}
|
||||
|
||||
var noParticipations: [Participation] {
|
||||
bet.participations.filter { $0.answer.uppercased() == "NO" }
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
HStack(spacing: 5) {
|
||||
Text("OUI")
|
||||
.font(.system(size: 25))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AllInColors.blue200)
|
||||
Spacer()
|
||||
Text("NON")
|
||||
.font(.system(size: 25))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AllInColors.pink100)
|
||||
}
|
||||
|
||||
GeometryReader { geometry in
|
||||
ZStack(alignment: .leading) {
|
||||
HStack{
|
||||
Spacer()
|
||||
Rectangle()
|
||||
.frame(width: min(CGFloat(1-self.value) * geometry.size.width, geometry.size.width-20), height: 17)
|
||||
.foregroundStyle(AllInColors.PinkBetGradiant).cornerRadius(999)
|
||||
}
|
||||
|
||||
HStack(spacing: 0) {
|
||||
Rectangle()
|
||||
.frame(width: min(CGFloat(self.value) * geometry.size.width, geometry.size.width-20), height: 17)
|
||||
.foregroundStyle(AllInColors.BlueBetGradiant)
|
||||
.cornerRadius(999)
|
||||
Image("loadingHeartIcon")
|
||||
.resizable()
|
||||
.frame(width: 29, height: 32)
|
||||
.padding(.leading, -10)
|
||||
}
|
||||
|
||||
}
|
||||
.padding(.bottom, 5)
|
||||
}
|
||||
.frame(height: 40)
|
||||
|
||||
HStack {
|
||||
Spacer()
|
||||
Text("bet_status_details_drawer")
|
||||
.textStyle(weight: .medium, color: AllInColors.primaryTextColor, size: 10)
|
||||
Image(showInfos ? "chevronUpIcon" : "chevronDownIcon")
|
||||
.resizable()
|
||||
.frame(width: 10, height: 7)
|
||||
.scaledToFill()
|
||||
}
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
showInfos.toggle()
|
||||
}
|
||||
}
|
||||
.padding(.bottom, 5)
|
||||
.padding(.trailing, 5)
|
||||
|
||||
if showInfos {
|
||||
VStack(spacing: 1) {
|
||||
HStack(spacing: 5) {
|
||||
Image("blueAllCoinIcon")
|
||||
.resizable()
|
||||
.frame(width:12, height: 12)
|
||||
Text(yesParticipations.reduce(0, {x,y in x + y.stake}).description)
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AllInColors.blue200)
|
||||
Spacer()
|
||||
Text(noParticipations.reduce(0, {x,y in x + y.stake}).description)
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AllInColors.pink100)
|
||||
Image("pinkAllCoinIcon")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
}
|
||||
HStack(spacing: 5){
|
||||
Image("bluePersonIcon")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
Text(yesParticipations.count.description)
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AllInColors.blue200)
|
||||
Spacer()
|
||||
Text(noParticipations.count.description)
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AllInColors.pink100)
|
||||
Image("pinkPersonIcon")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
|
||||
}
|
||||
HStack(spacing: 5){
|
||||
Image("blueBadgeIcon")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
Text(yesParticipations.max(by: { $0.stake < $1.stake })?.stake.description ?? "0")
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AllInColors.blue200)
|
||||
Spacer()
|
||||
Text(noParticipations.max(by: { $0.stake < $1.stake })?.stake.description ?? "0")
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AllInColors.pink100)
|
||||
Image("pinkBadgeIcon")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
|
||||
}
|
||||
HStack(spacing: 5){
|
||||
Image("blueTrophyIcon")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
Text("1.2")
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AllInColors.blue200)
|
||||
Spacer()
|
||||
Text("1.2")
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(AllInColors.pink100)
|
||||
Image("pinkTrophyIcon")
|
||||
.resizable()
|
||||
.frame(width:12, height: 12)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
//
|
||||
// ChoiceFinalAnswerCell.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Lucas Delanier on 29/01/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import Model
|
||||
|
||||
struct ChoiceFinalAnswerCell: View {
|
||||
|
||||
var selected = false
|
||||
var answer: AnswerDetail
|
||||
var rawColor = AllInColors.blueAccentColor
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
HStack {
|
||||
Spacer()
|
||||
Text(answer.response)
|
||||
.textStyle(weight: .bold, color: selected ? .white : rawColor, size: 40)
|
||||
.padding(.vertical, 10)
|
||||
Spacer()
|
||||
}
|
||||
HStack {
|
||||
Spacer()
|
||||
OddCapsule(
|
||||
backgroundColor: selected ? .white : AllInColors.purpleAccentColor,
|
||||
foregroundColor: selected ? AllInColors.purpleAccentColor : .white,
|
||||
odd: answer.odds
|
||||
)
|
||||
.padding(.trailing, 20)
|
||||
.scaleEffect(0.9)
|
||||
}
|
||||
}
|
||||
.background(selected ? AllInColors.purpleAccentColor : .white)
|
||||
.cornerRadius(17)
|
||||
.scaleEffect(selected ? 1.02 : 1)
|
||||
.animation(.easeInOut(duration: 0.3), value: selected)
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
//
|
||||
// CustomBetLine.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Lucas Delanier on 10/06/2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Model
|
||||
|
||||
struct CustomBetLine: View {
|
||||
|
||||
@State var showInfos: [String: Bool] = [:]
|
||||
var bet: BetDetail
|
||||
|
||||
var participationsForAnswer: [String: [Participation]] {
|
||||
Dictionary(grouping: bet.participations, by: { $0.answer.uppercased() })
|
||||
}
|
||||
|
||||
var sortedAnswers: [AnswerDetail] {
|
||||
bet.answers.sorted { $0.totalParticipants > $1.totalParticipants }
|
||||
}
|
||||
|
||||
func getTextStyle(for answer: AnswerDetail) -> Font.Weight {
|
||||
return answer == sortedAnswers.first ? .bold : .light
|
||||
}
|
||||
|
||||
func getColor(for answer: AnswerDetail) -> Color {
|
||||
return answer == sortedAnswers.first ? AllInColors.pinkAccentColor : AllInColors.blueAccentColor
|
||||
}
|
||||
|
||||
func getGradiant(for answer: AnswerDetail) -> LinearGradient {
|
||||
return answer == sortedAnswers.first ? AllInColors.PinkBetGradiant : AllInColors.BlueBetLineGradiant
|
||||
}
|
||||
|
||||
func getFlameImage(for answer: AnswerDetail) -> String {
|
||||
return answer == sortedAnswers.first ? "pinkFlameIcon" : "blueFlameIcon"
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
ForEach(sortedAnswers, id: \.response) { answer in
|
||||
let participations = participationsForAnswer[answer.response.uppercased()] ?? []
|
||||
let totalParticipations = bet.participations.count
|
||||
let percentage = totalParticipations > 0 ? CGFloat(participations.count) / CGFloat(totalParticipations) : 0.0
|
||||
|
||||
VStack {
|
||||
HStack {
|
||||
Text(answer.response)
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(getTextStyle(for: answer))
|
||||
.foregroundColor(getColor(for: answer))
|
||||
Spacer()
|
||||
}
|
||||
|
||||
GeometryReader { geometry in
|
||||
ZStack(alignment: .leading) {
|
||||
HStack(spacing: 0) {
|
||||
Rectangle()
|
||||
.frame(width: min(percentage * geometry.size.width, geometry.size.width-20), height: 17)
|
||||
.foregroundStyle(getGradiant(for: answer))
|
||||
.cornerRadius(999, corners: [.topLeft, .bottomLeft])
|
||||
Image(getFlameImage(for: answer))
|
||||
.resizable()
|
||||
.frame(width: 29, height: 32)
|
||||
.padding(.leading, -6)
|
||||
Text("\(Int(percentage * 100))%")
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundStyle(getColor(for: answer))
|
||||
.padding(.leading, 2)
|
||||
}
|
||||
}
|
||||
.padding(.bottom, 5)
|
||||
}
|
||||
.frame(height: 40)
|
||||
|
||||
HStack {
|
||||
Spacer()
|
||||
Text("bet_status_details_drawer")
|
||||
.textStyle(weight: .medium, color: AllInColors.primaryTextColor, size: 10)
|
||||
Image(showInfos[answer.response] ?? false ? "chevronUpIcon" : "chevronDownIcon")
|
||||
.resizable()
|
||||
.frame(width: 10, height: 7)
|
||||
.scaledToFill()
|
||||
}
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
showInfos[answer.response, default: false].toggle()
|
||||
}
|
||||
}
|
||||
.padding(.trailing, 5)
|
||||
|
||||
if showInfos[answer.response] ?? false {
|
||||
HStack{
|
||||
VStack(alignment: .leading,spacing: 1) {
|
||||
HStack(spacing: 5) {
|
||||
Image(answer == sortedAnswers.first ? "pinkAllCoinIcon" : "blueAllCoinIcon")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
Text(participations.reduce(0, { x, y in x + y.stake }).description)
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(getColor(for: answer))
|
||||
}
|
||||
HStack(spacing: 5) {
|
||||
Image(answer == sortedAnswers.first ? "pinkPersonIcon" : "bluePersonIcon")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
Text(participations.count.description)
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(getColor(for: answer))
|
||||
}
|
||||
HStack(spacing: 5) {
|
||||
Image(answer == sortedAnswers.first ? "pinkBadgeIcon" : "blueBadgeIcon")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
Text(participations.max(by: { $0.stake < $1.stake })?.stake.description ?? "0")
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(getColor(for: answer))
|
||||
}
|
||||
HStack(spacing: 5) {
|
||||
Image(answer == sortedAnswers.first ? "pinkTrophyIcon" : "blueTrophyIcon")
|
||||
.resizable()
|
||||
.frame(width: 12, height: 12)
|
||||
Text(String(format: "%.2f", answer.odds))
|
||||
.font(.system(size: 15))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(getColor(for: answer))
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
//
|
||||
// OddCapsule.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Lucas Delanier on 03/02/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct OddCapsule: View {
|
||||
var backgroundColor: Color = AllInColors.purpleAccentColor
|
||||
var foregroundColor: Color = AllInColors.whiteColor
|
||||
var odd: Float = 0.0
|
||||
var body: some View {
|
||||
HStack(alignment: .center) {
|
||||
Text("x\(odd, specifier: "%.2f")")
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(foregroundColor)
|
||||
}
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical,5)
|
||||
.background(backgroundColor)
|
||||
.cornerRadius(9999)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct OddCapsule_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
OddCapsule()
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
//
|
||||
// ParticiationCell.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Lucas Delanier on 21/01/2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Model
|
||||
|
||||
struct ParticiationCell: View {
|
||||
@State var participation: Participation?
|
||||
var body: some View {
|
||||
HStack(alignment: .center, spacing: 0){
|
||||
Circle().frame(width: 30, height: 30).foregroundColor(AllInColors.grey700Color).padding(.trailing, 5)
|
||||
Text(participation?.user.username ?? "Unknown")
|
||||
.font(.system(size: 15))
|
||||
.foregroundStyle(AllInColors.grey100Color)
|
||||
.fontWeight(.semibold)
|
||||
Spacer()
|
||||
Text(participation?.stake.description ?? "NaN")
|
||||
.font(.system(size: 18))
|
||||
.foregroundStyle(AllInColors.lightPurpleColor)
|
||||
.fontWeight(.bold).padding(.trailing, 5)
|
||||
Image("PurpleAllCoin").resizable().frame(width: 11, height: 12)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
//
|
||||
// userPicture.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Lucas Delanier on 04/06/2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
struct UserPicture: View {
|
||||
var picture: String?
|
||||
var username: String
|
||||
var size: CGFloat
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
if let pictureURL = picture {
|
||||
userImage(url: pictureURL)
|
||||
} else {
|
||||
placeholderImage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor private func userImage(url: String) -> some View {
|
||||
AsyncCachedImage(url: URL(string: url)) { image in
|
||||
image
|
||||
.resizable()
|
||||
.frame(width: size, height: size)
|
||||
.clipShape(Circle())
|
||||
} placeholder: {
|
||||
placeholderImage
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private var placeholderImage: some View {
|
||||
Circle()
|
||||
.foregroundColor(.gray)
|
||||
.frame(width: size, height: size)
|
||||
.overlay(
|
||||
Text(username.prefix(2).uppercased())
|
||||
.fontWeight(.medium)
|
||||
.foregroundStyle(.white)
|
||||
.font(.system(size: fontSize(for: size)))
|
||||
)
|
||||
}
|
||||
|
||||
private func fontSize(for diameter: CGFloat) -> CGFloat {
|
||||
let fontScaleFactor: CGFloat = 0.45
|
||||
return diameter * fontScaleFactor
|
||||
}
|
||||
}
|
||||
|
||||
struct UserPicture_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
UserPicture(picture: nil, username: "Lucas", size: 100)
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
//
|
||||
// Delegates.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Emre on 22/02/2024.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
||||
if let selectedAction = options.shortcutItem {
|
||||
QuickAction.selectedAction = selectedAction
|
||||
}
|
||||
let sceneConfiguration = UISceneConfiguration(name: "Quick Action Scene", sessionRole: connectingSceneSession.role)
|
||||
sceneConfiguration.delegateClass = QuickActionSceneDelegate.self
|
||||
return sceneConfiguration
|
||||
}
|
||||
}
|
||||
|
||||
class QuickActionSceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
||||
QuickAction.selectedAction = shortcutItem
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
//
|
||||
// QuickAction.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Emre on 22/02/2024.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
enum QuickAction {
|
||||
static var selectedAction: UIApplicationShortcutItem?
|
||||
|
||||
static var homeuserInfo: [String : NSSecureCoding] {
|
||||
["name" : "Bet" as NSSecureCoding]
|
||||
}
|
||||
|
||||
static var createuserInfo: [String : NSSecureCoding] {
|
||||
["name" : "CreationBet" as NSSecureCoding]
|
||||
}
|
||||
|
||||
static var frienduserInfo: [String : NSSecureCoding] {
|
||||
["name" : "Friends" as NSSecureCoding]
|
||||
}
|
||||
|
||||
static var rankuserInfo: [String : NSSecureCoding] {
|
||||
["name" : "Ranking" as NSSecureCoding]
|
||||
}
|
||||
|
||||
static var allShortcutItems: [UIApplicationShortcutItem] = {
|
||||
var shortcuts: [UIApplicationShortcutItem] = []
|
||||
|
||||
if AppStateContainer.shared.loggedState.connectedUser {
|
||||
shortcuts.append(UIApplicationShortcutItem(type: "home", localizedTitle: "Coins : " + String(AppStateContainer.shared.user?.nbCoins ?? 0), localizedSubtitle: "", icon: UIApplicationShortcutIcon(templateImageName: "allCoinBlackIcon"), userInfo: homeuserInfo))
|
||||
}
|
||||
|
||||
shortcuts.append(contentsOf: [
|
||||
UIApplicationShortcutItem(type: "create", localizedTitle: "Créer un pari", localizedSubtitle: "", icon: UIApplicationShortcutIcon(systemImageName: "pencil.circle"), userInfo: createuserInfo),
|
||||
UIApplicationShortcutItem(type: "friend", localizedTitle: "Voir mes amis", localizedSubtitle: "", icon: UIApplicationShortcutIcon(systemImageName: "person.2.square.stack"), userInfo: frienduserInfo),
|
||||
UIApplicationShortcutItem(type: "ranking", localizedTitle: "Classement", localizedSubtitle: "Où en suis-je ?", icon: UIApplicationShortcutIcon(systemImageName: "rosette"), userInfo: rankuserInfo)
|
||||
])
|
||||
|
||||
return shortcuts
|
||||
}()
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
/*
|
||||
Localizable.strings
|
||||
AllInApp
|
||||
|
||||
Created by Emre on 15/05/2024.
|
||||
|
||||
*/
|
||||
|
||||
/// Core
|
||||
|
||||
"generic_username" = "Username";
|
||||
"generic_email" = "Email";
|
||||
"generic_password" = "Password";
|
||||
"generic_login" = "Login";
|
||||
"generic_logout" = "Logout";
|
||||
"generic_already_have_account" = "Already have an account ?";
|
||||
"generic_register" = "Register";
|
||||
"generic_validate" = "Validate";
|
||||
"generic_ok" = "OK";
|
||||
"generic_error" = "Error";
|
||||
"generic_in_waiting" = "In waiting";
|
||||
"generic_search" = "Search";
|
||||
"generic_add" = "Add";
|
||||
"generic_acccept"="Accept";
|
||||
"generic_decline"="Decline";
|
||||
"generic_delete" = "Delete";
|
||||
"generic_stake" = "Stake";
|
||||
"network_error_text" = "Make sure to be properly connected to the network then try again.";
|
||||
|
||||
/// Bet type
|
||||
|
||||
"bet_type_binary" = "Yes / No";
|
||||
"bet_type_match" = "Sport match";
|
||||
"bet_type_custom" = "Custom answers";
|
||||
|
||||
/// Field error
|
||||
|
||||
"field_error_mandatory" = "This field is mandatory.";
|
||||
"field_error_not_identical" = "The fields are not identical.";
|
||||
"field_error_bad_email" = "Please enter a valid email.";
|
||||
|
||||
/// Drawer
|
||||
|
||||
"drawer_bets" = "Bets";
|
||||
"drawer_best_win" = "Best win";
|
||||
"drawer_nb_friends" = "Friends";
|
||||
"drawer_friends" = "FRIENDS";
|
||||
"drawer_friends_subtitle" = "Challenge your folks by adding them as friends.";
|
||||
"drawer_public_bets" = "PARTICIPATE";
|
||||
"drawer_public_bets_subtitle" = "Browse the most popular bets of the moment.";
|
||||
"drawer_create_a_bet" = "NEW BET";
|
||||
"drawer_create_a_bet_subtitle" = "Create a net bet and get your friends participating.";
|
||||
"drawer_bet_history" = "HISTORY";
|
||||
"drawer_bet_history_subtitle" = "View your current and finished bets.";
|
||||
"drawer_current_bets" = "MY PARTICIPATIONS";
|
||||
"drawer_current_bets_subtitle" = "Manage your bets and reward the winners.";
|
||||
"drawer_ranking" = "RANKING";
|
||||
"drawer_ranking_subtitle" = "Check your ranking among your friends.";
|
||||
|
||||
/// Welcome Page
|
||||
|
||||
"welcome_title" = "Welcome to,";
|
||||
"welcome_subtitle" = "Collect your Allcoins and come bet with your friend to prove who\'s best.";
|
||||
"welcome_join" = "Join";
|
||||
|
||||
/// Register Page
|
||||
|
||||
"register_hello" = "Hello,";
|
||||
"register_hello %@" = "Hello %@,";
|
||||
"register_title" = "We need this!";
|
||||
"register_subtitle" = "Don\'t worry it\'s fast.";
|
||||
"register_error_title" = "Error saving";
|
||||
"register_error_content" = "Registration failed. Try Again.";
|
||||
"register_confirm_password" = "Confirm password";
|
||||
"register_already_used" = "Email or nickname already used.";
|
||||
|
||||
/// Login Page
|
||||
|
||||
"login_title" = "Welcome back !";
|
||||
"login_subtitle" = "We missed you.";
|
||||
"login_error_title" = "Connection error";
|
||||
"login_error_content" = "Failed to login. Please try again.";
|
||||
"login_no_account" = "Don't have an account ?";
|
||||
"login_forgot_password" = "Forgot password ?";
|
||||
"login_bad_credentials" = "Incorrect login or password.";
|
||||
|
||||
/// Bet Creation Page
|
||||
|
||||
"bet_creation_theme_tooltip" = "Usually a common name describing the overall theme of the bet for reference..";
|
||||
"bet_creation_phrase_tooltip" = "Generally the question the participants will answer to.";
|
||||
"bet_creation_register_tooltip" = "After this date, nobody will be able to register anymore.";
|
||||
"bet_creation_bet_end_tooltip" = "After this date, the result will be announced.";
|
||||
"bet_creation_privacy_tooltip" = "Determines who will be able to see the bet.";
|
||||
"bet_creation_question" = "Question";
|
||||
"bet_creation_answer" = "Answer";
|
||||
"bet_creation_publish" = "Publish the bet";
|
||||
"bet_creation_theme" = "Theme";
|
||||
"bet_creation_theme_placeholder" = "Studies, sports, party…";
|
||||
"bet_creation_bet_phrase" = "Bet phrase";
|
||||
"bet_creation_bet_phrase_placeholder" = "Will David be missing this Monday in class ?";
|
||||
"bet_creation_end_registration_date" = "Registration end date";
|
||||
"bet_creation_end_bet_date" = "Bet end date";
|
||||
"bet_creation_bet_privacy" = "Bet privacy";
|
||||
"bet_creation_friends_available_format" = "friends available";
|
||||
"bet_creation_public_bottom_text_1" = "Your BET will be visible by all the users.";
|
||||
"bet_creation_public_bottom_text_2" = "Everyone will be able to join the BET.";
|
||||
"bet_creation_private_bottom_text_1" = "Your BET will only be visible by your friends.";
|
||||
"bet_creation_private_bottom_text_2" = "Only your friends will be able to join the BET.";
|
||||
"bet_creation_bottom_text_3" = "You can invite friends at any moment during the registration period.";
|
||||
"bet_creation_yes_no_bottom_text_1" = "The participants will have to respond with either YES or NO.";
|
||||
"bet_creation_yes_no_bottom_text_2" = "No other answer will be accepted.";
|
||||
"bet_creation_custom_bottom_text_1" = "You are going to fill in the different answers available in this bet.";
|
||||
"bet_creation_custom_bottom_text_2" = "Be careful to be clear and avoid any uncertainties";
|
||||
"bet_creation_error" = "Error while creating the bet.";
|
||||
"bet_creation_success_message" = "Bet created !";
|
||||
"bet_creation_response_title" = "Response title";
|
||||
"bet_creation_max_answers %lld" = "%lld more max.";
|
||||
"bet_creation_error_past_date" = "The registration end date must be later than the current date.";
|
||||
"bet_creation_error_date_order" = "The betting end date must be later than the registration end date.";
|
||||
|
||||
/// Bet page
|
||||
|
||||
"bet_popular" = "Popular";
|
||||
"bet_public" = "Public";
|
||||
"bet_private" = "Private";
|
||||
"bet_invitation" = "Invitation";
|
||||
"bet_current" = "Current";
|
||||
"bet_finished" = "Finished";
|
||||
"bet_starting" = "Starting on";
|
||||
"bet_started" = "Started on";
|
||||
"bet_ends" = "Ends on";
|
||||
"bet_ended" = "Ended on";
|
||||
"bet_participate" = "Participate";
|
||||
"bet_proposed_by_format %@" = "Proposed by %@";
|
||||
"bet_proposed_by_format" = "Proposed by";
|
||||
"bet_players_waiting_format %@" = "%@ players waiting";
|
||||
"bet_players_format" = "players";
|
||||
"bet_points_at_stake_format" = "points at stake";
|
||||
|
||||
/// Bet status
|
||||
|
||||
"bet_status_finished" = "Finished !";
|
||||
"bet_status_in_progress" = "In progress…";
|
||||
"bet_status_waiting" = "Waiting…";
|
||||
"bet_status_unavailable" = "Status unavailable";
|
||||
"bet_status_cancelled" = "Cancelled";
|
||||
"bet_status_place_your_bets" = "Place your bets";
|
||||
"bet_status_participants_list" = "Participants";
|
||||
"bet_status_details_drawer" = "Details";
|
||||
"participation_possible_winnings" = "Possible winnings";
|
||||
"bet_status_stake" = "Gambled";
|
||||
|
||||
/// Bet history
|
||||
|
||||
"bet_history_current_title" = "Current";
|
||||
"bet_history_title" = "History";
|
||||
|
||||
/// Bet confirmation
|
||||
|
||||
"bet_confirmation_text" = "This bet has now ended. You may now distribute the winnings by selecting the right answer.";
|
||||
"bet_confirmation_choose_response" = "Please select the final answer :";
|
||||
|
||||
/// Ranking
|
||||
|
||||
"ranking_title" = "Ranking";
|
||||
|
||||
/// Friends
|
||||
|
||||
"friends_title" = "Friends";
|
||||
"friends_request_sent" = "Request sent";
|
||||
"friends_request"= "Friends Request";
|
||||
|
||||
/// Daily reward
|
||||
|
||||
"daily_reward_title" = "Daily reward";
|
||||
"daily_reward_subtitle" = "Your daily reward is unlocked every day at 00:00 UTC and allows you to get between 10 and 150 Allcoins.";
|
||||
|
||||
/// Notification
|
||||
|
||||
"notification_title_end_bet_date" = "Who will be the winners?";
|
||||
"notification_subtitle_end_bet_date %@" = "The %@ bet has reached its deadline. Go to the app to enter the winning answer.";
|
||||
|
||||
/// Empty Views
|
||||
|
||||
"empty_ranking_title" = "It's a bit empty around here";
|
||||
"empty_ranking_explain" = "Add some friends to display them in the leaderboard";
|
||||
"empty_bets_title"= "No bet matches your search";
|
||||
"empty_friends_title" = "You don't have any friends yet";
|
||||
"empty_friends_explain" = "Add them from this screen";
|
||||
|
||||
/// Error Messages
|
||||
|
||||
"error_title" = "Error: Failed to Load Content.";
|
||||
"error_message" = "The content you are trying to load could not be retrieved. Please check your internet connection and try again";
|
@ -0,0 +1,50 @@
|
||||
//
|
||||
// NotificationService.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Emre on 22/02/2024.
|
||||
//
|
||||
|
||||
import UserNotifications
|
||||
|
||||
struct NotificationItem {
|
||||
var title: String
|
||||
var content: String
|
||||
var interval: TimeInterval
|
||||
}
|
||||
|
||||
class NotificationService: ObservableObject {
|
||||
|
||||
@Published var notifications: [NotificationItem] = []
|
||||
|
||||
func scheduleNotifications() {
|
||||
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
|
||||
if granted {
|
||||
print("Permission for notifications granted.")
|
||||
} else {
|
||||
print("Permission for notifications denied.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func loadNotifications() {
|
||||
for notification in notifications {
|
||||
scheduleNotification(with: notification)
|
||||
}
|
||||
}
|
||||
|
||||
func removeAllNotifications() {
|
||||
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
|
||||
}
|
||||
|
||||
func scheduleNotification(with item: NotificationItem) {
|
||||
let content = UNMutableNotificationContent()
|
||||
content.title = item.title
|
||||
content.body = item.content
|
||||
|
||||
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: item.interval, repeats: false)
|
||||
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
|
||||
|
||||
UNUserNotificationCenter.current().add(request)
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
//
|
||||
// asyncCachedImage.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Lucas Delanier on 06/06/2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@MainActor
|
||||
struct AsyncCachedImage<ImageView: View, PlaceholderView: View>: View {
|
||||
// Input dependencies
|
||||
var url: URL?
|
||||
@ViewBuilder var content: (Image) -> ImageView
|
||||
@ViewBuilder var placeholder: () -> PlaceholderView
|
||||
|
||||
// Downloaded image
|
||||
@State var image: UIImage? = nil
|
||||
|
||||
init(
|
||||
url: URL?,
|
||||
@ViewBuilder content: @escaping (Image) -> ImageView,
|
||||
@ViewBuilder placeholder: @escaping () -> PlaceholderView
|
||||
) {
|
||||
self.url = url
|
||||
self.content = content
|
||||
self.placeholder = placeholder
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
if let uiImage = image {
|
||||
content(Image(uiImage: uiImage))
|
||||
} else {
|
||||
placeholder()
|
||||
.onAppear {
|
||||
Task {
|
||||
image = await downloadPhoto()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Downloads if the image is not cached already
|
||||
// Otherwise returns from the cache
|
||||
private func downloadPhoto() async -> UIImage? {
|
||||
do {
|
||||
guard let url else { return nil }
|
||||
|
||||
// Check if the image is cached already
|
||||
if let cachedResponse = URLCache.shared.cachedResponse(for: .init(url: url)) {
|
||||
return UIImage(data: cachedResponse.data)
|
||||
} else {
|
||||
let (data, response) = try await URLSession.shared.data(from: url)
|
||||
|
||||
// Save returned image data into the cache
|
||||
URLCache.shared.storeCachedResponse(.init(response: response, data: data), for: .init(url: url))
|
||||
|
||||
guard let image = UIImage(data: data) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return image
|
||||
}
|
||||
} catch {
|
||||
print("Error downloading: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
//
|
||||
// BetEndingValidationViewModel.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Emre on 07/02/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import DependencyInjection
|
||||
import Model
|
||||
|
||||
class BetEndingValidationViewModel: ObservableObject {
|
||||
|
||||
var id: String
|
||||
@Inject var manager: Manager
|
||||
@Published var selectedAnswer : String?
|
||||
|
||||
init(id: String) {
|
||||
self.id = id
|
||||
}
|
||||
|
||||
func post() {
|
||||
if let answer = selectedAnswer {
|
||||
manager.addResponse(withIdBet: id, andResponse: answer)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
//
|
||||
// CurrentBetViewModel.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Emre on 31/01/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import DependencyInjection
|
||||
import Model
|
||||
|
||||
class CurrentBetViewModel: ObservableObject {
|
||||
|
||||
@Inject var manager: Manager
|
||||
|
||||
@Published private(set) var bets: [BetDetail] = []
|
||||
|
||||
init() {
|
||||
getItems()
|
||||
}
|
||||
|
||||
func getItems() {
|
||||
manager.getCurrentBets(withIndex: 0, withCount: 20) { bets in
|
||||
DispatchQueue.main.async {
|
||||
self.bets = bets
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
//
|
||||
// BetEndingValidationView.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Lucas Delanier on 29/01/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import Model
|
||||
import StubLib
|
||||
|
||||
struct BetEndingValidationView: View {
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
@StateObject private var viewModel: BetEndingValidationViewModel
|
||||
var betDetail: BetDetail
|
||||
|
||||
init(bet: BetDetail) {
|
||||
self.betDetail = bet
|
||||
self._viewModel = StateObject(wrappedValue: BetEndingValidationViewModel(id: bet.bet.id))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack{
|
||||
GeometryReader { geometry in
|
||||
|
||||
InfiniteScroller(contentWidth: geometry.size.width) {
|
||||
Image("marquee")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
}
|
||||
VStack {
|
||||
ZStack(alignment: .topLeading){
|
||||
HStack{
|
||||
Spacer()
|
||||
Image("allinIcon")
|
||||
.resizable()
|
||||
.frame(width: 35, height: 35)
|
||||
Spacer()
|
||||
}
|
||||
|
||||
Image("crossIcon")
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25)
|
||||
.onTapGesture {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
ReviewCard(bet: betDetail.bet, amount: 0, isWin: false)
|
||||
.padding(.top, 20)
|
||||
.padding(.bottom, 10)
|
||||
Text("bet_confirmation_text")
|
||||
.textStyle(weight: .regular, color: AllInColors.grey800Color, size: 13)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
Text("bet_confirmation_choose_response")
|
||||
.font(.system(size: 17))
|
||||
.foregroundStyle(.white)
|
||||
.fontWeight(.bold)
|
||||
.padding(.top, 30)
|
||||
.padding(.bottom, 10)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
VStack(spacing: 14){
|
||||
ForEach(betDetail.answers) { answer in
|
||||
ChoiceFinalAnswerCell(selected : answer.response == viewModel.selectedAnswer, answer: answer).onTapGesture {
|
||||
if(viewModel.selectedAnswer == answer.response){
|
||||
viewModel.selectedAnswer = nil
|
||||
}
|
||||
else {
|
||||
viewModel.selectedAnswer = answer.response
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
Button {
|
||||
dismiss()
|
||||
viewModel.post()
|
||||
} label: {
|
||||
Text("generic_validate")
|
||||
.font(.system(size: 23))
|
||||
.foregroundColor(.white)
|
||||
.fontWeight(.bold)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 3)
|
||||
}
|
||||
.opacity(viewModel.selectedAnswer != nil ? 1 : 0)
|
||||
.animation(.easeInOut(duration: 0.3), value: viewModel.selectedAnswer != nil)
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(AllInColors.purpleAccentColor)
|
||||
}
|
||||
.padding([.all],20)
|
||||
}
|
||||
|
||||
}.background(AllInColors.greyDarkColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,41 @@
|
||||
//
|
||||
// CurrentBetView.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Emre on 31/01/2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Model
|
||||
|
||||
struct CurrentBetView: View {
|
||||
|
||||
@StateObject private var viewModel = CurrentBetViewModel()
|
||||
@Binding var showMenu: Bool
|
||||
@State private var showingSheet = false
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .center, spacing: 0) {
|
||||
|
||||
TopBar(showMenu: self.$showMenu)
|
||||
ScrollView(showsIndicators: false) {
|
||||
Text("bet_history_current_title")
|
||||
.textStyle(weight: .bold, color: AllInColors.grey500Color, size: 25)
|
||||
.padding([.top],15)
|
||||
VStack(spacing: 20){
|
||||
ForEach(viewModel.bets, id: \.bet.id) { (betDetail: BetDetail) in
|
||||
ReviewCard(bet: betDetail.bet, amount: betDetail.userParticipation?.stake ?? 0, isWin: false)
|
||||
}
|
||||
}
|
||||
.padding([.trailing, .leading, .bottom],25)
|
||||
}
|
||||
.refreshable {
|
||||
viewModel.getItems()
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.edgesIgnoringSafeArea(.bottom)
|
||||
.background(AllInColors.backgroundColor)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,129 @@
|
||||
//
|
||||
// DailyGiftPage.swift
|
||||
// AllIn
|
||||
//
|
||||
// Created by Emre on 02/02/2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct DailyGiftPage: View {
|
||||
|
||||
enum Step {
|
||||
case first
|
||||
case second
|
||||
case end
|
||||
}
|
||||
|
||||
@State private var step: Step = .first
|
||||
@State private var scale: CGFloat = 1.0
|
||||
@State private var scale2: CGFloat = 0
|
||||
@State private var rotate: CGFloat = 1
|
||||
@Binding var show: Bool
|
||||
@Binding var gain: Int
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
LinearGradient(
|
||||
gradient: Gradient(colors: [
|
||||
Color.black.opacity(0.6),
|
||||
Color.black.opacity(0.9)
|
||||
]),
|
||||
startPoint: .top,
|
||||
endPoint: .bottom
|
||||
)
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
|
||||
VStack {
|
||||
Text("daily_reward_title")
|
||||
.textStyle(weight: .bold, color: .white, size: 25)
|
||||
|
||||
Group {
|
||||
switch step {
|
||||
case .first:
|
||||
Image("giftImage")
|
||||
.transition(
|
||||
.asymmetric(
|
||||
insertion: .scale(scale: 0.9).combined(with: .opacity),
|
||||
removal: .scale(scale: 1.7).combined(with: .opacity))
|
||||
)
|
||||
.scaleEffect(scale)
|
||||
.rotationEffect(.degrees(Double(scale) * 10), anchor: .center)
|
||||
.rotationEffect(.degrees(-10), anchor: .center)
|
||||
.onAppear {
|
||||
withAnimation(Animation.easeInOut(duration: 1).repeatForever()) {
|
||||
scale = 1.1
|
||||
}
|
||||
}
|
||||
case .second:
|
||||
ZStack {
|
||||
Image("giftEarnImage")
|
||||
.rotationEffect(.degrees(Double(rotate) * 10), anchor: .center)
|
||||
.rotationEffect(.degrees(-10), anchor: .center)
|
||||
.onAppear {
|
||||
withAnimation(Animation.easeInOut(duration: 1).repeatForever()) {
|
||||
rotate = 1.3
|
||||
}
|
||||
}
|
||||
HStack {
|
||||
Text("+" + gain.description)
|
||||
.textStyle(weight: .black, color: .white, size: 55)
|
||||
Image("allcoinWhiteIcon")
|
||||
.resizable()
|
||||
.frame(width: 40, height: 40)
|
||||
}
|
||||
}
|
||||
.scaleEffect(scale2)
|
||||
.onAppear {
|
||||
withAnimation(Animation.easeInOut(duration: 0.8)) {
|
||||
scale2 = 1.0
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
|
||||
withAnimation {
|
||||
show = false
|
||||
step = .first
|
||||
}
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
scale2 = 0
|
||||
}
|
||||
default :
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
.frame(width: geometry.size.width * 0.8, height: geometry.size.height * 0.4)
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
switch step {
|
||||
case .first:
|
||||
step = .second
|
||||
withAnimation {
|
||||
AppStateContainer.shared.user?.nbCoins += gain
|
||||
}
|
||||
case .second:
|
||||
show = false
|
||||
step = .end
|
||||
case .end:
|
||||
step = .first
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text("daily_reward_subtitle")
|
||||
.textStyle(weight: .medium, color: .white, size: 13)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal, geometry.size.width * 0.13)
|
||||
.opacity(0.67)
|
||||
}
|
||||
.frame(width: geometry.size.width, height: geometry.size.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct DailyGiftPage_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
DailyGiftPage(show: .constant(false), gain: .constant(20))
|
||||
}
|
||||
}
|