Newer Version Available
Game Zone UI Customization for iOS
Spinner Customization
The game zone UI components are available in the LoyaltyMobileSDK-iOS/SampleApps/MyNTORewards/MyNTORewards/GameZone package.
Customize the spinner components, such as the wheel size, frame width and color, wheel segments, spin button, and more in the FortuneWheelView.swift file. Here are all the parameters you can modify.
1VStack {
2 HStack {
3 Button {
4 // Invalidating the timer to avoid unintended navigation because of the timer
5 timer?.invalidate()
6 isSpinning ? nil : dismiss()
7 } label: {
8 Image("ic-backarrow")
9 }
10 .padding(.leading, 20)
11 .padding(.bottom, 10)
12 .frame(width: 30, height: 30)
13
14 Spacer()
15 }
16 ZStack {
17 Color.theme.accent
18 VStack {
19 VStack(spacing: 10) {
20 Text(gameDefinitionModel?.name ?? StringConstants.Gamification.spinaWheelHeaderLabel)
21 .font(.gameHeaderTitle)
22
23 Text(gameDefinitionModel?.description ?? StringConstants.Gamification.spinaWheelSubHeaderLabel)
24 .font(.gameHeaderSubTitle)
25 }
26 .padding(30)
27
28 Spacer()
29 ZStack {
30 // Fortune Wheel Segments
31 ZStack {
32 if let colors: [Color] = viewModel.getWheelColors(gameModel: gameDefinitionModel),
33 let labels: [LocalizedStringKey] = gameDefinitionModel?.gameRewards.map({LocalizedStringKey($0.name)}) {
34 ForEach(0..<colors.count, id: \.self) { index in
35 let startAngle = (360.0 / Double(colors.count) * Double(index)) - 90.0
36 let endAngle = (360.0 / Double(colors.count) * Double(index + 1)) - 90.0
37 WheelSegment(startAngle: startAngle,
38 endAngle: endAngle,
39 color: colors[index],
40 label: labels[index])
41 }
42 }
43 }
44 .overlay {
45 ZStack {
46 Circle()
47 .strokeBorder(Color.theme.fortuneWheelStrokeColor, lineWidth: 5)
48 .frame(width: 316, height: 316)
49 Circle()
50 .strokeBorder(Color.theme.fortuneWheelSecondaryStrokeColor, lineWidth: 1)
51 .frame(width: 307, height: 307)
52 }
53 }
54 .rotationEffect(Angle(degrees: rotationAngle))
55 .animation(isSpinning ? Animation.easeOut(duration: gameDefinitionModel?.timeoutDuration ?? 15)
56 .delay(0)
57 .repeatForever(autoreverses: false) : .default, value: isSpinning)
58
59 // Triangle Arrow Indicator
60 ZStack {
61 Triangle()
62 .fill(Color.white)
63 .frame(width: 70, height: 70) // Increase these dimensions by the stroke width
64 .offset(y: -40)
65
66 Triangle()
67 .fill(Color.theme.wheelIndicatorBackground)
68 .frame(width: 60, height: 60)
69 .offset(y: -35)
70 }
71
72 // Spin Button
73 Button {
74 playGame()
75 } label: {
76 userStartedSpinning ?
77 Text(StringConstants.Gamification.tapSpinButtonLabel).foregroundColor(Color.theme.wheelIndicatorBackground) :
78 Text(StringConstants.Gamification.tapSpinButtonLabel).foregroundColor(.white)
79
80 }
81 .frame(width: 70, height: 70)
82 .background(Color.theme.wheelIndicatorBackground)
83 .clipShape(Circle())
84 .overlay(Circle().stroke(Color.white, lineWidth: 5))
85 .disabled(userStartedSpinning) // Disable the button when spinning
86
87 }
88 .frame(width: 300, height: 300)
89
90 Spacer()
91
92 VStack(spacing: 20) {
93 Text((StringConstants.Gamification.tapSpinaWheeltoPlayLabel))
94 .font(.gameDescTitle)
95 Text(StringConstants.Gamification.spinaWheelBodyLabel)
96 .font(.gameDescText)
97 .multilineTextAlignment(.center)
98 .frame(width: 258)
99 }
100 Spacer()
101 }
102 .foregroundColor(.white)
103 }
104 .cornerRadius(15, corners: [.topLeft, .topRight])
105 .edgesIgnoringSafeArea(.bottom)
106 .fullScreenCover(isPresented: $showAlertForError) {
107 Spacer()
108 ProcessingErrorView(message: "Oops! Something went wrong while processing the request. Try again.")
109 Spacer()
110 Button {
111 timer?.invalidate()
112 isSpinning ? nil : dismiss()
113 } label: {
114 Text(StringConstants.Receipts.tryAgainButton)
115 .frame(maxWidth: .infinity)
116 }
117 .buttonStyle(.borderedProminent)
118 .longFlexibleButtonStyle()
119 }
120 }
121 }For example, to change the spin wheel outer frame width and height, open the LoyaltyMobileSDK-iOS/SampleApps/MyNTORewards/MyNTORewards/GameZone/Views/FortuneWheel/FortuneWheelView.swift file in Xcode, and replace Circle() frame(width: 316, height: 316) with Circle() frame(width: 300, height: 300).
1overlay {
2 ZStack {
3 Circle()
4 .strokeBorder(Color.theme.fortuneWheelStrokeColor, lineWidth: 5)
5 .frame(width: 316, height: 316)
6 Circle()
7 .strokeBorder(Color.theme.fortuneWheelSecondaryStrokeColor, lineWidth: 1)
8 .frame(width: 307, height: 307)
9 }
10 }To change the spin button background color to blue, open the LoyaltyMobileSDK-iOS/SampleApps/MyNTORewards/MyNTORewards/Misc/Color.swift file, and inside the ColorTheme structure, replace let wheelIndicatorBackground = Color("wheelIndicatorBackgroundColor") // #23475F with let wheelIndicatorBackground = Color.blue.
Scratch Card Customization
You can customize the scratch card components, such as the box, canvas, wrapper text, and more in the ScratchCanvasView.kt file. Here are all the properties you can customize:
1private var backButton: some View {
2 HStack {
3 Button {
4 // Invalidating the timer to avoid unintended navigation because of the timer
5 timer?.invalidate()
6 dismiss()
7 } label: {
8 Image("ic-backarrow")
9 }
10 .padding(.leading, 20)
11 .padding(.bottom, 10)
12 .frame(width: 30, height: 30)
13
14 Spacer()
15 }
16 }
17
18 private var titleView: some View {
19 VStack(spacing: 10) {
20 Text(gameDefinitionModel?.name ?? StringConstants.Gamification.scratchCardTitleLabel)
21 .font(.gameHeaderTitle)
22 Text(gameDefinitionModel?.description ?? StringConstants.Gamification.scratchCardSubTitleLabel)
23 .font(.gameHeaderSubTitle)
24 }
25 .padding(30)
26 }
27
28 private var loadingView: some View {
29 Text("Loading...")
30 .foregroundStyle(.white)
31 .font(.system(size: 24))
32 .fontWeight(.bold)
33 .frame(width: cardSize.width, height: cardSize.height)
34 .background(Color.theme.accent)
35 }
36
37 private var rewardText: some View {
38 Text(playGameViewModel.playedGameRewards?.first?.name ?? "--")
39 .font(.largeTitle)
40 .bold()
41 .foregroundStyle(.white)
42 .frame(width: cardSize.width, height: cardSize.height)
43 .background(Color.theme.accent)
44 .zIndex(finishedScratching ? 10 : 0)
45 }
46
47 private var scratchCardWrapperText: some View {
48 Text(String(repeating: (StringConstants.Gamification.scratchCardLabel), count: 70))
49 .font(Font.scratchText)
50 .multilineTextAlignment(.center)
51 .foregroundColor(Color.theme.scratchCardText)
52 .rotationEffect(Angle(degrees: -45))
53 .mask {
54 Rectangle()
55 .frame(width: cardSize.width, height: cardSize.height)
56 .cornerRadius(10)
57 .opacity(finishedScratching ? 0 : 1)
58 }
59 .opacity(finishedScratching ? 0 : 1)
60 }
61
62 private var scratchCardContentView: some View {
63 ZStack {
64 // Purple background with postage stamp border
65 DottedBorderRectangle(width: backgroundSize.width,
66 height: backgroundSize.height,
67 color: Color.theme.accent)
68
69 // Grey scratch card
70 Rectangle()
71 .fill(Color.theme.scratchCardBackground)
72 .frame(width: cardSize.width, height: cardSize.height)
73 .cornerRadius(10)
74 .opacity(finishedScratching ? 0 : 1)
75
76 // Text overlay
77 scratchCardWrapperText
78 }
79 }
80
81 private var scratchCardGame: some View {
82 ScratchCardGame(cursorSize: 30, cardSize: cardSize, gameModel: gameDefinitionModel, onFinish: $finishedScratching) {
83 scratchCardContentView
84 } overlayView: {
85 // Reward text
86 switch playGameViewModel.state {
87 case .loaded:
88 rewardText
89 default:
90 loadingView
91 }
92 }
93 .animation(.linear(duration: 0.5), value: playGameViewModel.state)
94 .environmentObject(playGameViewModel)
95 }
96
97 private var descriptionView: some View {
98 VStack(spacing: 20) {
99 Text((StringConstants.Gamification.scratchCardBodyLabel))
100 .font(.gameDescText)
101 .multilineTextAlignment(.center)
102 .frame(width: 258)
103 }
104 }
105}For example, to change the angle of the scratch card wrapper text inside the gray box, open the LoyaltyMobileSDK-iOS/SampleApps/MyNTORewards/MyNTORewards/GameZone/Views/ScrachCard/ScratchCardView.swift file in Xcode, and replace rotationEffect(Angle(degrees: -45)) with rotationEffect(Angle(degrees: -25)) . To change the number of times the text appears inside the gray box, replace Text(String(repeating: (StringConstants.Gamification.scratchCardLabel), count: 70)) with Text(String(repeating: (StringConstants.Gamification.scratchCardLabel), count: 50)) .
1private var scratchCardWrapperText: some View {
2 Text(String(repeating: (StringConstants.Gamification.scratchCardLabel), count: 50))
3 .font(Font.scratchText)
4 .multilineTextAlignment(.center)
5 .foregroundColor(Color.theme.scratchCardText)
6 .rotationEffect(Angle(degrees: -25))
7 .mask {
8 Rectangle()
9 .frame(width: cardSize.width, height: cardSize.height)
10 .cornerRadius(10)
11 .opacity(finishedScratching ? 0 : 1)
12 }
13 .opacity(finishedScratching ? 0 : 1)
14 }