LNAppConfig.swift 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. //
  2. // LNAppConfig.swift
  3. // Lanu
  4. //
  5. // Created by OneeChan on 2025/11/6.
  6. //
  7. import Foundation
  8. import Combine
  9. enum LNAppEnvType: Codable, CaseIterable {
  10. case test
  11. case official
  12. var text: String {
  13. switch self {
  14. case .test: "测试环境"
  15. case .official: "线上环境"
  16. }
  17. }
  18. }
  19. enum LNAppLanguage: Codable {
  20. case chiness
  21. case english
  22. case indonesian
  23. var text: String {
  24. switch self {
  25. case .chiness: "中文"
  26. case .english: "English"
  27. case .indonesian: "Bahasa Indonesia"
  28. }
  29. }
  30. var bundleName: String {
  31. switch self {
  32. case .chiness: "zh-Hans"
  33. case .english: "en"
  34. case .indonesian: "id"
  35. }
  36. }
  37. var languageCode: String {
  38. switch self {
  39. case .chiness: "zh"
  40. case .english: "en"
  41. case .indonesian: "id"
  42. }
  43. }
  44. var countryCode: String {
  45. switch self {
  46. case .chiness: "CN"
  47. case .english: "US"
  48. case .indonesian: "ID"
  49. }
  50. }
  51. var isSelected: Bool {
  52. self == LNAppConfig.shared.curLang
  53. }
  54. static var available: [LNAppLanguage] {
  55. [.chiness, .english, .indonesian]
  56. }
  57. }
  58. class LNAppConfig {
  59. static var shared = LNAppConfig()
  60. @Published
  61. private(set) var hasNewVersion = false
  62. private(set) var isForeground = true
  63. var curEnv: LNAppEnvType = LNUserDefaults[.appEnv, .official] {
  64. didSet {
  65. LNUserDefaults[.appEnv] = curEnv
  66. }
  67. }
  68. var countryCode: String {
  69. if #available(iOS 16.0, *) {
  70. Locale.current.region?.identifier ?? ""
  71. } else {
  72. Locale.current.regionCode ?? ""
  73. }
  74. }
  75. private static var defaultLanguage: LNAppLanguage {
  76. let lang = Locale.preferredLanguages.first ?? "en"
  77. return if lang == LNAppLanguage.chiness.bundleName {
  78. .chiness
  79. } else if lang == LNAppLanguage.indonesian.bundleName {
  80. .indonesian
  81. } else {
  82. .english
  83. }
  84. }
  85. var curLang: LNAppLanguage = LNUserDefaults[.appLanguage, defaultLanguage] {
  86. didSet {
  87. guard oldValue != curLang else { return }
  88. LNUserDefaults[.appLanguage] = curLang
  89. notifyLanguageChanged()
  90. }
  91. }
  92. var languageBundleMap: [LNAppLanguage: Bundle] = {
  93. LNAppLanguage.available.reduce(into: [LNAppLanguage: Bundle](), { result, language in
  94. let bundle = if let path = Bundle.main.path(forResource: language.bundleName, ofType: "lproj"),
  95. let bundle = Bundle(path: path) {
  96. bundle
  97. } else {
  98. Bundle.main
  99. }
  100. result[language] = bundle
  101. })
  102. }()
  103. var languageBundle: Bundle {
  104. languageBundleMap[curLang] ?? Bundle.main
  105. }
  106. init() {
  107. checkNewVersion()
  108. LNEventDeliver.addObserver(self)
  109. NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { [weak self] _ in
  110. guard let self else { return }
  111. isForeground = false
  112. }
  113. NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { [weak self] _ in
  114. guard let self else { return }
  115. isForeground = true
  116. }
  117. }
  118. }
  119. extension LNAppConfig {
  120. func jumpToAppStore() {
  121. let appStoreJumpURL = "https://apps.apple.com/us/app/gamigo/id6756352551?action=write-review"
  122. guard let url = URL(string: appStoreJumpURL) else { return }
  123. if UIApplication.shared.canOpenURL(url) {
  124. UIApplication.shared.open(url, options: [:], completionHandler: nil)
  125. }
  126. }
  127. private func checkNewVersion() {
  128. let appStoreLookupURL = "https://itunes.apple.com/lookup?bundleId=\(curAppBundleIdentifier)"
  129. guard let url = URL(string: appStoreLookupURL) else {
  130. return
  131. }
  132. let task = URLSession.shared.dataTask(with: url)
  133. { [weak self] data, response,
  134. error in
  135. guard let self = self else { return }
  136. guard error == nil,
  137. let data else {
  138. return
  139. }
  140. if let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
  141. let results = json["results"] as? [[String: Any]],
  142. let appStoreVersion = results.first?["version"] as? String {
  143. hasNewVersion = curAppVersion != appStoreVersion
  144. }
  145. }
  146. task.resume()
  147. }
  148. }
  149. extension LNAppConfig: LNNetworkMonitorNotify {
  150. func onNetworkStateChanged(state: LNNetworkState) {
  151. if case .available = state {
  152. checkNewVersion()
  153. }
  154. }
  155. }
  156. extension LNAppConfig {
  157. private func notifyLanguageChanged() {
  158. let curLang = self.curLang
  159. LNEventDeliver.notifyEvent {
  160. ($0 as? LNAppMainEvent)?.onAppLanguageChanged(newLanguage: curLang)
  161. }
  162. }
  163. }