Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions examples/demo/Assets/Resources/Theme.uss
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,35 @@
color: #34A853;
}

.language-dropdown-icon {
font-size: 18px;
color: var(--os-grey-600);
margin-left: 4px;
}

.language-option-list {
max-height: 360px;
}

.language-option {
flex-direction: row;
align-items: center;
min-height: 44px;
}

.language-option-label {
flex-grow: 1;
}

.language-option--selected .language-option-label {
color: var(--os-primary);
}

.language-option-check {
font-size: 18px;
color: var(--os-primary);
}

.guidance-banner {
background-color: var(--os-warning-background);
}
Expand Down
7 changes: 7 additions & 0 deletions examples/demo/Assets/Scripts/Services/PreferencesService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class PreferencesService
private const string KeyExternalUserId = "external_user_id";
private const string KeyLocationShared = "location_shared";
private const string KeyIamPaused = "iam_paused";
private const string KeyLanguage = "language";

public bool ConsentRequired
{
Expand Down Expand Up @@ -40,6 +41,12 @@ public bool IamPaused
set => SetBool(KeyIamPaused, value);
}

public string Language
{
get => GetString(KeyLanguage, "");
set => SetString(KeyLanguage, value);
}

private bool GetBool(string key, bool defaultValue) =>
PlayerPrefs.GetInt(key, defaultValue ? 1 : 0) == 1;

Expand Down
78 changes: 78 additions & 0 deletions examples/demo/Assets/Scripts/UI/Dialogs/LanguagePickerDialog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using OneSignalDemo.Services;
using UnityEngine.UIElements;

namespace OneSignalDemo.UI.Dialogs
{
public class LanguagePickerDialog : DialogBase
{
private readonly IReadOnlyList<KeyValuePair<string, string>> _options;
private readonly string _selectedCode;
private readonly Action<string> _onSelected;

/// <param name="options">Display name to language code pairs.</param>
public LanguagePickerDialog(
IReadOnlyList<KeyValuePair<string, string>> options,
string selectedCode,
Action<string> onSelected
)
{
_options = options;
_selectedCode = selectedCode ?? "";
_onSelected = onSelected;
}

protected override void BuildContent(VisualElement container)
{
var title = new Label("Language");
title.AddToClassList("dialog-title");
title.AddToClassList("text-dialog-title");
container.Add(title);

var list = new ScrollView(ScrollViewMode.Vertical);
list.name = "language_option_list";
list.AddToClassList("language-option-list");

foreach (var option in _options)
{
var code = option.Value;
var row = new VisualElement();
row.name = $"language_option_{(code.Length == 0 ? "default" : code)}";
row.AddToClassList("language-option");

var label = new Label(option.Key);
label.AddToClassList("language-option-label");
label.AddToClassList("text-card-label");
row.Add(label);

if (code == _selectedCode)
{
row.AddToClassList("language-option--selected");
var check = new Label(MaterialIcons.Check);
check.AddToClassList("material-icon");
check.AddToClassList("language-option-check");
row.Add(check);
}

void Select() => OnSelected(code);
row.AddManipulator(new Clickable(Select));
AccessibilityBridge.RegisterE2ETapTarget(row, () => true, Select);
list.Add(row);
}

container.Add(list);

var actions = new VisualElement();
actions.AddToClassList("dialog-actions");
actions.Add(CreateCancelButton());
container.Add(actions);
}

private void OnSelected(string code)
{
_onSelected?.Invoke(code);
Dismiss();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/demo/Assets/Scripts/UI/MaterialIcons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ public static class MaterialIcons
public const string Fullscreen = "\uE5D0";
public const string ExpandMore = "\uE5CF";
public const string ExpandLess = "\uE5CE";
public const string Check = "\uE5CA";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class PushSectionController
private readonly AppViewModel _viewModel;
private readonly VisualElement _root;
private Label _pushIdLabel;
private Label _statusLabel;
private SwitchToggle _enabledToggle;
private Button _promptButton;

Expand Down Expand Up @@ -43,8 +44,18 @@ private VisualElement BuildSection()

card.Add(SectionBuilder.CreateDivider());

var statusRow = SectionBuilder.CreateInlineKeyValue(
"Status",
FormatStatus(_viewModel.IsPushSubscribed),
"push_subscription_status"
);
_statusLabel = statusRow.Q<Label>("push_subscription_status_value");
card.Add(statusRow);

card.Add(SectionBuilder.CreateDivider());

var toggleRow = SectionBuilder.CreateToggleRow(
"Enabled",
"Opted In",
null,
"push_enabled_toggle",
_viewModel.PushOptedIn,
Expand Down Expand Up @@ -72,6 +83,7 @@ private VisualElement BuildSection()
public void Refresh()
{
_pushIdLabel.text = FormatIdValue(_viewModel.PushSubscriptionId);
_statusLabel.text = FormatStatus(_viewModel.IsPushSubscribed);
_enabledToggle.SetValueWithoutNotify(_viewModel.PushOptedIn);
_enabledToggle.SetEnabled(_viewModel.HasPermission);
_promptButton.style.display = _viewModel.HasPermission
Expand All @@ -82,6 +94,9 @@ public void Refresh()
private static string FormatIdValue(string value) =>
string.IsNullOrEmpty(value) ? "—" : value;

private static string FormatStatus(bool subscribed) =>
subscribed ? "Subscribed" : "Unsubscribed";

private void OnEnabledChanged(bool value) => _viewModel.SetPushEnabled(value);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using OneSignalDemo.Services;
using OneSignalDemo.UI.Dialogs;
using OneSignalDemo.ViewModels;
using UnityEngine.UIElements;
Expand All @@ -7,11 +9,60 @@ namespace OneSignalDemo.UI.Sections
{
public class UserSectionController
{
private static readonly KeyValuePair<string, string>[] LanguageOptions =
{
new("Device Default", ""),
new("English", "en"),
new("Arabic", "ar"),
new("Azerbaijani", "az"),
new("Bosnian", "bs"),
new("Catalan", "ca"),
new("Chinese (Simplified)", "zh-Hans"),
new("Chinese (Traditional)", "zh-Hant"),
new("Croatian", "hr"),
new("Czech", "cs"),
new("Danish", "da"),
new("Dutch", "nl"),
new("Estonian", "et"),
new("Finnish", "fi"),
new("French", "fr"),
new("Georgian", "ka"),
new("Bulgarian", "bg"),
new("German", "de"),
new("Greek", "el"),
new("Hindi", "hi"),
new("Hebrew", "he"),
new("Hungarian", "hu"),
new("Indonesian", "id"),
new("Italian", "it"),
new("Japanese", "ja"),
new("Korean", "ko"),
new("Latvian", "lv"),
new("Lithuanian", "lt"),
new("Malay", "ms"),
new("Norwegian", "nb"),
new("Persian", "fa"),
new("Polish", "pl"),
new("Portuguese", "pt"),
new("Punjabi", "pa"),
new("Romanian", "ro"),
new("Russian", "ru"),
new("Serbian", "sr"),
new("Slovak", "sk"),
new("Spanish", "es"),
new("Swedish", "sv"),
new("Thai", "th"),
new("Turkish", "tr"),
new("Ukrainian", "uk"),
new("Vietnamese", "vi"),
};

private readonly AppViewModel _viewModel;
private readonly VisualElement _dialogRoot;
private readonly VisualElement _root;
private Label _statusValue;
private Label _externalIdValue;
private Label _languageValue;
private Button _loginButton;
private Button _logoutButton;

Expand Down Expand Up @@ -48,6 +99,26 @@ private VisualElement BuildSection()
);
_externalIdValue = extIdRow.Q<Label>("user_external_id_value");
statusCard.Add(extIdRow);

statusCard.Add(SectionBuilder.CreateDivider());

var languageRow = SectionBuilder.CreateInlineKeyValue(
"Language",
LanguageName(_viewModel.Language),
"user_language_dropdown"
);
_languageValue = languageRow.Q<Label>("user_language_dropdown_value");
var chevron = new Label(MaterialIcons.ExpandMore);
chevron.AddToClassList("material-icon");
chevron.AddToClassList("language-dropdown-icon");
languageRow.Add(chevron);
languageRow.AddManipulator(new Clickable(ShowLanguagePicker));
AccessibilityBridge.RegisterE2ETapTarget(
languageRow,
() => languageRow.enabledInHierarchy,
ShowLanguagePicker
);
statusCard.Add(languageRow);
section.Add(statusCard);

_loginButton = SectionBuilder.CreatePrimaryButton(
Expand Down Expand Up @@ -79,12 +150,34 @@ private void ShowLoginDialog()
dialog.Show(_dialogRoot);
}

private void ShowLanguagePicker()
{
var dialog = new LanguagePickerDialog(
LanguageOptions,
_viewModel.Language,
code => _viewModel.SetLanguage(code)
);
dialog.Show(_dialogRoot);
}

private static string LanguageName(string code)
{
code ??= "";
foreach (var option in LanguageOptions)
{
if (option.Value == code)
return option.Key;
}
return code;
}

public void Refresh()
{
_statusValue.text = _viewModel.IsLoggedIn ? "Logged In" : "Anonymous";
_statusValue.EnableInClassList("status-value-green", _viewModel.IsLoggedIn);

_externalIdValue.text = _viewModel.IsLoggedIn ? _viewModel.ExternalUserId : "\u2014";
_languageValue.text = LanguageName(_viewModel.Language);

_loginButton.text = _viewModel.IsLoggedIn ? "SWITCH USER" : "LOGIN USER";
_logoutButton.style.display = _viewModel.IsLoggedIn
Expand Down
23 changes: 23 additions & 0 deletions examples/demo/Assets/Scripts/ViewModels/AppViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ public class AppViewModel : MonoBehaviour
private string _externalUserId;
private string _oneSignalId;
private string _pushSubscriptionId;
private string _pushToken;
private bool _pushOptedIn;
private bool _hasPermission;
private bool _isLoading;
private string _language;

// Drops stale FetchUserDataFromApi responses (mirrors requestSequenceRef in RN useOneSignal).
private int _requestSequence;
Expand Down Expand Up @@ -63,6 +65,9 @@ public class AppViewModel : MonoBehaviour
public string PushSubscriptionId => _pushSubscriptionId;
public bool PushOptedIn => _pushOptedIn;
public bool HasPermission => _hasPermission;
public bool IsPushSubscribed =>
_pushOptedIn && _hasPermission && !string.IsNullOrEmpty(_pushToken);
public string Language => _language;
public bool IsLoading => _isLoading;
public bool IsLoggedIn => !string.IsNullOrEmpty(_externalUserId);

Expand Down Expand Up @@ -115,8 +120,10 @@ public void LoadInitialState()
_inAppMessagesPaused = _prefs.IamPaused;
_locationShared = _prefs.LocationShared;
_externalUserId = _prefs.ExternalUserId;
_language = _prefs.Language;

_pushSubscriptionId = OneSignal.User.PushSubscription.Id ?? "";
_pushToken = OneSignal.User.PushSubscription.Token ?? "";
_pushOptedIn = OneSignal.User.PushSubscription.OptedIn;
_hasPermission = OneSignal.Notifications.Permission;
_oneSignalId = OneSignal.User.OneSignalId ?? "";
Expand Down Expand Up @@ -168,11 +175,25 @@ public void LogoutUser()
_externalUserId = "";
_prefs.ExternalUserId = "";
ClearUserData();
SetLanguage("");

Debug.Log($"[{Tag}] Logged out");
NotifyStateChanged();
}

// An empty code makes the native SDK fall back to the device language.
public void SetLanguage(string language)
{
language ??= "";
OneSignal.User.Language = language;
_language = language;
_prefs.Language = language;
Debug.Log(
$"[{Tag}] Language set to: {(language.Length == 0 ? "device default" : language)}"
);
NotifyStateChanged();
}

public void AddAlias(string label, string id)
{
OneSignal.User.AddAlias(label, id);
Expand Down Expand Up @@ -572,6 +593,7 @@ public async Task FetchUserDataFromApi()
}

_pushSubscriptionId = OneSignal.User.PushSubscription.Id ?? "";
_pushToken = OneSignal.User.PushSubscription.Token ?? "";
_pushOptedIn = OneSignal.User.PushSubscription.OptedIn;
_hasPermission = OneSignal.Notifications.Permission;

Expand Down Expand Up @@ -646,6 +668,7 @@ private static void MergeUnique(List<string> target, IEnumerable<string> source)
private void OnPushSubscriptionChanged(object sender, PushSubscriptionChangedEventArgs e)
{
_pushSubscriptionId = OneSignal.User.PushSubscription.Id ?? "";
_pushToken = OneSignal.User.PushSubscription.Token ?? "";
_pushOptedIn = OneSignal.User.PushSubscription.OptedIn;
var previous = e.State.Previous;
var current = e.State.Current;
Expand Down
Loading