using Core.KV; using game.KV; using System.Globalization; using System.Threading.Tasks; using asap.core; using Game; using UnityEngine; using System; namespace game { public interface ISettingService { bool Music { get; set; } bool Sound { get; set; } bool Vibration { get; set; } bool Notice { get; } string Lang { get; set; } int UnitOfWeight { get; set; } bool ShowNotice { get; set; } bool CheckRequestPermission(); } public class DefaultSettingService : ISettingService { bool _music; bool _sound; bool _vibration; string _lang; int _unitOfWeight = 1; bool? _showNotice; private readonly bool requiresFormalKV; private KvSessionOwner promptOwner; internal bool HasKVPromptOwner => promptOwner != null; // Preserve only our key/owner/error metadata across void UI boundaries, never platform payloads. internal static InvalidOperationException PromptFailure(string message) { var error = new InvalidOperationException(message); error.Data["B01PromptDiagnostic"] = message; return error; } internal static void LogPromptFailure(Exception error) => Debug.LogError( error.Data["B01PromptDiagnostic"] as string ?? "Notification prompt stopped: " + error.GetType().Name); public DefaultSettingService() : this(false) { } internal DefaultSettingService(bool formalKV) { requiresFormalKV = formalKV; } // The frozen startup selection is supplied before login; this instance can never change owners. internal void PreflightFormalPromptOwner(KvSessionOwner owner) { if (!requiresFormalKV || owner == null || (promptOwner != null && !ReferenceEquals(promptOwner, owner))) { throw PromptFailure("ShowNotice: formal owner mismatch."); } var read = KvSaveStore.ReadKV(owner, "ShowNotice"); if (!read.Success) { throw PromptFailure($"ShowNotice owner={owner.OwnerInstanceId}: {read.Error}"); } } internal void BindFormalPromptOwner(KvSessionOwner owner) { PreflightFormalPromptOwner(owner); if (promptOwner == null) { promptOwner = owner; } RequirePromptOwner(); } internal void ReleaseFailedPromptOwner(KvSessionOwner owner) { if (promptOwner == null) { return; } if (!ReferenceEquals(promptOwner, owner) || owner.Status != KVSyncStatus.Closed) { throw PromptFailure("ShowNotice: failed owner has not closed."); } promptOwner = null; _showNotice = null; } internal void RequirePromptOwner() { if (promptOwner != null) ReadPrompt(); else if (requiresFormalKV) throw PromptFailure("ShowNotice: formal owner not handed off."); } private PlayerSaveReadResult ReadPrompt() { var read = KvSaveStore.ReadKV(promptOwner, "ShowNotice"); if (!read.Success) { throw PromptFailure($"ShowNotice owner={promptOwner.OwnerInstanceId}: {read.Error}"); } return read; } public bool Music { set { if (value != _music) { PlayerPrefs.SetInt("Music", value ? 1 : 0); _music = value; GContext.Publish(new SoundMuteEvent(0)); } } get { return _music; } } public bool Sound { set { if (value != _sound) { PlayerPrefs.SetInt("Sound", value ? 1 : 0); _sound = value; GContext.Publish(new SoundMuteEvent(1)); } } get { return _sound; } } public bool Vibration { set { if (value != _vibration) { PlayerPrefs.SetInt("Vibration", value ? 1 : 0); _vibration = value; } } get { return _vibration; } } public bool Notice { get { return GContext.container.Resolve().IsNoticeOpen; } } public string Lang { set { if (value != _lang) { PlayerPrefs.SetString("Lang", value); _lang = value; } } get { return _lang; } } public int UnitOfWeight { set { if (value != _unitOfWeight) { PlayerPrefs.SetInt("UnitOfWeight", value); _unitOfWeight = value; } } get { return _unitOfWeight; } } public bool ShowNotice { get { if (requiresFormalKV && promptOwner == null) { RequirePromptOwner(); } if (promptOwner != null) { var read = ReadPrompt(); _showNotice ??= read.Found == true && read.Value == "1"; return _showNotice.Value; } _showNotice ??= PlayFabMgr.Instance.GetLocalData("ShowNotice") == "1"; return _showNotice.Value; } set { if (requiresFormalKV && promptOwner == null) { RequirePromptOwner(); } if (promptOwner != null) { ReadPrompt(); if (value != _showNotice) { _showNotice = value; var promptEdit = KvSaveStore.WriteKV(promptOwner, "ShowNotice", value ? "1" : "0"); if (!promptEdit.Success) { throw PromptFailure($"ShowNotice owner={promptOwner.OwnerInstanceId}: {promptEdit.Error}; uncertain={promptEdit.LocalCommitMayHaveSucceeded}"); } } RequirePromptOwner(); return; } if (value != _showNotice) { _showNotice = value; PlayFabMgr.Instance.UpdateUserDataValue("ShowNotice", value ? "1" : "0"); } } } public void Init(cfg.Tables tables) { if (!PlayerPrefs.HasKey("Music")) { var globalConfig = tables.TbGlobalConfig; Music = globalConfig.MusicSetting; Sound = globalConfig.SoundSetting; Vibration = true; CultureInfo info = System.Globalization.CultureInfo.CurrentUICulture; string Language = info.TwoLetterISOLanguageName; if (Language == "zh") { if (info.DisplayName.Contains("Simplified")) { Language = "zh_Hans"; } else { Language = "zh_Hant"; } } Lang = Language; } else { _music = PlayerPrefs.GetInt("Music") == 1; _sound = PlayerPrefs.GetInt("Sound") == 1; _vibration = PlayerPrefs.GetInt("Vibration") == 1; _lang = PlayerPrefs.GetString("Lang"); _unitOfWeight = PlayerPrefs.GetInt("UnitOfWeight"); } } public bool CheckRequestPermission() { if (ShowNotice) { return false; } var notification = GContext.container.Resolve(); if (notification is LocalNotificationService local) local.RequirePromptOwner(this); if (notification.IsNoticeOpen) { ShowNotice = true; return false; } return true; } private async Task AskPermission() { var result = new TaskCompletionSource(); var callbacks = new UnityEngine.Android.PermissionCallbacks(); callbacks.PermissionGranted += (x) => result.SetResult(true); callbacks.PermissionDeniedAndDontAskAgain += (x) => result.SetResult(false); callbacks.PermissionDenied += (x) => result.SetResult(false); UnityEngine.Android.Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS", callbacks); return await result.Task; } } }