Files
keepass2android/src/keepass2android-app/settings/DatabaseSettingsActivity.cs
2025-01-07 11:20:08 +01:00

179 lines
6.8 KiB
C#

/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
Keepass2Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Keepass2Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Widget;
using Android.Provider;
using Android.Views.Autofill;
using Java.IO;
using KeePass.DataExchange;
using KeePassLib.Cryptography.Cipher;
using KeePassLib.Keys;
using KeePassLib.Serialization;
using KeePassLib.Utility;
using keepass2android.Io;
using keepass2android.Utils;
using KeePassLib;
using KeePassLib.Cryptography.KeyDerivation;
using KeePassLib.Interfaces;
using System.Collections.Generic;
using AndroidX.Preference;
using keepass2android;
namespace keepass2android
{
/// <summary>
/// <para>
/// A helper class that manages language preference display and selection.
/// </para>
/// <para>
/// The idea is to provide a ListPreference with a "System language" item at the top, followed by
/// the localized list of supported language names. The items are backed by their corresponding "code".
/// For a langauge that's the 2-char lowercase language code, which is exactly the same code that
/// LocaleManager.Language expects.
/// </para>
/// <para>
/// "System language" is a special case. LocaleManager.Language expects null, but ListPreference
/// does not support null as a valid code. To work around this, LanguageEntry.SYS_LANG_CODE
/// is used as the preference code. LanguageEntry.PrefCodeToLanguage(string) is used to convert the
/// preference codes to language codes as needed.
/// </para>
/// </summary>
internal class AppLanguageManager
{
private readonly PreferenceFragmentCompat _fragment;
private readonly AndroidX.Preference.ListPreference _langPref;
private readonly Dictionary<string, LanguageEntry> _langEntriesByCodeUnique;
public AppLanguageManager(PreferenceFragmentCompat fragment, AndroidX.Preference.ListPreference langPref, HashSet<string> supportedLocales)
{
this._fragment = fragment;
this._langPref = langPref;
this._langEntriesByCodeUnique = CreateCodeToEntryMapping(fragment, supportedLocales);
ConfigureLanguageList();
}
private static Dictionary<string, LanguageEntry> CreateCodeToEntryMapping(PreferenceFragmentCompat fragment, HashSet<string> supportedLocales)
{
var localesByCode = new Dictionary<string, List<Java.Util.Locale>>();
foreach (var loc in Java.Util.Locale.GetAvailableLocales())
{
if (!supportedLocales.Contains(loc.Language))
continue;
if (!localesByCode.ContainsKey(loc.Language))
{
localesByCode[loc.Language] = new List<Java.Util.Locale>();
}
localesByCode[loc.Language].Add(loc);
}
var langEntriesByCodeUnique = localesByCode
.Select(l => new KeyValuePair<string, LanguageEntry>(l.Key, LanguageEntry.OfLocale(l.Value.First())))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var sysLangEntry = LanguageEntry.SystemDefault(fragment.GetString(Resource.String.SystemLanguage));
langEntriesByCodeUnique.Add(sysLangEntry.Code, sysLangEntry);
return langEntriesByCodeUnique;
}
private void ConfigureLanguageList()
{
List<KeyValuePair<string, LanguageEntry>> langEntriesList = _langEntriesByCodeUnique
.OrderByDescending(kvp => kvp.Value.IsSystem)
.ThenBy(kvp => kvp.Value.Name)
.ToList();
_langPref.SetEntries(langEntriesList
.Select(kvp => kvp.Value.Name)
.ToArray());
_langPref.SetEntryValues(langEntriesList
.Select(kvp => kvp.Value.Code)
.ToArray());
_langPref.Summary = GetDisplayLanguage(LanguageEntry.PrefCodeToLanguage(_langPref.Value));
_langPref.PreferenceChange += AppLanguagePrefChange;
}
private string GetDisplayLanguage(string languageCode)
{
if (languageCode != null && this._langEntriesByCodeUnique.ContainsKey(languageCode))
return this._langEntriesByCodeUnique[languageCode]?.Name;
else
return _fragment.GetString(Resource.String.SystemLanguage);
}
private void AppLanguagePrefChange(object sender, AndroidX.Preference.Preference.PreferenceChangeEventArgs args)
{
string langCode = LanguageEntry.PrefCodeToLanguage((string)args.NewValue);
LocaleManager.Language = langCode;
_langPref.Summary = GetDisplayLanguage(langCode);
}
}
#pragma warning restore CS0618 // Type or member is obsolete
/// <summary>
/// Activity to configure the application and database settings. The database must be unlocked, and this activity will close if it becomes locked.
/// </summary>
[Activity(Label = "@string/app_name", Theme = "@style/Kp2aTheme_ActionBar", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden)]
public class DatabaseSettingsActivity : LockCloseActivity, PreferenceFragmentCompat.IOnPreferenceStartFragmentCallback
{
public static void Launch(Activity ctx)
{
ctx.StartActivity(new Intent(ctx, typeof(DatabaseSettingsActivity)));
}
private ActivityDesign _design;
public DatabaseSettingsActivity()
{
_design = new ActivityDesign(this);
settingsFragmentManager = new SettingsFragmentManager(this);
}
protected override void OnCreate(Bundle savedInstanceState)
{
_design.ApplyTheme();
base.OnCreate(savedInstanceState);
}
public SettingsFragmentManager settingsFragmentManager;
public bool OnPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref)
{
return settingsFragmentManager.OnPreferenceStartFragment(caller, pref);
}
}
}