add Android version

This commit is contained in:
Tsanie Lily 2020-05-11 23:18:38 +08:00
parent 9f5685a2f8
commit 4561bc2674
53 changed files with 14716 additions and 63 deletions

@ -0,0 +1,19 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories) and given a Build Action of "AndroidAsset".
These files will be deployed with your package and will be accessible using Android's
AssetManager, like this:
public class ReadAsset : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
InputStream input = Assets.Open ("my_asset.txt");
}
}
Additionally, some Android functions will automatically load asset files:
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,49 @@
using Pixiview.Droid.Effects;
using Pixiview.Utils;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using static Android.Views.View;
[assembly: ResolutionGroupName("Pixiview")]
[assembly: ExportEffect(typeof(LongPressEffectImplement), "LongPressEffect")]
namespace Pixiview.Droid.Effects
{
public class LongPressEffectImplement : PlatformEffect
{
private bool attached;
protected override void OnAttached()
{
if (!attached)
{
attached = true;
Control.LongClick += Container_LongClick;
}
}
protected override void OnDetached()
{
if (attached)
{
attached = false;
Control.LongClick -= Container_LongClick;
}
}
private void Container_LongClick(object sender, LongClickEventArgs e)
{
var element = Element;
if (element != null)
{
var command = LongPressEffect.GetCommand(element);
if (command != null)
{
e.Handled = true;
var o = LongPressEffect.GetCommandParameter(element);
command.Execute(o);
}
}
}
}
}

@ -0,0 +1,9 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Style", "IDE0056:Use index operator", Justification = "<Pending>")]
[assembly: SuppressMessage("Style", "IDE0066:Convert switch statement to expression", Justification = "<Pending>")]

@ -0,0 +1,35 @@
using Android.App;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
namespace Pixiview.Droid
{
[Activity(Label = "Pixiview", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity Main { get; private set; }
protected override void OnCreate(Bundle savedInstanceState)
{
Main = this;
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Code Notifications", "XA0001:Find issues with Android API usage", Justification = "<Pending>")]
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B695E0C4-084A-456D-B075-718E55BA1FD6}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TemplateGuid>{c9e5eea5-ca05-42a1-839b-61506e0a37df}</TemplateGuid>
<OutputType>Library</OutputType>
<RootNamespace>Pixiview.Droid</RootNamespace>
<AssemblyName>Pixiview.Android</AssemblyName>
<Deterministic>True</Deterministic>
<AndroidApplication>True</AndroidApplication>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<AndroidResgenClass>Resource</AndroidResgenClass>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
<AndroidUseAapt2>true</AndroidUseAapt2>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidManagedSymbols>true</AndroidManagedSymbols>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<AndroidCreatePackagePerAbi>true</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>arm64-v8a</AndroidSupportedAbis>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Forms" Version="4.6.0.726" />
<PackageReference Include="Xamarin.Essentials" Version="1.5.3.1" />
<PackageReference Include="Newtonsoft.Json">
<Version>12.0.3</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="MainActivity.cs" />
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Effects\LongPressEffectImplement.cs" />
<Compile Include="Renderers\CircleImageRenderer.cs" />
<Compile Include="Renderers\CardViewRenderer.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
<None Include="Properties\AndroidManifest.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\Tabbar.xml" />
<AndroidResource Include="Resources\layout\Toolbar.xml" />
<AndroidResource Include="Resources\values\styles.xml" />
<AndroidResource Include="Resources\values\colors.xml" />
<AndroidResource Include="Resources\drawable\download.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\drawable\userprofile.jpg">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-xxxhdpi\icon_foreground.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-xxxhdpi\icon_round.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-xxxhdpi\icon.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-xxhdpi\icon_foreground.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-xxhdpi\icon_round.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-xxhdpi\icon.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-xhdpi\icon_foreground.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-xhdpi\icon_round.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-xhdpi\icon.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-mdpi\icon_foreground.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-mdpi\icon_round.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-mdpi\icon.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-hdpi\icon_foreground.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-hdpi\icon_round.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-hdpi\icon.png">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon_round.xml">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon.xml">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\drawable\" />
<Folder Include="Effects\" />
<Folder Include="Resources\mipmap-anydpi-v26\" />
<Folder Include="Resources\mipmap-hdpi\" />
<Folder Include="Resources\mipmap-mdpi\" />
<Folder Include="Resources\mipmap-xhdpi\" />
<Folder Include="Resources\mipmap-xxhdpi\" />
<Folder Include="Resources\mipmap-xxxhdpi\" />
<Folder Include="Renderers\" />
</ItemGroup>
<ItemGroup>
<AndroidAsset Include="Assets\fa-light-300.ttf" />
<AndroidAsset Include="Assets\fa-regular-400.ttf" />
<AndroidAsset Include="Assets\fa-solid-900.ttf" />
</ItemGroup>
<Import Project="..\Pixiview\Pixiview.projitems" Label="Shared" Condition="Exists('..\Pixiview\Pixiview.projitems')" />
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
</Project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0.511" package="org.tsanie.pixiview" android:versionCode="2">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
<application android:label="Pixiview" android:icon="@mipmap/icon" android:roundIcon="@mipmap/icon_round"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

@ -0,0 +1,30 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Android.App;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Pixiview.Android")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Pixiview.Android")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
// Add some common permissions, these can be removed if not needed
[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]

@ -0,0 +1,65 @@
using Android.Content;
using Android.Graphics;
using Android.Views;
using Pixiview.Droid.Renderers;
using Pixiview.UI;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(CardView), typeof(CardViewRenderer))]
namespace Pixiview.Droid.Renderers
{
public class CardViewRenderer : VisualElementRenderer<CardView>
{
ViewOutlineProvider original;
public CardViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<CardView> e)
{
base.OnElementChanged(e);
var element = e.NewElement;
if (element != null)
{
var radius = element.CornerRadius;
if (radius > 0)
{
original = OutlineProvider;
OutlineProvider = new CornerRadiusOutlineProvider(element, radius);
ClipToOutline = true;
}
}
}
protected override void OnDetachedFromWindow()
{
OutlineProvider = original;
base.OnDetachedFromWindow();
}
private class CornerRadiusOutlineProvider : ViewOutlineProvider
{
private readonly Element element;
private readonly float radius;
public CornerRadiusOutlineProvider(Element from, float r)
{
element = from;
radius = r;
}
public override void GetOutline(Android.Views.View view, Outline outline)
{
var scale = view.Resources.DisplayMetrics.Density;
var width = (double)element.GetValue(VisualElement.WidthProperty) * scale;
var height = (double)element.GetValue(VisualElement.HeightProperty) * scale;
var rect = new Rect(0, 0, (int)width, (int)height);
outline.SetRoundRect(rect, radius * scale);
}
}
}
}

@ -0,0 +1,66 @@
using System;
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Pixiview.Droid.Renderers;
using Pixiview.UI;
using Xamarin.Forms;
[assembly: ExportRenderer(typeof(CircleImage), typeof(CircleImageRenderer))]
namespace Pixiview.Droid.Renderers
{
public class CircleImageRenderer : Xamarin.Forms.Platform.Android.FastRenderers.ImageRenderer
{
private Paint paint;
private int radius;
private float scale;
public CircleImageRenderer(Context context) : base(context)
{
}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
int size = Math.Min(MeasuredWidth, MeasuredHeight);
radius = size / 2;
SetMeasuredDimension(size, size);
}
protected override void OnDraw(Canvas canvas)
{
paint = new Paint();
var bitmap = DrawableToBitmap(Drawable);
if (bitmap == null)
{
base.OnDraw(canvas);
return;
}
var bitmapShader = new BitmapShader(bitmap, Shader.TileMode.Clamp, Shader.TileMode.Clamp);
scale = radius * 2.0f / Math.Min(bitmap.Width, bitmap.Height);
var matrix = new Matrix();
matrix.SetScale(scale, scale);
bitmapShader.SetLocalMatrix(matrix);
paint.SetShader(bitmapShader);
canvas.DrawCircle(radius, radius, radius, paint);
}
private Bitmap DrawableToBitmap(Drawable drawable)
{
if (drawable is BitmapDrawable bd)
{
return bd.Bitmap;
}
int w = drawable.IntrinsicWidth;
int h = drawable.IntrinsicHeight;
var bitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888);
var canvas = new Canvas(bitmap);
drawable.SetBounds(0, 0, w, h);
drawable.Draw(canvas);
return bitmap;
}
}
}

@ -0,0 +1,50 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.xml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable-hdpi/
icon.png
drawable-ldpi/
icon.png
drawable-mdpi/
icon.png
layout/
main.xml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called
"Resource" that contains the tokens for each one of the resources included. For example,
for the above Resources layout, this is what the Resource class would expose:
public class Resource {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

(image error) Size: 1.9 KiB

Binary file not shown.

After

(image error) Size: 20 KiB

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TabLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/sliding_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:tabIndicatorColor="@android:color/white" app:tabGravity="fill" app:tabMode="fixed" />

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/icon_background"/>
<foreground android:drawable="@mipmap/icon_foreground"/>
</adaptive-icon>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/icon_background"/>
<foreground android:drawable="@mipmap/icon_foreground"/>
</adaptive-icon>

Binary file not shown.

After

(image error) Size: 1.6 KiB

Binary file not shown.

After

(image error) Size: 2.0 KiB

Binary file not shown.

After

(image error) Size: 3.6 KiB

Binary file not shown.

After

(image error) Size: 1.2 KiB

Binary file not shown.

After

(image error) Size: 1.3 KiB

Binary file not shown.

After

(image error) Size: 2.3 KiB

Binary file not shown.

After

(image error) Size: 2.3 KiB

Binary file not shown.

After

(image error) Size: 2.7 KiB

Binary file not shown.

After

(image error) Size: 5.1 KiB

Binary file not shown.

After

(image error) Size: 3.5 KiB

Binary file not shown.

After

(image error) Size: 4.6 KiB

Binary file not shown.

After

(image error) Size: 8.0 KiB

Binary file not shown.

After

(image error) Size: 4.9 KiB

Binary file not shown.

After

(image error) Size: 6.6 KiB

Binary file not shown.

After

(image error) Size: 12 KiB

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="icon_background">#1999F7</color>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MainTheme" parent="MainTheme.Base">
</style>
<!-- Base theme applied no matter what API -->
<style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
<!--If you are using revision 22.1 please use just windowNoTitle. Without android:-->
<item name="windowNoTitle">true</item>
<!--We will be using the toolbar so no need to show ActionBar-->
<item name="windowActionBar">false</item>
<!-- Set theme colors from https://aka.ms/material-colors -->
<!-- colorPrimary is used for the default action bar background -->
<item name="colorPrimary">#2196F3</item>
<!-- colorPrimaryDark is used for the status bar -->
<item name="colorPrimaryDark">#1976D2</item>
<!-- colorAccent is used as the default value for colorControlActivated
which is used to tint widgets -->
<item name="colorAccent">#FF4081</item>
<!-- You can also set colorControlNormal, colorControlActivated
colorControlHighlight and colorSwitchThumbNormal. -->
<item name="windowActionModeOverlay">true</item>
<item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
</style>
<style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
<item name="colorAccent">#FF4081</item>
</style>
</resources>

@ -14,10 +14,8 @@
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<string>2</string>
<key>MinimumOSVersion</key>
<string>13.4</string>
<key>NSExtension</key>
@ -32,5 +30,7 @@
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
<key>CFBundleShortVersionString</key>
<string>1.0.511</string>
</dict>
</plist>

@ -1,5 +1,4 @@
using System.Threading.Tasks;
using Pixiview.iOS.Effects;
using Pixiview.iOS.Effects;
using Pixiview.Utils;
using UIKit;
using Xamarin.Forms;

@ -26,8 +26,6 @@
<string>Pixiview</string>
<key>CFBundleIdentifier</key>
<string>org.tsanie.Pixiview</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>CFBundleName</key>
@ -80,5 +78,9 @@
</array>
</dict>
</array>
<key>CFBundleShortVersionString</key>
<string>1.0.511</string>
<key>CFBundleVersion</key>
<string>2</string>
</dict>
</plist>

@ -3,11 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pixiview.iOS", "Pixiview.iOS\Pixiview.iOS.csproj", "{0CDD279E-3CAB-4CCA-A7C4-BC499724D051}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pixiview", "Pixiview\Pixiview.shproj", "{57C27E64-049B-4EE8-9308-BCAFE329E8E8}"
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Pixiview", "Pixiview\Pixiview.shproj", "{57C27E64-049B-4EE8-9308-BCAFE329E8E8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pixiview.iOS.OpenExtension", "Pixiview.iOS.OpenExtension\Pixiview.iOS.OpenExtension.csproj", "{618D8350-495C-42D0-9DAC-87ADD36AC727}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "Pixiview.Android", "Pixiview.Android\Pixiview.Android.csproj", "{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pixiview.Android", "Pixiview.Android\Pixiview.Android.csproj", "{B695E0C4-084A-456D-B075-718E55BA1FD6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -43,17 +43,17 @@ Global
{618D8350-495C-42D0-9DAC-87ADD36AC727}.Debug|iPhone.Build.0 = Debug|iPhone
{618D8350-495C-42D0-9DAC-87ADD36AC727}.Release|iPhone.ActiveCfg = Release|iPhone
{618D8350-495C-42D0-9DAC-87ADD36AC727}.Release|iPhone.Build.0 = Release|iPhone
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Release|Any CPU.Build.0 = Release|Any CPU
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Debug|iPhone.Build.0 = Debug|Any CPU
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Release|iPhone.ActiveCfg = Release|Any CPU
{FBB80F2B-0C2B-4BE5-A578-853AA0AF9F4A}.Release|iPhone.Build.0 = Release|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Release|Any CPU.Build.0 = Release|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Debug|iPhone.Build.0 = Debug|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Release|iPhone.ActiveCfg = Release|Any CPU
{B695E0C4-084A-456D-B075-718E55BA1FD6}.Release|iPhone.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

@ -74,11 +74,13 @@ namespace Pixiview
{
themeInstance = LightTheme.Instance;
}
#if __ANDROID__
EnvironmentService.SetStatusBarColor
#endif
#if __IOS__
var style = (StatusBarStyles)themeInstance[ThemeBase.StatusBarStyle];
EnvironmentService.SetStatusBarStyle(style);
#elif __ANDROID__
var color = (Color)themeInstance[ThemeBase.NavColor];
EnvironmentService.SetStatusBarColor(color);
#endif
Resources = themeInstance;
}

@ -32,7 +32,7 @@
</Shell.FlyoutHeaderTemplate>
<Shell.ItemTemplate>
<DataTemplate x:DataType="BaseShellItem">
<Grid>
<Grid HeightRequest="{x:OnPlatform Android=40}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">

@ -19,10 +19,9 @@
ItemTemplate="{StaticResource cardView}"/>
</ScrollView>
<u:BlurryPanel VerticalOptions="Start" HeightRequest="50" Margin="{Binding PanelTopMargin}"/>
<SearchBar Placeholder="{r:Text Search}" HeightRequest="50"
<SearchBar x:Name="searchBar" Placeholder="{r:Text Search}" HeightRequest="50"
VerticalOptions="Start"
Margin="{Binding PageTopMargin}"
BackgroundColor="Transparent"
CancelButtonColor="{DynamicResource TintColor}"
Text="{Binding Keywords, Mode=TwoWay}"
SearchButtonPressed="SearchBar_SearchButtonPressed"

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
using Pixiview.UI;
using Pixiview.Utils;
using Xamarin.Essentials;
using Xamarin.Forms;
@ -24,6 +23,14 @@ namespace Pixiview.Illust
{
Resources.Add("cardView", GetCardViewTemplate());
InitializeComponent();
#if __IOS__
searchBar.BackgroundColor = Color.Transparent;
#elif __ANDROID__
searchBar.SetDynamicResource(SearchBar.TextColorProperty, UI.Theme.ThemeBase.TextColor);
searchBar.SetDynamicResource(SearchBar.PlaceholderColorProperty, UI.Theme.ThemeBase.SubTextColor);
searchBar.SetDynamicResource(BackgroundColorProperty, UI.Theme.ThemeBase.WindowColor);
#endif
}
protected override bool IsLazyload => true;

@ -7,7 +7,12 @@
BackgroundColor="{DynamicResource WindowColor}">
<Shell.TitleView>
<StackLayout Orientation="Horizontal" Padding="0, 2, 0, 4">
<u:CircleImage Aspect="AspectFill" Source="{Binding UserIcon}"/>
<u:CircleImage Aspect="AspectFill" Source="{Binding UserIcon}"
WidthRequest="{x:OnPlatform Android=40}">
<u:CircleImage.Margin>
<OnPlatform x:TypeArguments="Thickness" Android="0, 5, 0, 5"/>
</u:CircleImage.Margin>
</u:CircleImage>
<Label Text="{Binding IllustItem.UserName}" Margin="10, 0, 0, 0"
VerticalOptions="Center" LineBreakMode="TailTruncation"
TextColor="{DynamicResource TextColor}"/>

@ -18,7 +18,7 @@
<CarouselView ItemsSource="{Binding Illusts}" HorizontalScrollBarVisibility="Never"
PositionChanged="CarouselView_PositionChanged">
<CarouselView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" ItemSpacing="20"/>
<LinearItemsLayout Orientation="Vertical" ItemSpacing="20"/>
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<DataTemplate x:DataType="mdl:IllustDetailItem">

@ -17,6 +17,7 @@ namespace Pixiview.Illust
{
public static readonly BindableProperty FavoriteIconProperty = BindableProperty.Create(
nameof(FavoriteIcon), typeof(ImageSource), typeof(ViewIllustPage));
public static readonly BindableProperty IllustsProperty = BindableProperty.Create(
nameof(Illusts), typeof(IllustDetailItem[]), typeof(ViewIllustPage));
public static readonly BindableProperty PagePositionTextProperty = BindableProperty.Create(
@ -345,7 +346,7 @@ namespace Pixiview.Illust
{
MainThread.BeginInvokeOnMainThread(async () =>
{
var result = await FileStore.SaveImageToGalleryAsync(image);
var result = await FileStore.SaveImageToGalleryAsync(image, item.OriginalUrl);
string message = result ?? ResourceHelper.SaveSuccess;
await DisplayAlert(ResourceHelper.Title, message, ResourceHelper.Ok);

@ -68,9 +68,9 @@ namespace Pixiview.Resources
#if __IOS__
var langId = $"Pixiview.iOS.Resources.Languages.{lang.Language}.xml";
var langCodeId = $"Pixiview.iOS.Resources.Languages.{lang.LanguageCode}.xml";
#else
var langId = $"Pixiview.Android.Resources.Languages.{lang.Language}.xml";
var langCodeId = $"Pixiview.Android.Resources.Languages.{lang.LanguageCode}.xml";
#elif __ANDROID__
var langId = $"Pixiview.Droid.Resources.Languages.{lang.Language}.xml";
var langCodeId = $"Pixiview.Droid.Resources.Languages.{lang.LanguageCode}.xml";
#endif
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(LanguageResource)).Assembly;
var names = assembly.GetManifestResourceNames();
@ -81,8 +81,8 @@ namespace Pixiview.Resources
{
#if __IOS__
name = "Pixiview.iOS.Resources.Languages.zh-CN.xml";
#else
name = "Pixiview.Android.Resources.Languages.zh-CN.xml";
#elif __ANDROID__
name = "Pixiview.Droid.Resources.Languages.zh-CN.xml";
#endif
}
var xml = new XmlDocument();

@ -1,5 +1,4 @@
using System;
using Xamarin.Essentials;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Pixiview.UI
@ -25,8 +24,12 @@ namespace Pixiview.UI
public const string IconSolidFontFamily = "FontAwesome5Pro-Solid";
public const string IconLeft = "\uf104";
#else
// TODO
#elif __ANDROID__
public const string IconLightFontFamily = "fa-light-300.ttf#FontAwesome5Pro-Light";
public const string IconRegularFontFamily = "fa-regular-400.ttf#FontAwesome5Pro-Regular";
public const string IconSolidFontFamily = "fa-solid-900.ttf#FontAwesome5Pro-Solid";
public const string IconLeft = "\uf053";
#endif
public const string IconUser = "\uf007";
@ -103,7 +106,7 @@ namespace Pixiview.UI
}
#endif
}
catch (Exception ex)
catch (System.Exception ex)
{
App.DebugError("device.get", $"failed to get the device model. {ex.Message}");
}

@ -1,11 +1,15 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Globalization;
using System.Threading;
using Pixiview.Resources;
#if __IOS__
using System.Diagnostics.CodeAnalysis;
using Foundation;
using UIKit;
#elif __ANDROID__
using Android.OS;
using Xamarin.Forms.Platform.Android;
#endif
using Xamarin.Forms;
namespace Pixiview.Utils
{
@ -40,8 +44,19 @@ namespace Pixiview.Utils
}
//*/
public static void SetStatusBarColor(Color color)
{
#if __ANDROID_21__
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
{
Droid.MainActivity.Main.SetStatusBarColor(color.ToAndroid());
}
#endif
}
public static void SetStatusBarStyle(StatusBarStyles style)
{
#if __IOS__
SetStatusBarStyle(ConvertStyle(style));
}
@ -78,6 +93,9 @@ namespace Pixiview.Utils
return UIStatusBarStyle.Default;
}
}
#else
}
#endif
#endregion
@ -94,6 +112,8 @@ namespace Pixiview.Utils
public static CultureInfo GetCurrentCultureInfo()
{
string lang;
#if __IOS__
if (NSLocale.PreferredLanguages.Length > 0)
{
var pref = NSLocale.PreferredLanguages[0];
@ -103,6 +123,10 @@ namespace Pixiview.Utils
{
lang = "zh-CN";
}
#elif __ANDROID__
var locale = Java.Util.Locale.Default;
lang = AndroidToDotnetLanguage(locale.ToString().Replace('_', '-'));
#endif
CultureInfo ci;
var platform = new PlatformCulture(lang);
@ -128,6 +152,7 @@ namespace Pixiview.Utils
return ci;
}
#if __IOS__
[SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
private static string iOSToDotnetLanguage(string iOSLanguage)
{
@ -153,6 +178,35 @@ namespace Pixiview.Utils
App.DebugPrint($"iOS Language: {iOSLanguage}, .NET Language/Locale: {netLanguage}");
return netLanguage;
}
#elif __ANDROID__
private static string AndroidToDotnetLanguage(string androidLanguage)
{
string netLanguage;
//certain languages need to be converted to CultureInfo equivalent
switch (androidLanguage)
{
case "ms-BN": // "Malaysian (Brunei)" not supported .NET culture
case "ms-MY": // "Malaysian (Malaysia)" not supported .NET culture
case "ms-SG": // "Malaysian (Singapore)" not supported .NET culture
netLanguage = "ms"; // closest supported
break;
case "in-ID": // "Indonesian (Indonesia)" has different code in .NET
netLanguage = "id-ID"; // correct code for .NET
break;
case "gsw-CH": // "Schwiizertüütsch (Swiss German)" not supported .NET culture
netLanguage = "de-CH"; // closest supported
break;
// add more application-specific cases here (if required)
// ONLY use cultures that have been tested and known to work
default:
netLanguage = androidLanguage;
break;
}
App.DebugPrint($"Android Language: {androidLanguage}, .NET Language/Locale: {netLanguage}");
return netLanguage;
}
#endif
private static string ToDotnetFallbackLanguage(PlatformCulture platCulture)
{

@ -2,15 +2,18 @@
using Xamarin.Forms;
#if __IOS__
using Xamarin.Forms.Platform.iOS;
#else
using Xamarin.Forms.Platform.Android;
#elif __ANDROID__
using Android.Content;
using Android.Net;
using System.IO;
using System.Linq;
#endif
namespace Pixiview.Utils
{
public class FileStore
{
public static Task<string> SaveImageToGalleryAsync(ImageSource image)
public static Task<string> SaveImageToGalleryAsync(ImageSource image, string url = null)
{
#if __IOS__
IImageSourceHandler renderer;
@ -41,8 +44,31 @@ namespace Pixiview.Utils
});
}
return task.Task;
#else
// TODO
#elif __ANDROID__
Java.IO.File camera;
var dirs = Droid.MainActivity.Main.GetExternalMediaDirs();
camera = dirs.FirstOrDefault();
if (camera == null)
{
camera = Droid.MainActivity.Main.GetExternalFilesDir(Android.OS.Environment.DirectoryPictures);
}
if (!camera.Exists())
{
camera.Mkdirs();
}
var filename = Path.GetFileName(url);
var imgFile = new Java.IO.File(camera, filename).AbsolutePath;
File.Copy(((FileImageSource)image).File, imgFile);
var uri = Uri.FromFile(new Java.IO.File(imgFile));
var intent = new Intent(Intent.ActionMediaScannerScanFile);
intent.SetData(uri);
Droid.MainActivity.Main.SendBroadcast(intent);
var task = new TaskCompletionSource<string>();
task.SetResult(null);
return task.Task;
#endif
}
}

@ -16,7 +16,11 @@ namespace Pixiview.Utils
public static class Stores
{
public static readonly string PersonalFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
#if __IOS__
public static readonly string CacheFolder = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache);
#elif __ANDROID__
public static readonly string CacheFolder = FileSystem.CacheDirectory;
#endif
private const string favoriteFile = "favorites.json";
private const string imageFolder = "img-original";
@ -492,27 +496,17 @@ namespace Pixiview.Utils
public const string SuffixPreload = " id=\"meta-preload-data\" content='";
public const int SuffixPreloadLength = 33; // SuffixPreload.Length
public static string UrlIllustList => Prefix + "ajax/top/illust?mode=all&lang=zh";
public static string UrlIllust = Prefix + "artworks/{0}";
public static string UrlIllustUserAll = Prefix + "ajax/user/{0}/profile/all?lang=zh";
public static string UrlIllustUserArtworks = Prefix + "ajax/user/{0}/profile/illusts?{1}work_category=illustManga&is_first_page={2}&lang=zh";
public static string UrlIllustUser = Prefix + "users/{0}/artworks";
public static string UrlIllustPage = Prefix + "ajax/illust/{0}/pages?lang=zh";
public static string UrlIllust => Prefix + "artworks/{0}";
public static string UrlIllustUserAll => Prefix + "ajax/user/{0}/profile/all?lang=zh";
public static string UrlIllustUserArtworks => Prefix + "ajax/user/{0}/profile/illusts?{1}work_category=illustManga&is_first_page={2}&lang=zh";
public static string UrlIllustUser => Prefix + "users/{0}/artworks";
public static string UrlIllustPage => Prefix + "ajax/illust/{0}/pages?lang=zh";
public const string UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36";
public const string AcceptImage = "image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5";
public const string AcceptJson = "application/json";
//public const string AcceptEncoding = "gzip, deflate";
public const string AcceptLanguage = "zh-cn";
//public const string UserId = "2603358";
//public const string Cookie =
// "PHPSESSID=2603358_VHyGPeRaz7LpeoFkRsHvjXIpApCMb56a; " +
// "a_type=0; b_type=1; c_type=31; d_type=2; " +
// "p_ab_id=2; p_ab_id_2=6; p_ab_d_id=1155161977; " +
// "privacy_policy_agreement=2; " +
// "login_ever=yes; " +
// "__cfduid=d9fa2d4d1ddd30db85ebb519f9855d2561587806747; " +
// "first_visit_datetime_pc=2019-10-29+22%3A05%3A30; " +
// "yuid_b=NgcXQWQ";
public const string UserId = "53887721";
public const string Cookie =
"PHPSESSID=5sn8n049j5c18l0tlj91qrjhesgddhjv; " +