utilities feature
This commit is contained in:
		
							
								
								
									
										85
									
								
								Gallery.Share/App.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								Gallery.Share/App.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | |||||||
|  | using Xamarin.Forms; | ||||||
|  | using Gallery.Services; | ||||||
|  | using Xamarin.Essentials; | ||||||
|  | using Gallery.Resources; | ||||||
|  | using Gallery.Util; | ||||||
|  | using Gallery.Resources.Theme; | ||||||
|  |  | ||||||
|  | namespace Gallery | ||||||
|  | { | ||||||
|  |     public partial class App : Application | ||||||
|  |     { | ||||||
|  |         public static AppTheme CurrentTheme { get; private set; } | ||||||
|  |         public static PlatformCulture CurrentCulture { get; private set; } | ||||||
|  |  | ||||||
|  |         public App() | ||||||
|  |         { | ||||||
|  |             DependencyService.Register<MockDataStore>(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private void InitResource() | ||||||
|  |         { | ||||||
|  |             var theme = AppInfo.RequestedTheme; | ||||||
|  |             SetTheme(theme, true); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private void InitPreference() | ||||||
|  |         { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private void InitLanguage() | ||||||
|  |         { | ||||||
|  |             var ci = Environment.GetCurrentCultureInfo(); | ||||||
|  |             Environment.SetCultureInfo(ci); | ||||||
|  |             CurrentCulture = new PlatformCulture(ci.Name.ToLower()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private void SetTheme(AppTheme theme, bool force = false) | ||||||
|  |         { | ||||||
|  |             if (force || theme != CurrentTheme) | ||||||
|  |             { | ||||||
|  |                 CurrentTheme = theme; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | #if DEBUG | ||||||
|  |             Log.Print($"application theme: {theme}"); | ||||||
|  | #endif | ||||||
|  |             Theme themeInstance = theme switch | ||||||
|  |             { | ||||||
|  |                 AppTheme.Dark => DarkTheme.Instance, | ||||||
|  |                 _ => LightTheme.Instance | ||||||
|  |             }; | ||||||
|  | #if __IOS__ | ||||||
|  |             var style = (StatusBarStyles)themeInstance[Theme.StatusBarStyle]; | ||||||
|  |             Environment.SetStatusBarStyle(style); | ||||||
|  | #elif __ANDROID__ | ||||||
|  |             var color = (Color)themeInstance[Theme.NavigationColor]; | ||||||
|  |             Environment.SetStatusBarColor(color); | ||||||
|  | #endif | ||||||
|  |             Resources = themeInstance; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         protected override void OnStart() | ||||||
|  |         { | ||||||
|  |             InitLanguage(); | ||||||
|  |             MainPage = new AppShell(); | ||||||
|  |  | ||||||
|  |             InitResource(); | ||||||
|  |             InitPreference(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         protected override void OnSleep() | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         protected override void OnResume() | ||||||
|  |         { | ||||||
|  |             var theme = AppInfo.RequestedTheme; | ||||||
|  |             SetTheme(theme); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="utf-8" ?> |  | ||||||
| <Application xmlns="http://xamarin.com/schemas/2014/forms" |  | ||||||
|              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" |  | ||||||
|              x:Class="Gallery.App"> |  | ||||||
|     <!-- |  | ||||||
|         Define global resources and styles here, that apply to all pages in your app. |  | ||||||
|     --> |  | ||||||
|     <Application.Resources> |  | ||||||
|         <ResourceDictionary> |  | ||||||
|             <Color x:Key="Primary">#2196F3</Color> |  | ||||||
|             <Style TargetType="Button"> |  | ||||||
|                 <Setter Property="TextColor" Value="White"></Setter> |  | ||||||
|                 <Setter Property="VisualStateManager.VisualStateGroups"> |  | ||||||
|                     <VisualStateGroupList> |  | ||||||
|                         <VisualStateGroup x:Name="CommonStates"> |  | ||||||
|                             <VisualState x:Name="Normal"> |  | ||||||
|                                 <VisualState.Setters> |  | ||||||
|                                     <Setter Property="BackgroundColor" Value="{StaticResource Primary}" /> |  | ||||||
|                                 </VisualState.Setters> |  | ||||||
|                             </VisualState> |  | ||||||
|                             <VisualState x:Name="Disabled"> |  | ||||||
|                                 <VisualState.Setters> |  | ||||||
|                                     <Setter Property="BackgroundColor" Value="#332196F3" /> |  | ||||||
|                                 </VisualState.Setters> |  | ||||||
|                             </VisualState> |  | ||||||
|                         </VisualStateGroup> |  | ||||||
|                     </VisualStateGroupList> |  | ||||||
|                 </Setter> |  | ||||||
|             </Style> |  | ||||||
|         </ResourceDictionary>         |  | ||||||
|     </Application.Resources> |  | ||||||
| </Application> |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| using System; |  | ||||||
| using Xamarin.Forms; |  | ||||||
| using Xamarin.Forms.Xaml; |  | ||||||
| using Gallery.Services; |  | ||||||
| using Gallery.Views; |  | ||||||
|  |  | ||||||
| namespace Gallery |  | ||||||
| { |  | ||||||
|     public partial class App : Application |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         public App() |  | ||||||
|         { |  | ||||||
|             InitializeComponent(); |  | ||||||
|  |  | ||||||
|             DependencyService.Register<MockDataStore>(); |  | ||||||
|             MainPage = new AppShell(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         protected override void OnStart() |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         protected override void OnSleep() |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         protected override void OnResume() |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -14,12 +14,12 @@ | |||||||
|     <Shell.Resources> |     <Shell.Resources> | ||||||
|         <ResourceDictionary> |         <ResourceDictionary> | ||||||
|             <Style x:Key="BaseStyle" TargetType="Element"> |             <Style x:Key="BaseStyle" TargetType="Element"> | ||||||
|                 <Setter Property="Shell.BackgroundColor" Value="{StaticResource Primary}" /> |                 <Setter Property="Shell.BackgroundColor" Value="{DynamicResource Primary}" /> | ||||||
|                 <Setter Property="Shell.ForegroundColor" Value="White" /> |                 <Setter Property="Shell.ForegroundColor" Value="White" /> | ||||||
|                 <Setter Property="Shell.TitleColor" Value="White" /> |                 <Setter Property="Shell.TitleColor" Value="White" /> | ||||||
|                 <Setter Property="Shell.DisabledColor" Value="#B4FFFFFF" /> |                 <Setter Property="Shell.DisabledColor" Value="#B4FFFFFF" /> | ||||||
|                 <Setter Property="Shell.UnselectedColor" Value="#95FFFFFF" /> |                 <Setter Property="Shell.UnselectedColor" Value="#95FFFFFF" /> | ||||||
|                 <Setter Property="Shell.TabBarBackgroundColor" Value="{StaticResource Primary}" /> |                 <Setter Property="Shell.TabBarBackgroundColor" Value="{DynamicResource Primary}" /> | ||||||
|                 <Setter Property="Shell.TabBarForegroundColor" Value="White"/> |                 <Setter Property="Shell.TabBarForegroundColor" Value="White"/> | ||||||
|                 <Setter Property="Shell.TabBarUnselectedColor" Value="#95FFFFFF"/> |                 <Setter Property="Shell.TabBarUnselectedColor" Value="#95FFFFFF"/> | ||||||
|                 <Setter Property="Shell.TabBarTitleColor" Value="White"/> |                 <Setter Property="Shell.TabBarTitleColor" Value="White"/> | ||||||
| @@ -41,12 +41,12 @@ | |||||||
|                             <VisualState x:Name="Normal"> |                             <VisualState x:Name="Normal"> | ||||||
|                                 <VisualState.Setters> |                                 <VisualState.Setters> | ||||||
|                                     <Setter Property="BackgroundColor" Value="{x:OnPlatform UWP=Transparent, iOS=White}" /> |                                     <Setter Property="BackgroundColor" Value="{x:OnPlatform UWP=Transparent, iOS=White}" /> | ||||||
|                                     <Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{StaticResource Primary}" /> |                                     <Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{DynamicResource Primary}" /> | ||||||
|                                 </VisualState.Setters> |                                 </VisualState.Setters> | ||||||
|                             </VisualState> |                             </VisualState> | ||||||
|                             <VisualState x:Name="Selected"> |                             <VisualState x:Name="Selected"> | ||||||
|                                 <VisualState.Setters> |                                 <VisualState.Setters> | ||||||
|                                     <Setter Property="BackgroundColor" Value="{StaticResource Primary}" /> |                                     <Setter Property="BackgroundColor" Value="{DynamicResource Primary}" /> | ||||||
|                                 </VisualState.Setters> |                                 </VisualState.Setters> | ||||||
|                             </VisualState> |                             </VisualState> | ||||||
|                         </VisualStateGroup> |                         </VisualStateGroup> | ||||||
| @@ -63,7 +63,7 @@ | |||||||
|                         <VisualStateGroup x:Name="CommonStates"> |                         <VisualStateGroup x:Name="CommonStates"> | ||||||
|                             <VisualState x:Name="Normal"> |                             <VisualState x:Name="Normal"> | ||||||
|                                 <VisualState.Setters> |                                 <VisualState.Setters> | ||||||
|                                     <Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{StaticResource Primary}" /> |                                     <Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{DynamicResource Primary}" /> | ||||||
|                                 </VisualState.Setters> |                                 </VisualState.Setters> | ||||||
|                             </VisualState> |                             </VisualState> | ||||||
|                         </VisualStateGroup> |                         </VisualStateGroup> | ||||||
|   | |||||||
| @@ -1,12 +1,10 @@ | |||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; |  | ||||||
| using Gallery.ViewModels; |  | ||||||
| using Gallery.Views; | using Gallery.Views; | ||||||
| using Xamarin.Forms; | using Xamarin.Forms; | ||||||
|  |  | ||||||
| namespace Gallery | namespace Gallery | ||||||
| { | { | ||||||
|     public partial class AppShell : Xamarin.Forms.Shell |     public partial class AppShell : Shell | ||||||
|     { |     { | ||||||
|         public AppShell() |         public AppShell() | ||||||
|         { |         { | ||||||
| @@ -17,7 +15,7 @@ namespace Gallery | |||||||
|  |  | ||||||
|         private async void OnMenuItemClicked(object sender, EventArgs e) |         private async void OnMenuItemClicked(object sender, EventArgs e) | ||||||
|         { |         { | ||||||
|             await Shell.Current.GoToAsync("//LoginPage"); |             await Current.GoToAsync("//LoginPage"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,9 +6,10 @@ | |||||||
|     <SharedGUID>{E72B5C40-090B-4A1C-9170-BD33C14A9A91}</SharedGUID> |     <SharedGUID>{E72B5C40-090B-4A1C-9170-BD33C14A9A91}</SharedGUID> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <PropertyGroup Label="Configuration"> |   <PropertyGroup Label="Configuration"> | ||||||
|     <Import_RootNamespace>Gallery.Share</Import_RootNamespace> |     <Import_RootNamespace>Gallery</Import_RootNamespace> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  |     <Compile Include="$(MSBuildThisFileDirectory)App.cs" /> | ||||||
|     <Compile Include="$(MSBuildThisFileDirectory)Models\Item.cs" /> |     <Compile Include="$(MSBuildThisFileDirectory)Models\Item.cs" /> | ||||||
|     <Compile Include="$(MSBuildThisFileDirectory)Services\IDataStore.cs" /> |     <Compile Include="$(MSBuildThisFileDirectory)Services\IDataStore.cs" /> | ||||||
|     <Compile Include="$(MSBuildThisFileDirectory)Services\MockDataStore.cs" /> |     <Compile Include="$(MSBuildThisFileDirectory)Services\MockDataStore.cs" /> | ||||||
| @@ -33,18 +34,26 @@ | |||||||
|     <Compile Include="$(MSBuildThisFileDirectory)Views\NewItemPage.xaml.cs"> |     <Compile Include="$(MSBuildThisFileDirectory)Views\NewItemPage.xaml.cs"> | ||||||
|       <DependentUpon>Views\NewItemPage.xaml</DependentUpon> |       <DependentUpon>Views\NewItemPage.xaml</DependentUpon> | ||||||
|     </Compile> |     </Compile> | ||||||
|     <Compile Include="$(MSBuildThisFileDirectory)App.xaml.cs"> |  | ||||||
|       <DependentUpon>App.xaml</DependentUpon> |  | ||||||
|     </Compile> |  | ||||||
|     <Compile Include="$(MSBuildThisFileDirectory)AppShell.xaml.cs"> |     <Compile Include="$(MSBuildThisFileDirectory)AppShell.xaml.cs"> | ||||||
|       <DependentUpon>AppShell.xaml</DependentUpon> |       <DependentUpon>AppShell.xaml</DependentUpon> | ||||||
|     </Compile> |     </Compile> | ||||||
|  |     <Compile Include="$(MSBuildThisFileDirectory)Services\Environment.cs" /> | ||||||
|  |     <Compile Include="$(MSBuildThisFileDirectory)Resources\PlatformCulture.cs" /> | ||||||
|  |     <Compile Include="$(MSBuildThisFileDirectory)Resources\Helper.cs" /> | ||||||
|  |     <Compile Include="$(MSBuildThisFileDirectory)Resources\Theme\Theme.cs" /> | ||||||
|  |     <Compile Include="$(MSBuildThisFileDirectory)Resources\Theme\LightTheme.cs" /> | ||||||
|  |     <Compile Include="$(MSBuildThisFileDirectory)Resources\Theme\DarkTheme.cs" /> | ||||||
|  |     <Compile Include="$(MSBuildThisFileDirectory)Resources\UI\Definition.cs" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <Folder Include="$(MSBuildThisFileDirectory)Models\" /> |     <Folder Include="$(MSBuildThisFileDirectory)Models\" /> | ||||||
|     <Folder Include="$(MSBuildThisFileDirectory)Services\" /> |     <Folder Include="$(MSBuildThisFileDirectory)Services\" /> | ||||||
|     <Folder Include="$(MSBuildThisFileDirectory)ViewModels\" /> |     <Folder Include="$(MSBuildThisFileDirectory)ViewModels\" /> | ||||||
|     <Folder Include="$(MSBuildThisFileDirectory)Views\" /> |     <Folder Include="$(MSBuildThisFileDirectory)Views\" /> | ||||||
|  |     <Folder Include="$(MSBuildThisFileDirectory)Resources\" /> | ||||||
|  |     <Folder Include="$(MSBuildThisFileDirectory)Resources\Theme\" /> | ||||||
|  |     <Folder Include="$(MSBuildThisFileDirectory)Resources\Languages\" /> | ||||||
|  |     <Folder Include="$(MSBuildThisFileDirectory)Resources\UI\" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <EmbeddedResource Include="$(MSBuildThisFileDirectory)Views\AboutPage.xaml"> |     <EmbeddedResource Include="$(MSBuildThisFileDirectory)Views\AboutPage.xaml"> | ||||||
| @@ -67,13 +76,12 @@ | |||||||
|       <SubType>Designer</SubType> |       <SubType>Designer</SubType> | ||||||
|       <Generator>MSBuild:UpdateDesignTimeXaml</Generator> |       <Generator>MSBuild:UpdateDesignTimeXaml</Generator> | ||||||
|     </EmbeddedResource> |     </EmbeddedResource> | ||||||
|     <EmbeddedResource Include="$(MSBuildThisFileDirectory)App.xaml"> |  | ||||||
|       <SubType>Designer</SubType> |  | ||||||
|       <Generator>MSBuild:UpdateDesignTimeXaml</Generator> |  | ||||||
|     </EmbeddedResource> |  | ||||||
|     <EmbeddedResource Include="$(MSBuildThisFileDirectory)AppShell.xaml"> |     <EmbeddedResource Include="$(MSBuildThisFileDirectory)AppShell.xaml"> | ||||||
|       <SubType>Designer</SubType> |       <SubType>Designer</SubType> | ||||||
|       <Generator>MSBuild:UpdateDesignTimeXaml</Generator> |       <Generator>MSBuild:UpdateDesignTimeXaml</Generator> | ||||||
|     </EmbeddedResource> |     </EmbeddedResource> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <None Include="$(MSBuildThisFileDirectory)Resources\Languages\zh-CN.xml" /> | ||||||
|  |   </ItemGroup> | ||||||
| </Project> | </Project> | ||||||
							
								
								
									
										100
									
								
								Gallery.Share/Resources/Helper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								Gallery.Share/Resources/Helper.cs
									
									
									
									
									
										Normal 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); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								Gallery.Share/Resources/Languages/zh-CN.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								Gallery.Share/Resources/Languages/zh-CN.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||||
|  | <root> | ||||||
|  |     <Title>Gallery</Title> | ||||||
|  | </root> | ||||||
							
								
								
									
										36
									
								
								Gallery.Share/Resources/PlatformCulture.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								Gallery.Share/Resources/PlatformCulture.cs
									
									
									
									
									
										Normal 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; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								Gallery.Share/Resources/Theme/DarkTheme.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Gallery.Share/Resources/Theme/DarkTheme.cs
									
									
									
									
									
										Normal 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)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								Gallery.Share/Resources/Theme/LightTheme.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Gallery.Share/Resources/Theme/LightTheme.cs
									
									
									
									
									
										Normal 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)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										44
									
								
								Gallery.Share/Resources/Theme/Theme.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								Gallery.Share/Resources/Theme/Theme.cs
									
									
									
									
									
										Normal 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 | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										129
									
								
								Gallery.Share/Resources/UI/Definition.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								Gallery.Share/Resources/UI/Definition.cs
									
									
									
									
									
										Normal 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; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										216
									
								
								Gallery.Share/Services/Environment.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								Gallery.Share/Services/Environment.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | |||||||
|  | #if __ANDROID_21__ | ||||||
|  | using Xamarin.Forms.Platform.Android; | ||||||
|  | #endif | ||||||
|  | using System.Globalization; | ||||||
|  | using System.Threading; | ||||||
|  | using Gallery.Resources; | ||||||
|  | using Gallery.Util; | ||||||
|  | using Xamarin.Forms; | ||||||
|  |  | ||||||
|  | namespace Gallery.Services | ||||||
|  | { | ||||||
|  |     public class Environment | ||||||
|  |     { | ||||||
|  |         private static readonly CultureInfo DefaultCulture = new("zh-CN"); | ||||||
|  |  | ||||||
|  | #if __ANDROID_21__ | ||||||
|  |         public static void SetStatusBarColor(Color color) | ||||||
|  |         { | ||||||
|  |             if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop) | ||||||
|  |             { | ||||||
|  |                 Android.OS.Droid.MainActivity.Main.SetStatusBarColor(color.ToAndroid()); | ||||||
|  |                 Android.OS.Droid.MainActivity.Main.Window.DecorView.SystemUiVisibility = | ||||||
|  |                     App.CurrentTheme == Xamarin.Essentials.AppTheme.Dark ? | ||||||
|  |                     Android.Views.StatusBarVisibility.Visible : | ||||||
|  |                     (Android.Views.StatusBarVisibility)Android.Views.SystemUiFlags.LightStatusBar; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |         public static void SetStatusBarStyle(StatusBarStyles style) | ||||||
|  |         { | ||||||
|  | #if __IOS__ | ||||||
|  |             SetStatusBarStyle(ConvertStyle(style)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static void SetStatusBarStyle(UIKit.UIStatusBarStyle style) | ||||||
|  |         { | ||||||
|  |             if (UIKit.UIApplication.SharedApplication.StatusBarStyle == style) | ||||||
|  |             { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             if (style == UIKit.UIStatusBarStyle.BlackOpaque) | ||||||
|  |             { | ||||||
|  |                 UIKit.UIApplication.SharedApplication.SetStatusBarHidden(true, true); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 if (UIKit.UIApplication.SharedApplication.StatusBarHidden) | ||||||
|  |                 { | ||||||
|  |                     UIKit.UIApplication.SharedApplication.SetStatusBarStyle(style, false); | ||||||
|  |                     UIKit.UIApplication.SharedApplication.SetStatusBarHidden(false, true); | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     UIKit.UIApplication.SharedApplication.SetStatusBarStyle(style, true); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static UIKit.UIStatusBarStyle ConvertStyle(StatusBarStyles style) | ||||||
|  |         { | ||||||
|  |             return style switch | ||||||
|  |             { | ||||||
|  |                 StatusBarStyles.DarkText => UIKit.UIStatusBarStyle.DarkContent, | ||||||
|  |                 StatusBarStyles.WhiteText => UIKit.UIStatusBarStyle.LightContent, | ||||||
|  |                 StatusBarStyles.Hidden => UIKit.UIStatusBarStyle.BlackOpaque, | ||||||
|  |                 _ => UIKit.UIStatusBarStyle.Default, | ||||||
|  |             }; | ||||||
|  | #endif | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static void SetCultureInfo(CultureInfo ci) | ||||||
|  |         { | ||||||
|  |             Thread.CurrentThread.CurrentCulture = ci; | ||||||
|  |             Thread.CurrentThread.CurrentUICulture = ci; | ||||||
|  | #if DEBUG | ||||||
|  |             Log.Print($"CurrentCulture set: {ci.Name}"); | ||||||
|  | #endif | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static CultureInfo GetCurrentCultureInfo() | ||||||
|  |         { | ||||||
|  |             string lang; | ||||||
|  |  | ||||||
|  | #if __IOS__ | ||||||
|  |             if (Foundation.NSLocale.PreferredLanguages.Length > 0) | ||||||
|  |             { | ||||||
|  |                 var pref = Foundation.NSLocale.PreferredLanguages[0]; | ||||||
|  |                 lang = ToDotnetLanguage(pref); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 lang = "zh-CN"; | ||||||
|  |             } | ||||||
|  | #elif __ANDROID__ | ||||||
|  |             var locale = Java.Util.Locale.Default; | ||||||
|  |             lang = ToDotnetLanguage(locale.ToString().Replace('_', '-')); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |             CultureInfo ci; | ||||||
|  |             var platform = new PlatformCulture(lang); | ||||||
|  |             try | ||||||
|  |             { | ||||||
|  |                 ci = new CultureInfo(platform.Language); | ||||||
|  |             } | ||||||
|  |             catch (CultureNotFoundException e) | ||||||
|  |             { | ||||||
|  |                 try | ||||||
|  |                 { | ||||||
|  |                     var fallback = ToDotnetFallbackLanguage(platform); | ||||||
|  |                     Log.Print($"{lang} failed, trying {fallback} ({e.Message})"); | ||||||
|  |                     ci = new CultureInfo(fallback); | ||||||
|  |                 } | ||||||
|  |                 catch (CultureNotFoundException e1) | ||||||
|  |                 { | ||||||
|  |                     Log.Error("culture.get", $"{lang} couldn't be set, using 'zh-CN' ({e1.Message})"); | ||||||
|  |                     ci = DefaultCulture; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return ci; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  | #if __IOS__ | ||||||
|  |         private static string ToDotnetLanguage(string iOSLanguage) | ||||||
|  |         { | ||||||
|  |             //certain languages need to be converted to CultureInfo equivalent | ||||||
|  |             string netLanguage = iOSLanguage switch | ||||||
|  |             { | ||||||
|  |                 // "Malaysian (Malaysia)" not supported .NET culture | ||||||
|  |                 // "Malaysian (Singapore)" not supported .NET culture | ||||||
|  |                 "ms-MY" or "ms-SG" => "ms", // closest supported | ||||||
|  |                 // "Schwiizertüütsch (Swiss German)" not supported .NET culture | ||||||
|  |                 "gsw-CH" => "de-CH", // closest supported | ||||||
|  |                 // add more application-specific cases here (if required) | ||||||
|  |                 // ONLY use cultures that have been tested and known to work | ||||||
|  |                 _ => iOSLanguage | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  | #if DEBUG | ||||||
|  |             Log.Print($"iOS Language: {iOSLanguage}, .NET Language/Locale: {netLanguage}"); | ||||||
|  | #endif | ||||||
|  |             return netLanguage; | ||||||
|  |         } | ||||||
|  | #elif __ANDROID__ | ||||||
|  |         private static string ToDotnetLanguage(string androidLanguage) | ||||||
|  |         { | ||||||
|  |             //certain languages need to be converted to CultureInfo equivalent | ||||||
|  |             string netLanguage = androidLanguage switch | ||||||
|  |             { | ||||||
|  |                 // "Malaysian (Brunei)" not supported .NET culture | ||||||
|  |                 // "Malaysian (Malaysia)" not supported .NET culture | ||||||
|  |                 // "Malaysian (Singapore)" not supported .NET culture | ||||||
|  |                 "ms-BN" or "ms-MY" or "ms-SG" => "ms", // closest supported | ||||||
|  |                 // "Indonesian (Indonesia)" has different code in  .NET  | ||||||
|  |                 "in-ID" => "id-ID", // correct code for .NET | ||||||
|  |                 // "Schwiizertüütsch (Swiss German)" not supported .NET culture | ||||||
|  |                 "gsw-CH" => "de-CH", // closest supported | ||||||
|  |                 // add more application-specific cases here (if required) | ||||||
|  |                 // ONLY use cultures that have been tested and known to work | ||||||
|  |                 _ => androidLanguage | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  | #if DEBUG | ||||||
|  |             Log.Print($"Android Language: {androidLanguage}, .NET Language/Locale: {netLanguage}"); | ||||||
|  | #endif | ||||||
|  |             return netLanguage; | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |         private static string ToDotnetFallbackLanguage(PlatformCulture platCulture) | ||||||
|  |         { | ||||||
|  |             string netLanguage = platCulture.LanguageCode switch | ||||||
|  |             { | ||||||
|  |                 "pt" => "pt-PT", // fallback to Portuguese (Portugal) | ||||||
|  |                 "gsw" => "de-CH", // equivalent to German (Switzerland) for this app | ||||||
|  |                 // add more application-specific cases here (if required) | ||||||
|  |                 // ONLY use cultures that have been tested and known to work | ||||||
|  |                 _ => platCulture.LanguageCode // use the first part of the identifier (two chars, usually); | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  | #if DEBUG | ||||||
|  |             Log.Print($".NET Fallback Language/Locale: {platCulture.LanguageCode} to {netLanguage} (application-specific)"); | ||||||
|  | #endif | ||||||
|  |             return netLanguage; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static class Screen | ||||||
|  |     { | ||||||
|  |         private const string StatusBarStyle = nameof(StatusBarStyle); | ||||||
|  |         private const string HomeIndicatorAutoHidden = nameof(HomeIndicatorAutoHidden); | ||||||
|  |  | ||||||
|  |         public static readonly BindableProperty StatusBarStyleProperty = BindableProperty.CreateAttached(StatusBarStyle, typeof(StatusBarStyles), typeof(Page), StatusBarStyles.WhiteText); | ||||||
|  |         public static StatusBarStyles GetStatusBarStyle(VisualElement page) => (StatusBarStyles)page.GetValue(StatusBarStyleProperty); | ||||||
|  |         public static void SetStatusBarStyle(VisualElement page, StatusBarStyles value) => page.SetValue(StatusBarStyleProperty, value); | ||||||
|  |  | ||||||
|  |         public static readonly BindableProperty HomeIndicatorAutoHiddenProperty = BindableProperty.CreateAttached(HomeIndicatorAutoHidden, typeof(bool), typeof(Shell), false); | ||||||
|  |         public static bool GetHomeIndicatorAutoHidden(VisualElement page) => (bool)page.GetValue(HomeIndicatorAutoHiddenProperty); | ||||||
|  |         public static void SetHomeIndicatorAutoHidden(VisualElement page, bool value) => page.SetValue(HomeIndicatorAutoHiddenProperty, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public enum StatusBarStyles | ||||||
|  |     { | ||||||
|  |         Default, | ||||||
|  |         // Will behave as normal.  | ||||||
|  |         // White text on black NavigationBar/in iOS Dark mode and  | ||||||
|  |         // Black text on white NavigationBar/in iOS Light mode | ||||||
|  |         DarkText, | ||||||
|  |         // Will switch the color of content of StatusBar to black.  | ||||||
|  |         WhiteText, | ||||||
|  |         // Will switch the color of content of StatusBar to white.  | ||||||
|  |         Hidden | ||||||
|  |         // Will hide the StatusBar | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -43,7 +43,7 @@ | |||||||
|                 </Label> |                 </Label> | ||||||
|                 <Button Margin="0,10,0,0" Text="Learn more" |                 <Button Margin="0,10,0,0" Text="Learn more" | ||||||
|                         Command="{Binding OpenWebCommand}" |                         Command="{Binding OpenWebCommand}" | ||||||
|                         BackgroundColor="{StaticResource Primary}" |                         BackgroundColor="{DynamicResource Primary}" | ||||||
|                         TextColor="White" /> |                         TextColor="White" /> | ||||||
|             </StackLayout> |             </StackLayout> | ||||||
|         </ScrollView> |         </ScrollView> | ||||||
|   | |||||||
							
								
								
									
										99
									
								
								Gallery.Util/Extensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								Gallery.Util/Extensions.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | |||||||
|  | using System; | ||||||
|  | using Xamarin.Forms; | ||||||
|  |  | ||||||
|  | namespace Gallery.Util | ||||||
|  | { | ||||||
|  |     public static class Extensions | ||||||
|  |     { | ||||||
|  |         public static T Binding<T>(this T view, BindableProperty property, string name, BindingMode mode = BindingMode.Default, IValueConverter converter = null) where T : BindableObject | ||||||
|  |         { | ||||||
|  |             if (name == null) | ||||||
|  |             { | ||||||
|  |                 view.SetValue(property, property.DefaultValue); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 view.SetBinding(property, name, mode, converter); | ||||||
|  |             } | ||||||
|  |             return view; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static T DynamicResource<T>(this T view, BindableProperty property, string key) where T : Element | ||||||
|  |         { | ||||||
|  |             view.SetDynamicResource(property, key); | ||||||
|  |             return view; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static T GridRow<T>(this T view, int row) where T : BindableObject | ||||||
|  |         { | ||||||
|  |             Grid.SetRow(view, row); | ||||||
|  |             return view; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static T GridRowSpan<T>(this T view, int rowSpan) where T : BindableObject | ||||||
|  |         { | ||||||
|  |             Grid.SetRowSpan(view, rowSpan); | ||||||
|  |             return view; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static T GridColumn<T>(this T view, int column) where T : BindableObject | ||||||
|  |         { | ||||||
|  |             Grid.SetColumn(view, column); | ||||||
|  |             return view; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static T GridColumnSpan<T>(this T view, int columnSpan) where T : BindableObject | ||||||
|  |         { | ||||||
|  |             Grid.SetColumnSpan(view, columnSpan); | ||||||
|  |             return view; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static int IndexOf<T>(this T[] array, Predicate<T> predicate) | ||||||
|  |         { | ||||||
|  |             for (var i = 0; i < array.Length; i++) | ||||||
|  |             { | ||||||
|  |                 if (predicate(array[i])) | ||||||
|  |                 { | ||||||
|  |                     return i; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static int LastIndexOf<T>(this T[] array, Predicate<T> predicate) | ||||||
|  |         { | ||||||
|  |             for (var i = array.Length - 1; i >= 0; i--) | ||||||
|  |             { | ||||||
|  |                 if (predicate(array[i])) | ||||||
|  |                 { | ||||||
|  |                     return i; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return -1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static bool All<T>(this T[] array, Predicate<T> predicate) | ||||||
|  |         { | ||||||
|  |             for (var i = 0; i < array.Length; i++) | ||||||
|  |             { | ||||||
|  |                 if (!predicate(array[i])) | ||||||
|  |                 { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static bool AnyFor<T>(this T[] array, int from, int to, Predicate<T> predicate) | ||||||
|  |         { | ||||||
|  |             for (var i = from; i <= to; i++) | ||||||
|  |             { | ||||||
|  |                 if (predicate(array[i])) | ||||||
|  |                 { | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -6,6 +6,12 @@ | |||||||
|     <AssemblyOriginatorKeyFile>..\Ref\Tsanie.snk</AssemblyOriginatorKeyFile> |     <AssemblyOriginatorKeyFile>..\Ref\Tsanie.snk</AssemblyOriginatorKeyFile> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|  |  | ||||||
|  |   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||||||
|  |     <LangVersion>9.0</LangVersion> | ||||||
|  |   </PropertyGroup> | ||||||
|  |   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||||||
|  |     <LangVersion>9.0</LangVersion> | ||||||
|  |   </PropertyGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <None Remove="System.Text.Json" /> |     <None Remove="System.Text.Json" /> | ||||||
|     <None Remove="Xamarin.Forms" /> |     <None Remove="Xamarin.Forms" /> | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ namespace Gallery.Util.Interface | |||||||
| { | { | ||||||
|     public interface IGallerySource |     public interface IGallerySource | ||||||
|     { |     { | ||||||
|         string GetCookie(); |         void SetCookie(); | ||||||
|  |  | ||||||
|         GalleryItem[] GetRecentItems(int page); |         GalleryItem[] GetRecentItems(int page); | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								Gallery.Util/Log.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								Gallery.Util/Log.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | using System; | ||||||
|  | using System.Diagnostics; | ||||||
|  |  | ||||||
|  | namespace Gallery.Util | ||||||
|  | { | ||||||
|  |     public static class Log  | ||||||
|  |     { | ||||||
|  |         public static ILog Logger { get; set; } = new DefaultLogger(); | ||||||
|  |  | ||||||
|  |         public static void Print(string message) | ||||||
|  |         { | ||||||
|  |             Logger?.Print(message); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public static void Error(string category, string message) | ||||||
|  |         { | ||||||
|  |             Logger?.Error(category, message); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public class DefaultLogger : ILog | ||||||
|  |     { | ||||||
|  |         public void Print(string message) | ||||||
|  |         { | ||||||
|  | #if DEBUG | ||||||
|  |             Debug.WriteLine("[{0:HH:mm:ss.fff}] - {1}", DateTime.Now, message); | ||||||
|  | #endif | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public void Error(string category, string message) | ||||||
|  |         { | ||||||
|  |             Debug.Fail(string.Format("[{0:HH:mm:ss.fff}] - {1} - {2}", DateTime.Now, category, message)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public interface ILog | ||||||
|  |     { | ||||||
|  |         void Print(string message); | ||||||
|  |         void Error(string category, string message); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										148
									
								
								Gallery.Util/ParallelTask.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								Gallery.Util/ParallelTask.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | |||||||
|  | using System; | ||||||
|  | using System.Threading; | ||||||
|  |  | ||||||
|  | namespace Gallery.Util | ||||||
|  | { | ||||||
|  |     public class ParallelTask : IDisposable | ||||||
|  |     { | ||||||
|  |         public static ParallelTask Start(string tag, int from, int toExclusive, int maxCount, Predicate<int> action, int tagIndex = -1, WaitCallback complete = null) | ||||||
|  |         { | ||||||
|  |             if (toExclusive <= from) | ||||||
|  |             { | ||||||
|  |                 if (complete != null) | ||||||
|  |                 { | ||||||
|  |                     ThreadPool.QueueUserWorkItem(complete); | ||||||
|  |                 } | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |             var task = new ParallelTask(tag, from, toExclusive, maxCount, action, tagIndex, complete); | ||||||
|  |             task.Start(); | ||||||
|  |             return task; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private readonly object sync = new(); | ||||||
|  |         private int count; | ||||||
|  |         private bool disposed; | ||||||
|  |  | ||||||
|  |         public int TagIndex { get; private set; } | ||||||
|  |         private readonly string tag; | ||||||
|  |         private readonly int max; | ||||||
|  |         private readonly int from; | ||||||
|  |         private readonly int to; | ||||||
|  |         private readonly Predicate<int> action; | ||||||
|  |         private readonly WaitCallback complete; | ||||||
|  |  | ||||||
|  |         private ParallelTask(string tag, int from, int to, int maxCount, Predicate<int> action, int tagIndex, WaitCallback complete) | ||||||
|  |         { | ||||||
|  |             if (maxCount <= 0) | ||||||
|  |             { | ||||||
|  |                 throw new ArgumentOutOfRangeException(nameof(maxCount)); | ||||||
|  |             } | ||||||
|  |             max = maxCount; | ||||||
|  |             if (from >= to) | ||||||
|  |             { | ||||||
|  |                 throw new ArgumentOutOfRangeException(nameof(from)); | ||||||
|  |             } | ||||||
|  |             TagIndex = tagIndex; | ||||||
|  |             this.tag = tag; | ||||||
|  |             this.from = from; | ||||||
|  |             this.to = to; | ||||||
|  |             this.action = action; | ||||||
|  |             this.complete = complete; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public void Start() | ||||||
|  |         { | ||||||
|  |             ThreadPool.QueueUserWorkItem(DoStart); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         public void Dispose() | ||||||
|  |         { | ||||||
|  |             disposed = true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private void DoStart(object state) | ||||||
|  |         { | ||||||
|  | #if DEBUG | ||||||
|  |             const long TIMEOUT = 60000L; | ||||||
|  |             var sw = new System.Diagnostics.Stopwatch(); | ||||||
|  |             long lastElapsed = 0; | ||||||
|  |             sw.Start(); | ||||||
|  | #endif | ||||||
|  |             for (int i = from; i < to; i++) | ||||||
|  |             { | ||||||
|  |                 var index = i; | ||||||
|  |                 while (count >= max) | ||||||
|  |                 { | ||||||
|  | #if DEBUG | ||||||
|  |                     var elapsed = sw.ElapsedMilliseconds; | ||||||
|  |                     if (elapsed - lastElapsed > TIMEOUT) | ||||||
|  |                     { | ||||||
|  |                         lastElapsed = elapsed; | ||||||
|  |                         Log.Print($"WARNING: parallel task ({tag}), {count} tasks in queue, cost too much time ({elapsed:n0}ms)"); | ||||||
|  |                     } | ||||||
|  | #endif | ||||||
|  |                     if (disposed) | ||||||
|  |                     { | ||||||
|  | #if DEBUG | ||||||
|  |                         sw.Stop(); | ||||||
|  |                         Log.Print($"parallel task determinate, disposed ({tag}), cost time ({elapsed:n0}ms)"); | ||||||
|  | #endif | ||||||
|  |                         return; | ||||||
|  |                     } | ||||||
|  |                     Thread.Sleep(16); | ||||||
|  |                 } | ||||||
|  |                 lock (sync) | ||||||
|  |                 { | ||||||
|  |                     count++; | ||||||
|  |                 } | ||||||
|  |                 ThreadPool.QueueUserWorkItem(o => | ||||||
|  |                 { | ||||||
|  |                     try | ||||||
|  |                     { | ||||||
|  |                         if (!action(index)) | ||||||
|  |                         { | ||||||
|  |                             disposed = true; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     catch (Exception ex) | ||||||
|  |                     { | ||||||
|  |                         Log.Error($"parallel.start ({tag})", $"failed to run action, index: {index}, error: {ex}"); | ||||||
|  |                     } | ||||||
|  |                     finally | ||||||
|  |                     { | ||||||
|  |                         lock (sync) | ||||||
|  |                         { | ||||||
|  |                             count--; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             while (count > 0) | ||||||
|  |             { | ||||||
|  | #if DEBUG | ||||||
|  |                 var elapsed = sw.ElapsedMilliseconds; | ||||||
|  |                 if (elapsed - lastElapsed > TIMEOUT) | ||||||
|  |                 { | ||||||
|  |                     lastElapsed = elapsed; | ||||||
|  |                     Log.Print($"WARNING: parallel task ({tag}), {count} ending tasks in queue, cost too much time ({elapsed:n0}ms)"); | ||||||
|  |                 } | ||||||
|  | #endif | ||||||
|  |                 if (disposed) | ||||||
|  |                 { | ||||||
|  | #if DEBUG | ||||||
|  |                     sw.Stop(); | ||||||
|  |                     Log.Print($"parallel task determinate, disposed ({tag}), ending cost time ({elapsed:n0}ms)"); | ||||||
|  | #endif | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 Thread.Sleep(16); | ||||||
|  |             } | ||||||
|  | #if DEBUG | ||||||
|  |             sw.Stop(); | ||||||
|  |             Log.Print($"parallel task done ({tag}), cost time ({sw.ElapsedMilliseconds:n0}ms)"); | ||||||
|  | #endif | ||||||
|  |             complete?.Invoke(null); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -30,6 +30,7 @@ | |||||||
|     <MtouchDebug>true</MtouchDebug> |     <MtouchDebug>true</MtouchDebug> | ||||||
|     <CodesignProvision>Gallery.Dev</CodesignProvision> |     <CodesignProvision>Gallery.Dev</CodesignProvision> | ||||||
|     <CodesignKey>Apple Development: Li Chen (5559SN7Z38)</CodesignKey> |     <CodesignKey>Apple Development: Li Chen (5559SN7Z38)</CodesignKey> | ||||||
|  |     <LangVersion>9.0</LangVersion> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' "> |   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' "> | ||||||
|     <DebugType>none</DebugType> |     <DebugType>none</DebugType> | ||||||
| @@ -41,6 +42,7 @@ | |||||||
|     <MtouchArch>x86_64</MtouchArch> |     <MtouchArch>x86_64</MtouchArch> | ||||||
|     <CodesignProvision>Gallery.Ad-Hoc</CodesignProvision> |     <CodesignProvision>Gallery.Ad-Hoc</CodesignProvision> | ||||||
|     <CodesignKey>Apple Distribution: Li Chen (7HSM5CKPJ2)</CodesignKey> |     <CodesignKey>Apple Distribution: Li Chen (7HSM5CKPJ2)</CodesignKey> | ||||||
|  |     <LangVersion>9.0</LangVersion> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' "> |   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' "> | ||||||
|     <DebugSymbols>true</DebugSymbols> |     <DebugSymbols>true</DebugSymbols> | ||||||
| @@ -57,6 +59,7 @@ | |||||||
|     <MtouchLink>None</MtouchLink> |     <MtouchLink>None</MtouchLink> | ||||||
|     <MtouchInterpreter>-all</MtouchInterpreter> |     <MtouchInterpreter>-all</MtouchInterpreter> | ||||||
|     <CodesignProvision>Gallery.Dev</CodesignProvision> |     <CodesignProvision>Gallery.Dev</CodesignProvision> | ||||||
|  |     <LangVersion>9.0</LangVersion> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' "> |   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' "> | ||||||
|     <DebugType>none</DebugType> |     <DebugType>none</DebugType> | ||||||
| @@ -69,6 +72,7 @@ | |||||||
|     <CodesignEntitlements>Entitlements.plist</CodesignEntitlements> |     <CodesignEntitlements>Entitlements.plist</CodesignEntitlements> | ||||||
|     <CodesignProvision>Gallery.Ad-Hoc</CodesignProvision> |     <CodesignProvision>Gallery.Ad-Hoc</CodesignProvision> | ||||||
|     <MtouchLink>SdkOnly</MtouchLink> |     <MtouchLink>SdkOnly</MtouchLink> | ||||||
|  |     <LangVersion>9.0</LangVersion> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <Compile Include="Main.cs" /> |     <Compile Include="Main.cs" /> | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										19
									
								
								Gallery.sln
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								Gallery.sln
									
									
									
									
									
								
							| @@ -9,6 +9,10 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Gallery.Share", "Gallery.Sh | |||||||
| EndProject | EndProject | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gallery.Util", "Gallery.Util\Gallery.Util.csproj", "{222C22EC-3A47-4CF5-B9FB-CA28DE9F4BC8}" | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gallery.Util", "Gallery.Util\Gallery.Util.csproj", "{222C22EC-3A47-4CF5-B9FB-CA28DE9F4BC8}" | ||||||
| EndProject | EndProject | ||||||
|  | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GallerySources", "GallerySources", "{F37B4FEC-D2B1-4289-BA6D-A154F783572A}" | ||||||
|  | EndProject | ||||||
|  | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gallery.Yandere", "GallerySources\Gallery.Yandere\Gallery.Yandere.csproj", "{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}" | ||||||
|  | EndProject | ||||||
| Global | Global | ||||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||||
| 		Debug|iPhoneSimulator = Debug|iPhoneSimulator | 		Debug|iPhoneSimulator = Debug|iPhoneSimulator | ||||||
| @@ -43,6 +47,18 @@ Global | |||||||
| 		{222C22EC-3A47-4CF5-B9FB-CA28DE9F4BC8}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{222C22EC-3A47-4CF5-B9FB-CA28DE9F4BC8}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{222C22EC-3A47-4CF5-B9FB-CA28DE9F4BC8}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{222C22EC-3A47-4CF5-B9FB-CA28DE9F4BC8}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{222C22EC-3A47-4CF5-B9FB-CA28DE9F4BC8}.Release|Any CPU.Build.0 = Release|Any CPU | 		{222C22EC-3A47-4CF5-B9FB-CA28DE9F4BC8}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Debug|iPhone.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Debug|iPhone.Build.0 = Debug|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Release|iPhone.ActiveCfg = Release|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Release|iPhone.Build.0 = Release|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(SolutionProperties) = preSolution | 	GlobalSection(SolutionProperties) = preSolution | ||||||
| 		HideSolutionNode = FALSE | 		HideSolutionNode = FALSE | ||||||
| @@ -50,4 +66,7 @@ Global | |||||||
| 	GlobalSection(ExtensibilityGlobals) = postSolution | 	GlobalSection(ExtensibilityGlobals) = postSolution | ||||||
| 		SolutionGuid = {A969B750-3E3E-4815-B336-02B32908D0C4} | 		SolutionGuid = {A969B750-3E3E-4815-B336-02B32908D0C4} | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
|  | 	GlobalSection(NestedProjects) = preSolution | ||||||
|  | 		{F7ECCC03-28AC-4326-B0D1-F24C08808B9F} = {F37B4FEC-D2B1-4289-BA6D-A154F783572A} | ||||||
|  | 	EndGlobalSection | ||||||
| EndGlobal | EndGlobal | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								GallerySources/Gallery.Yandere/Gallery.Yandere.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								GallerySources/Gallery.Yandere/Gallery.Yandere.csproj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | <Project Sdk="Microsoft.NET.Sdk"> | ||||||
|  |  | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <TargetFramework>netstandard2.1</TargetFramework> | ||||||
|  |   </PropertyGroup> | ||||||
|  |  | ||||||
|  |   <ItemGroup> | ||||||
|  |     <ProjectReference Include="..\..\Gallery.Util\Gallery.Util.csproj" /> | ||||||
|  |   </ItemGroup> | ||||||
|  | </Project> | ||||||
		Reference in New Issue
	
	Block a user