utilities feature

This commit is contained in:
2021-08-06 14:42:40 +08:00
parent 569c0a733f
commit 600d81a3f1
24 changed files with 1036 additions and 83 deletions

View File

@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml;
using Gallery.Util;
using Xamarin.Forms.Xaml;
namespace Gallery.Resources
{
public class Helper
{
private static readonly Dictionary<string, LanguageResource> dict = new();
public static string GetResource(string name, params object[] args)
{
if (!dict.TryGetValue(App.CurrentCulture.PlatformString, out LanguageResource lang))
{
lang = new LanguageResource(App.CurrentCulture);
dict.Add(App.CurrentCulture.PlatformString, lang);
}
if (args == null || args.Length == 0)
{
return lang[name];
}
return string.Format(lang[name], args);
}
private class LanguageResource
{
private readonly Dictionary<string, string> strings;
public string this[string key]
{
get
{
if (strings != null && strings.TryGetValue(key, out string val))
{
return val;
}
return key;
}
}
public LanguageResource(PlatformCulture lang)
{
try
{
const string PROJECT = "Gallery";
const string PLATFORM =
#if __IOS__
"iOS";
#elif __ANDROID__
"Droid";
#endif
var langId = $"{PROJECT}.{PLATFORM}.Resources.Languages.{lang.Language}.xml";
var langCodeId = $"{PROJECT}.{PLATFORM}.Resources.Languages.{lang.LanguageCode}.xml";
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(LanguageResource)).Assembly;
var names = assembly.GetManifestResourceNames();
var name = names.FirstOrDefault(n =>
string.Equals(n, langId, StringComparison.OrdinalIgnoreCase) ||
string.Equals(n, langCodeId, StringComparison.OrdinalIgnoreCase));
if (name == null)
{
name = $"{PROJECT}.{PLATFORM}.Resources.Languages.zh-CN.xml";
}
var xml = new XmlDocument();
using (var stream = assembly.GetManifestResourceStream(name))
{
xml.Load(stream);
}
strings = new Dictionary<string, string>();
foreach (XmlElement ele in xml.DocumentElement)
{
strings[ele.Name] = ele.InnerText;
}
}
catch (Exception ex)
{
// load failed
Log.Error("language.ctor", $"failed to load xml resource: {ex.Message}");
}
}
}
}
public class TextExtension : IMarkupExtension
{
public string Text { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Text == null)
{
return string.Empty;
}
return Helper.GetResource(Text);
}
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<Title>Gallery</Title>
</root>

View File

@ -0,0 +1,36 @@
namespace Gallery.Resources
{
public class PlatformCulture
{
public string PlatformString { get; private set; }
public string LanguageCode { get; private set; }
public string LocaleCode { get; private set; }
public string Language => string.IsNullOrEmpty(LocaleCode) ? LanguageCode : $"{LanguageCode}-{LocaleCode}";
public PlatformCulture() : this(null) { }
public PlatformCulture(string cultureString)
{
if (string.IsNullOrEmpty(cultureString))
{
cultureString = "zh-CN";
}
PlatformString = cultureString.Replace('_', '-');
var index = PlatformString.IndexOf('-');
if (index > 0)
{
var parts = PlatformString.Split('-');
LanguageCode = parts[0];
LocaleCode = parts[^1];
}
else
{
LanguageCode = PlatformString;
LocaleCode = string.Empty;
}
}
public override string ToString() => PlatformString;
}
}

View File

@ -0,0 +1,35 @@
using Gallery.Services;
using Xamarin.Forms;
namespace Gallery.Resources.Theme
{
public class DarkTheme : Theme
{
private static DarkTheme instance;
public static DarkTheme Instance
{
get
{
if (instance == null)
{
instance = new DarkTheme();
}
return instance;
}
}
public DarkTheme()
{
InitColors();
InitResources();
}
private void InitColors()
{
Add(StatusBarStyle, StatusBarStyles.WhiteText);
Add(NavigationColor, Color.FromRgb(0x11, 0x11, 0x11));
Add(Primary, Color.FromRgb(33, 150, 243));
}
}
}

View File

@ -0,0 +1,35 @@
using Gallery.Services;
using Xamarin.Forms;
namespace Gallery.Resources.Theme
{
public class LightTheme : Theme
{
private static LightTheme instance;
public static LightTheme Instance
{
get
{
if (instance == null)
{
instance = new LightTheme();
}
return instance;
}
}
public LightTheme()
{
InitColors();
InitResources();
}
private void InitColors()
{
Add(StatusBarStyle, StatusBarStyles.DarkText);
Add(NavigationColor, Color.FromRgb(0xf0, 0xf0, 0xf0));
Add(Primary, Color.FromRgb(33, 150, 243));
}
}
}

View File

@ -0,0 +1,44 @@
using Gallery.Resources.UI;
using Xamarin.Forms;
namespace Gallery.Resources.Theme
{
public abstract class Theme : ResourceDictionary
{
public const string StatusBarStyle = nameof(StatusBarStyle);
public const string NavigationColor = nameof(NavigationColor);
public const string IconLightFamily = nameof(IconLightFamily);
public const string IconRegularFamily = nameof(IconRegularFamily);
public const string IconSolidFamily = nameof(IconSolidFamily);
public const string ScreenBottomPadding = nameof(ScreenBottomPadding);
public const string IconClose = nameof(IconClose);
public const string FontIconRefresh = nameof(FontIconRefresh);
public const string Primary = nameof(Primary);
protected void InitResources()
{
Add(IconLightFamily, Definition.IconLightFamily);
Add(IconRegularFamily, Definition.IconRegularFamily);
Add(IconSolidFamily, Definition.IconSolidFamily);
Add(ScreenBottomPadding, Definition.ScreenBottomPadding);
Add(FontIconRefresh, GetFontIcon(Definition.IconRefresh, Definition.IconSolidFamily));
Add(IconClose, Definition.IconClose);
}
private FontImageSource GetFontIcon(string icon, string family, Color color = default)
{
return new FontImageSource
{
FontFamily = family,
Glyph = icon,
Size = Definition.FontSizeTitle,
Color = color
};
}
}
}

View File

@ -0,0 +1,129 @@
using System;
using Gallery.Util;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Gallery.Resources.UI
{
public static class Definition
{
public const double FontSizeTitle = 18.0;
public static readonly Thickness ScreenBottomPadding;
#if __IOS__
public const string IconLightFamily = "FontAwesome5Pro-Light";
public const string IconRegularFamily = "FontAwesome5Pro-Regular";
public const string IconSolidFamily = "FontAwesome5Pro-Solid";
public const string IconLeft = "\uf104";
#elif __ANDROID__
public const string IconLightFamily = "fa-light-300.ttf#FontAwesome5Pro-Light";
public const string IconRegularFamily = "fa-regular-400.ttf#FontAwesome5Pro-Regular";
public const string IconSolidFamily = "fa-solid-900.ttf#FontAwesome5Pro-Solid";
public const string IconLeft = "\uf053";
#endif
public const string IconRefresh = "\uf2f9";
public const string IconClose = "\uf057";
static Definition()
{
_ = IsFullscreenDevice;
if (_isBottomPadding)
{
if (DeviceInfo.Idiom == DeviceIdiom.Phone)
{
ScreenBottomPadding = new Thickness(0, 0, 0, 26);
}
else
{
ScreenBottomPadding = new Thickness(0, 0, 0, 16);
}
}
}
private static bool _isBottomPadding;
private static bool? _isFullscreenDevice;
public static bool IsFullscreenDevice
{
get
{
if (_isFullscreenDevice != null)
{
return _isFullscreenDevice.Value;
}
#if __IOS__
try
{
var model = DeviceInfo.Model;
if (model == "iPhone10,3")
{
// iPhone X
_isFullscreenDevice = true;
_isBottomPadding = true;
}
else if (model.StartsWith("iPhone"))
{
var vs = model[6..].Split(',');
if (vs.Length == 2 && int.TryParse(vs[0], out int main) && int.TryParse(vs[1], out int sub))
{
// iPhone X
// iPhone XS/XR/11/12 or newer
var flag = (main == 10 && sub == 6) || main > 10;
_isFullscreenDevice = flag;
_isBottomPadding = flag;
}
else
{
_isFullscreenDevice = false;
}
}
else if (model.StartsWith("iPad"))
{
var vs = model[4..].Split(',');
if (vs.Length == 2 && int.TryParse(vs[0], out int main) && int.TryParse(vs[1], out int sub))
{
// iPad Pro 11-inch (gen 1~3)
// iPad Pro 12.9-inch (gen 3~5)
var flag = main == 8 || (main == 13 && sub >= 4 && sub < 12);
_isBottomPadding = flag;
}
else
{
_isFullscreenDevice = false;
}
}
else
{
#if DEBUG
// simulator
var name = DeviceInfo.Name;
var flag =
name.StartsWith("iPhone X") ||
name.StartsWith("iPhone 11") ||
name.StartsWith("iPhone 12");
_isFullscreenDevice = flag;
_isBottomPadding = flag ||
name.StartsWith("iPad Pro (11-inch)") ||
name.StartsWith("iPad Pro (12.9-inch) (3rd generation)") ||
name.StartsWith("iPad Pro (12.9-inch) (4th generation)") ||
name.StartsWith("iPad Pro (12.9-inch) (5th generation)");
#else
_isFullscreenDevice = false;
#endif
}
}
catch (Exception ex)
{
Log.Error("device.model.get", $"failed to get the device model. {ex.Message}");
}
#else
_isFullscreenDevice = false;
#endif
return _isFullscreenDevice.Value;
}
}
}
}