<commit_before>//
//  SetttingsView.swift
//  Conjugar
//
//  Created by <NAME> on 11/3/19.
//  Copyright © 2019 <NAME>. All rights reserved.
//

import SwiftUI

struct SettingsView: View {
  static let englishTitle = "Settings"

  @State private var isGameCenterButtonOffScreen = true
  @State private var isGameCenterUIHidden = false
  @State private var rateReviewDescription = ""

  @EnvironmentObject var current: World
  @ObservedObject var store = SelectionStore()

  private let offScreenButtonScale: CGFloat = 1.5
  private let animationDuration = 1.0

  init() {
    UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: Colors.yellow], for: .selected)
    UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: Colors.yellow], for: .normal)
  }

  var body: some View {
    ZStack {
      Color.black
        .edgesIgnoringSafeArea(.all)

      VStack(alignment: .center, spacing: 16) {
        Text(Localizations.Settings.localizedTitle)
          .modifier(HeadingLabel())

        ScrollView(.vertical) {
          Group {
            Text(Localizations.Settings.region)
              .modifier(SubheadingLabel())

            Picker("", selection: $store.region) {
              ForEach(Region.allCases, id: \.self) { type in
                Text(type.localizedRegion).tag(type)
              }
            }
              .modifier(SegmentedPicker())
              .onAppear {
                self.store.region = self.current.settings.region
                self.store.current = self.current
              }

            Text(Localizations.Settings.regionDescription)
              .modifier(BodyLabel())

            Spacer(minLength: Layout.tripleDefaultSpacing)
          }

          Group {
            Text(Localizations.Settings.difficulty)
              .modifier(SubheadingLabel())

            Picker("", selection: $store.difficulty) {
              ForEach(Difficulty.allCases, id: \.self) { type in
                Text(type.localizedDifficulty).tag(type)
              }
            }
              .modifier(SegmentedPicker())
              .onAppear {
                self.store.difficulty = self.current.settings.difficulty
                self.store.current = self.current
              }

            Text(Localizations.Settings.difficultyDescription)
              .modifier(BodyLabel())

            Spacer(minLength: Layout.tripleDefaultSpacing)
          }

          Group {
            Text("Browse Tú and/or Vos")
              .modifier(SubheadingLabel())

            Picker("", selection: $store.secondSingularBrowse) {
              ForEach(SecondSingularBrowse.allCases, id: \.self) { type in
                Text(type.localizedSecondSingularBrowse).tag(type)
              }
            }
              .modifier(SegmentedPicker())
              .onAppear {
                self.store.secondSingularBrowse = self.current.settings.secondSingularBrowse
                self.store.current = self.current
              }

            Text("This setting determines whether you see tú conjugations, vos conjugations, or both when you browse verb conjugations.")
              .modifier(BodyLabel())

            Spacer(minLength: Layout.tripleDefaultSpacing)
          }

          Group {
            Text(Localizations.Settings.quiz)
              .modifier(SubheadingLabel())

            Picker("", selection: $store.secondSingularQuiz) {
              ForEach(SecondSingularQuiz.allCases, id: \.self) { type in
                Text(type.rawValue).tag(type)
              }
            }
              .modifier(SegmentedPicker())
              .onAppear {
                self.store.secondSingularQuiz = self.current.settings.secondSingularQuiz
                self.store.current = self.current
              }

            Text(Localizations.Settings.quizDescription)
              .modifier(BodyLabel())

            Spacer(minLength: Layout.tripleDefaultSpacing)
          }

          if !isGameCenterUIHidden {
            Group {
              Text(Localizations.Quiz.gameCenter)
                .modifier(SubheadingLabel())

              Button(Localizations.Settings.enable) {
                self.current.settings.userRejectedGameCenter = false

                self.current.gameCenter.authenticate(
                  onViewController: self.current.parentViewController ?? UIViewController(),
                  completion: { authenticated in
                    self.isGameCenterUIHidden = authenticated
                })
              }
                .modifier(StandardButton())
                .onAppear {
                  self.isGameCenterButtonOffScreen = false
                }
                .scaleEffect(isGameCenterButtonOffScreen ? offScreenButtonScale : 1.0)
                .animation(.easeInOut(duration: animationDuration))

              // Does not work in ScrollView.
              // https://www.hackingwithswift.com/quick-start/swiftui/how-to-start-an-animation-immediately-after-a-view-appears
              // @State var scale: CGFloat = 1

//              .scaleEffect(scale)
//              .onAppear {
//                  let baseAnimation = Animation.easeInOut(duration: 1)
//                  let repeated = baseAnimation.repeatForever(autoreverses: true)
//
//                  return withAnimation(repeated) {
//                      self.scale = 0.9
//                  }
//              }

              Text(Localizations.Settings.enableDescription)
                .modifier(BodyLabel())

              Spacer(minLength: Layout.tripleDefaultSpacing)
            }
          }

          Group {
            Text(Localizations.Settings.ratingsAndReviews)
              .modifier(SubheadingLabel())

            Button(Localizations.Settings.rateOrReview) {
              guard let url = URL(string: "https://itunes.apple.com/us/app/immigration/id\(RatingsFetcher.iTunesID)?action=write-review") else {
                return
              }
              UIApplication.shared.open(url, options: [:])
            }
              .modifier(StandardButton())

            if rateReviewDescription != "" {
              Text(rateReviewDescription)
                .modifier(BodyLabel())
            }
          }

          Spacer()
        }
      }
    }
      .onAppear {
        RatingsFetcher.fetchRatingsDescription(completion: { description in
          if description != RatingsFetcher.errorMessage {
            DispatchQueue.main.async {
              self.rateReviewDescription = description
            }
          }
        })

        self.current.analytics.recordVisitation(viewController: "\(SettingsView.self)")

        self.isGameCenterUIHidden = self.current.gameCenter.isAuthenticated
      }
  }
}

final class SelectionStore: ObservableObject {
  var current: World?

  var region: Region = Settings.regionDefault {
    didSet {
      current?.settings.region = region
    }
  }

  var difficulty: Difficulty = Settings.difficultyDefault {
    didSet {
      current?.settings.difficulty = difficulty
    }
  }

  var secondSingularBrowse: SecondSingularBrowse = Settings.secondSingularBrowseDefault {
    didSet {
      current?.settings.secondSingularBrowse = secondSingularBrowse
    }
  }

  var secondSingularQuiz: SecondSingularQuiz = Settings.secondSingularQuizDefault {
    didSet {
      current?.settings.secondSingularQuiz = secondSingularQuiz
    }
  }
}
<commit_msg>continue i18n<commit_after>//
//  SetttingsView.swift
//  Conjugar
//
//  Created by <NAME> on 11/3/19.
//  Copyright © 2019 <NAME>. All rights reserved.
//

import SwiftUI

struct SettingsView: View {
  static let englishTitle = "Settings"

  @State private var isGameCenterButtonOffScreen = true
  @State private var isGameCenterUIHidden = false
  @State private var rateReviewDescription = ""

  @EnvironmentObject var current: World
  @ObservedObject var store = SelectionStore()

  private let offScreenButtonScale: CGFloat = 1.5
  private let animationDuration = 1.0

  init() {
    UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: Colors.yellow], for: .selected)
    UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: Colors.yellow], for: .normal)
  }

  var body: some View {
    ZStack {
      Color.black
        .edgesIgnoringSafeArea(.all)

      VStack(alignment: .center, spacing: 16) {
        Text(Localizations.Settings.localizedTitle)
          .modifier(HeadingLabel())

        ScrollView(.vertical) {
          Group {
            Text(Localizations.Settings.region)
              .modifier(SubheadingLabel())

            Picker("", selection: $store.region) {
              ForEach(Region.allCases, id: \.self) { type in
                Text(type.localizedRegion).tag(type)
              }
            }
              .modifier(SegmentedPicker())
              .onAppear {
                self.store.region = self.current.settings.region
                self.store.current = self.current
              }

            Text(Localizations.Settings.regionDescription)
              .modifier(BodyLabel())

            Spacer(minLength: Layout.tripleDefaultSpacing)
          }

          Group {
            Text(Localizations.Settings.difficulty)
              .modifier(SubheadingLabel())

            Picker("", selection: $store.difficulty) {
              ForEach(Difficulty.allCases, id: \.self) { type in
                Text(type.localizedDifficulty).tag(type)
              }
            }
              .modifier(SegmentedPicker())
              .onAppear {
                self.store.difficulty = self.current.settings.difficulty
                self.store.current = self.current
              }

            Text(Localizations.Settings.difficultyDescription)
              .modifier(BodyLabel())

            Spacer(minLength: Layout.tripleDefaultSpacing)
          }

          Group {
            Text(Localizations.Settings.browse)
              .modifier(SubheadingLabel())

            Picker("", selection: $store.secondSingularBrowse) {
              ForEach(SecondSingularBrowse.allCases, id: \.self) { type in
                Text(type.localizedSecondSingularBrowse).tag(type)
              }
            }
              .modifier(SegmentedPicker())
              .onAppear {
                self.store.secondSingularBrowse = self.current.settings.secondSingularBrowse
                self.store.current = self.current
              }

            Text(Localizations.Settings.browseDescription)
              .modifier(BodyLabel())

            Spacer(minLength: Layout.tripleDefaultSpacing)
          }

          Group {
            Text(Localizations.Settings.quiz)
              .modifier(SubheadingLabel())

            Picker("", selection: $store.secondSingularQuiz) {
              ForEach(SecondSingularQuiz.allCases, id: \.self) { type in
                Text(type.rawValue).tag(type)
              }
            }
              .modifier(SegmentedPicker())
              .onAppear {
                self.store.secondSingularQuiz = self.current.settings.secondSingularQuiz
                self.store.current = self.current
              }

            Text(Localizations.Settings.quizDescription)
              .modifier(BodyLabel())

            Spacer(minLength: Layout.tripleDefaultSpacing)
          }

          if !isGameCenterUIHidden {
            Group {
              Text(Localizations.Quiz.gameCenter)
                .modifier(SubheadingLabel())

              Button(Localizations.Settings.enable) {
                self.current.settings.userRejectedGameCenter = false

                self.current.gameCenter.authenticate(
                  onViewController: self.current.parentViewController ?? UIViewController(),
                  completion: { authenticated in
                    self.isGameCenterUIHidden = authenticated
                })
              }
                .modifier(StandardButton())
                .onAppear {
                  self.isGameCenterButtonOffScreen = false
                }
                .scaleEffect(isGameCenterButtonOffScreen ? offScreenButtonScale : 1.0)
                .animation(.easeInOut(duration: animationDuration))

              // Does not work in ScrollView.
              // https://www.hackingwithswift.com/quick-start/swiftui/how-to-start-an-animation-immediately-after-a-view-appears
              // @State var scale: CGFloat = 1

//              .scaleEffect(scale)
//              .onAppear {
//                  let baseAnimation = Animation.easeInOut(duration: 1)
//                  let repeated = baseAnimation.repeatForever(autoreverses: true)
//
//                  return withAnimation(repeated) {
//                      self.scale = 0.9
//                  }
//              }

              Text(Localizations.Settings.enableDescription)
                .modifier(BodyLabel())

              Spacer(minLength: Layout.tripleDefaultSpacing)
            }
          }

          Group {
            Text(Localizations.Settings.ratingsAndReviews)
              .modifier(SubheadingLabel())

            Button(Localizations.Settings.rateOrReview) {
              guard let url = URL(string: "https://itunes.apple.com/us/app/immigration/id\(RatingsFetcher.iTunesID)?action=write-review") else {
                return
              }
              UIApplication.shared.open(url, options: [:])
            }
              .modifier(StandardButton())

            if rateReviewDescription != "" {
              Text(rateReviewDescription)
                .modifier(BodyLabel())
            }
          }

          Spacer()
        }
      }
    }
      .onAppear {
        RatingsFetcher.fetchRatingsDescription(completion: { description in
          if description != RatingsFetcher.errorMessage {
            DispatchQueue.main.async {
              self.rateReviewDescription = description
            }
          }
        })

        self.current.analytics.recordVisitation(viewController: "\(SettingsView.self)")

        self.isGameCenterUIHidden = self.current.gameCenter.isAuthenticated
      }
  }
}

final class SelectionStore: ObservableObject {
  var current: World?

  var region: Region = Settings.regionDefault {
    didSet {
      current?.settings.region = region
    }
  }

  var difficulty: Difficulty = Settings.difficultyDefault {
    didSet {
      current?.settings.difficulty = difficulty
    }
  }

  var secondSingularBrowse: SecondSingularBrowse = Settings.secondSingularBrowseDefault {
    didSet {
      current?.settings.secondSingularBrowse = secondSingularBrowse
    }
  }

  var secondSingularQuiz: SecondSingularQuiz = Settings.secondSingularQuizDefault {
    didSet {
      current?.settings.secondSingularQuiz = secondSingularQuiz
    }
  }
}

{'fraction_non_alphanumeric': 0.09331890722207195, 'fraction_numerical': 0.0029753854476602653, 'mean_word_length': 1.7887987931359608, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '896907', 'n_tokens_mistral': 4048, 'n_tokens_neox': 3792, 'n_words': 598}