initial
405
.gitignore
vendored
Normal file
@ -0,0 +1,405 @@
|
||||
# globs
|
||||
Makefile.in
|
||||
*.userprefs
|
||||
*.usertasks
|
||||
config.make
|
||||
config.status
|
||||
aclocal.m4
|
||||
install-sh
|
||||
autom4te.cache/
|
||||
*.tar.gz
|
||||
tarballs/
|
||||
test-results/
|
||||
|
||||
# Mac bundle stuff
|
||||
*.dmg
|
||||
*.app
|
||||
|
||||
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# content below from: https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
61
Billing.Shared/App.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using Billing.Languages;
|
||||
using Billing.Themes;
|
||||
using Xamarin.Essentials;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Billing;
|
||||
|
||||
public class App : Application
|
||||
{
|
||||
public static AppTheme CurrentTheme { get; private set; }
|
||||
public static PlatformCulture CurrentCulture { get; private set; }
|
||||
|
||||
public App()
|
||||
{
|
||||
CurrentCulture = new PlatformCulture();
|
||||
InitResources();
|
||||
|
||||
MainPage = new MainShell();
|
||||
Shell.Current.GoToAsync("//Bills");
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
SetTheme(AppInfo.RequestedTheme);
|
||||
}
|
||||
|
||||
private void InitResources()
|
||||
{
|
||||
var theme = AppInfo.RequestedTheme;
|
||||
SetTheme(theme, true);
|
||||
}
|
||||
|
||||
private void SetTheme(AppTheme theme, bool force = false)
|
||||
{
|
||||
if (force || theme != CurrentTheme)
|
||||
{
|
||||
CurrentTheme = theme;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
Helper.Debug($"application theme: {theme}");
|
||||
|
||||
BaseTheme instance;
|
||||
if (theme == AppTheme.Dark)
|
||||
{
|
||||
instance = Dark.Instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
instance = Light.Instance;
|
||||
}
|
||||
// TODO: status bar
|
||||
Resources = instance;
|
||||
}
|
||||
}
|
3
Billing.Shared/AssemblyInfo.cs
Normal file
@ -0,0 +1,3 @@
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
|
73
Billing.Shared/Billing.Shared.projitems
Normal file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' < '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
<HasSharedItems>true</HasSharedItems>
|
||||
<SharedGUID>6ac75d01-70d6-4a07-8685-bc52afd97a7a</SharedGUID>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration">
|
||||
<Import_RootNamespace>Billing</Import_RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Languages\en.xml" />
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Languages\zh-CN.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)App.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)AssemblyInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Helper.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Languages\PlatformCulture.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Languages\Resource.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)MainShell.xaml.cs">
|
||||
<DependentUpon>MainShell.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Themes\BaseTheme.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Themes\Dark.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Themes\Light.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)UI\BillingDate.xaml.cs">
|
||||
<DependentUpon>BillingDate.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)UI\BillingPage.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)UI\Converters.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)UI\CustomControl.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)UI\Definition.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Views\AccountPage.xaml.cs">
|
||||
<DependentUpon>AccountPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Views\AddBillPage.xaml.cs">
|
||||
<DependentUpon>AddBillPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Views\BillPage.xaml.cs">
|
||||
<DependentUpon>BillPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Views\SettingPage.xaml.cs">
|
||||
<DependentUpon>SettingPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)MainShell.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)UI\BillingDate.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Views\AccountPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Views\AddBillPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Views\BillPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Views\SettingPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
13
Billing.Shared/Billing.Shared.shproj
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>6ac75d01-70d6-4a07-8685-bc52afd97a7a</ProjectGuid>
|
||||
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
|
||||
<PropertyGroup />
|
||||
<Import Project="Billing.Shared.projitems" Label="Shared" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
|
||||
</Project>
|
23
Billing.Shared/Helper.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Billing;
|
||||
|
||||
internal static class Helper
|
||||
{
|
||||
public static void Debug(string message)
|
||||
{
|
||||
var time = DateTime.Now.ToString("HH:mm:ss.fff");
|
||||
System.Diagnostics.Debug.WriteLine($"[{time}] - {message}");
|
||||
}
|
||||
|
||||
public static void Error(string category, Exception ex)
|
||||
{
|
||||
Error(category, ex?.Message ?? "unknown error");
|
||||
}
|
||||
|
||||
public static void Error(string category, string message)
|
||||
{
|
||||
var time = DateTime.Now.ToString("HH:mm:ss.fff");
|
||||
System.Diagnostics.Debug.Fail($"[{time}] - {category}", message);
|
||||
}
|
||||
}
|
61
Billing.Shared/Languages/PlatformCulture.cs
Normal file
@ -0,0 +1,61 @@
|
||||
namespace Billing.Languages
|
||||
{
|
||||
public partial class PlatformCulture
|
||||
{
|
||||
public string PlatformString { get; set; }
|
||||
public string LanguageCode { get; set; }
|
||||
public string LocaleCode { get; set; }
|
||||
|
||||
public string Language => string.IsNullOrEmpty(LocaleCode) ? LanguageCode : LanguageCode + "-" + LocaleCode;
|
||||
|
||||
public partial string GetNamespace();
|
||||
public partial void Init();
|
||||
|
||||
public PlatformCulture()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
private void Init(string cultureString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(cultureString))
|
||||
{
|
||||
cultureString = "zh-CN";
|
||||
}
|
||||
|
||||
PlatformString = cultureString.Replace('_', '-');
|
||||
if (PlatformString.Contains('-'))
|
||||
{
|
||||
var parts = PlatformString.Split('-');
|
||||
LanguageCode = parts[0];
|
||||
LocaleCode = parts[^1];
|
||||
}
|
||||
else
|
||||
{
|
||||
LanguageCode = PlatformString;
|
||||
LocaleCode = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private string ToDotnetFallbackLanguage()
|
||||
{
|
||||
string netLanguage = LanguageCode switch
|
||||
{
|
||||
// fallback to Portuguese (Portugal)
|
||||
"pt" => "pt-PT",
|
||||
// equivalent to German (Switzerland) for this app
|
||||
"gsw" => "de-CH",
|
||||
|
||||
// add more application-specific cases here (if required)
|
||||
// ONLY use cultures that have been tested and known to work
|
||||
|
||||
// use the first part of the identifier (two chars, usually);
|
||||
_ => LanguageCode,
|
||||
};
|
||||
Helper.Debug($".NET Fallback Language/Locale: {LanguageCode} to {netLanguage} (application-specific)");
|
||||
return netLanguage;
|
||||
}
|
||||
|
||||
public override string ToString() => PlatformString;
|
||||
}
|
||||
}
|
95
Billing.Shared/Languages/Resource.cs
Normal file
@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Billing.Languages
|
||||
{
|
||||
internal class Resource
|
||||
{
|
||||
public static string TitleDateFormat => Text(nameof(TitleDateFormat));
|
||||
|
||||
static readonly Dictionary<string, LanguageResource> dict = new();
|
||||
|
||||
public static string Text(string name, params object[] args)
|
||||
{
|
||||
string current = App.CurrentCulture.PlatformString;
|
||||
if (!dict.TryGetValue(current, out LanguageResource lang))
|
||||
{
|
||||
lang = new LanguageResource(App.CurrentCulture);
|
||||
dict.Add(current, 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?.TryGetValue(key, out string val) == true)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
public LanguageResource(PlatformCulture lang)
|
||||
{
|
||||
try
|
||||
{
|
||||
var ns = lang.GetNamespace();
|
||||
var langId = $"{ns}.Languages.{lang.Language}.xml";
|
||||
var langCodeId = $"{ns}.Languages.{lang.LanguageCode}.xml";
|
||||
var assembly = typeof(LanguageResource).Assembly;
|
||||
var name = assembly.GetManifestResourceNames().FirstOrDefault(n =>
|
||||
string.Equals(n, langId, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(n, langCodeId, StringComparison.OrdinalIgnoreCase));
|
||||
if (name == null)
|
||||
{
|
||||
name = $"{ns}.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)
|
||||
{
|
||||
Helper.Error("language.ctor", $"failed to load json resource: {lang}, {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ContentProperty(nameof(Text))]
|
||||
public class TextExtension : IMarkupExtension
|
||||
{
|
||||
public string Text { get; set; }
|
||||
|
||||
public object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
if (Text == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
return Resource.Text(Text);
|
||||
}
|
||||
}
|
||||
}
|
16
Billing.Shared/Languages/en.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<Accounts>Accounts</Accounts>
|
||||
<Bills>Bills</Bills>
|
||||
<Settings>Settings</Settings>
|
||||
<Sunday>Su</Sunday>
|
||||
<Monday>Mo</Monday>
|
||||
<Tuesday>Tu</Tuesday>
|
||||
<Wednesday>We</Wednesday>
|
||||
<Thursday>Th</Thursday>
|
||||
<Friday>Fr</Friday>
|
||||
<Saturday>Sa</Saturday>
|
||||
<NoRecords>Bills not yet generated</NoRecords>
|
||||
<Memo>Click here to record</Memo>
|
||||
<TitleDateFormat>MM/dd/yyyy</TitleDateFormat>
|
||||
</root>
|
16
Billing.Shared/Languages/zh-CN.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<Accounts>账户</Accounts>
|
||||
<Bills>账单</Bills>
|
||||
<Settings>设置</Settings>
|
||||
<Sunday>周日</Sunday>
|
||||
<Monday>周一</Monday>
|
||||
<Tuesday>周二</Tuesday>
|
||||
<Wednesday>周三</Wednesday>
|
||||
<Thursday>周四</Thursday>
|
||||
<Friday>周五</Friday>
|
||||
<Saturday>周六</Saturday>
|
||||
<NoRecords>还未产生账单</NoRecords>
|
||||
<Memo>点此记录</Memo>
|
||||
<TitleDateFormat>yyyy年MM月dd日</TitleDateFormat>
|
||||
</root>
|
18
Billing.Shared/MainShell.xaml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:v="clr-namespace:Billing.Views"
|
||||
xmlns:r="clr-namespace:Billing.Languages"
|
||||
x:Class="Billing.MainShell"
|
||||
BackgroundColor="{DynamicResource WindowBackgroundColor}"
|
||||
ForegroundColor="{DynamicResource PrimaryColor}"
|
||||
TitleColor="{DynamicResource PrimaryColor}"
|
||||
Shell.NavBarHasShadow="True">
|
||||
|
||||
<TabBar>
|
||||
<ShellContent ContentTemplate="{DataTemplate v:AccountPage}" Route="Accounts" Title="{r:Text Accounts}" Icon="wallet.png"/>
|
||||
<ShellContent ContentTemplate="{DataTemplate v:BillPage}" Route="Bills" Title="{r:Text Bills}" Icon="bill.png"/>
|
||||
<ShellContent ContentTemplate="{DataTemplate v:SettingPage}" Route="Settings" Title="{r:Text Settings}" Icon="settings.png"/>
|
||||
</TabBar>
|
||||
|
||||
</Shell>
|
11
Billing.Shared/MainShell.xaml.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Billing;
|
||||
|
||||
public partial class MainShell : Shell
|
||||
{
|
||||
public MainShell()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
65
Billing.Shared/Themes/BaseTheme.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using Billing.UI;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Billing.Themes;
|
||||
|
||||
public abstract class BaseTheme : ResourceDictionary
|
||||
{
|
||||
public const string CascadiaFontRegular = nameof(CascadiaFontRegular);
|
||||
public const string CascadiaFontBold = nameof(CascadiaFontBold);
|
||||
public const string RobotoCondensedFontRegular = nameof(RobotoCondensedFontRegular);
|
||||
public const string RobotoCondensedFontBold = nameof(RobotoCondensedFontBold);
|
||||
public const string WindowBackgroundColor = nameof(WindowBackgroundColor);
|
||||
public const string PromptBackgroundColor = nameof(PromptBackgroundColor);
|
||||
public const string PrimaryColor = nameof(PrimaryColor);
|
||||
public const string SecondaryColor = nameof(SecondaryColor);
|
||||
public const string TabBarBackgroundColor = nameof(TabBarBackgroundColor);
|
||||
public const string TabBarTitleColor = nameof(TabBarTitleColor);
|
||||
public const string TabBarUnselectedColor = nameof(TabBarUnselectedColor);
|
||||
public const string OutRangeDayColor = nameof(OutRangeDayColor);
|
||||
public const string TextColor = nameof(TextColor);
|
||||
public const string WeekendColor = nameof(WeekendColor);
|
||||
|
||||
protected abstract Color PrimaryMauiColor { get; }
|
||||
protected abstract Color SecondaryMauiColor { get; }
|
||||
|
||||
protected void InitResources()
|
||||
{
|
||||
var robotoRegularFontFamily = Definition.GetRobotoCondensedRegularFontFamily();
|
||||
Add(CascadiaFontRegular, Definition.GetCascadiaRegularFontFamily());
|
||||
Add(CascadiaFontBold, Definition.GetCascadiaBoldFontFamily());
|
||||
Add(RobotoCondensedFontRegular, Definition.GetRobotoCondensedRegularFontFamily());
|
||||
Add(RobotoCondensedFontBold, Definition.GetRobotoCondensedBoldFontFamily());
|
||||
|
||||
Add(PrimaryColor, PrimaryMauiColor);
|
||||
Add(SecondaryColor, SecondaryMauiColor);
|
||||
Add(TabBarTitleColor, PrimaryMauiColor);
|
||||
|
||||
Add(new Style(typeof(Label))
|
||||
{
|
||||
Setters =
|
||||
{
|
||||
new Setter { Property = Label.FontSizeProperty, Value = Device.GetNamedSize(NamedSize.Small, typeof(Label)) },
|
||||
new Setter { Property = Label.TextColorProperty, Value = PrimaryMauiColor },
|
||||
new Setter { Property = Label.FontFamilyProperty, Value = robotoRegularFontFamily }
|
||||
}
|
||||
});
|
||||
Add(new Style(typeof(Button))
|
||||
{
|
||||
Setters =
|
||||
{
|
||||
new Setter { Property = Button.TextColorProperty, Value = SecondaryMauiColor },
|
||||
new Setter { Property = Button.FontFamilyProperty, Value = robotoRegularFontFamily },
|
||||
new Setter { Property = VisualElement.BackgroundColorProperty, Value = PrimaryMauiColor },
|
||||
new Setter { Property = Button.PaddingProperty, Value = new Thickness(14, 10) }
|
||||
}
|
||||
});
|
||||
Add(new Style(typeof(TintImage))
|
||||
{
|
||||
Setters =
|
||||
{
|
||||
new Setter { Property = TintImage.PrimaryColorProperty, Value = PrimaryMauiColor }
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
40
Billing.Shared/Themes/Dark.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Billing.Themes;
|
||||
|
||||
public class Dark : BaseTheme
|
||||
{
|
||||
private static Dark _instance;
|
||||
|
||||
public static Dark Instance => _instance ??= new Dark();
|
||||
|
||||
protected override Color PrimaryMauiColor => Color.White;
|
||||
protected override Color SecondaryMauiColor => Color.LightGray;
|
||||
|
||||
public Dark()
|
||||
{
|
||||
InitColors();
|
||||
InitResources();
|
||||
}
|
||||
|
||||
private void InitColors()
|
||||
{
|
||||
Add(WindowBackgroundColor, Color.Black);
|
||||
Add(PromptBackgroundColor, Color.FromRgb(0x1f, 0x1f, 0x1f));
|
||||
Add(TabBarBackgroundColor, Color.Black);
|
||||
Add(TabBarUnselectedColor, Color.FromRgb(0x82, 0x82, 0x82));
|
||||
Add(OutRangeDayColor, Color.DarkGray);
|
||||
Add(TextColor, Color.FromRgb(0xcc, 0xcc, 0xcc));
|
||||
Add(WeekendColor, Color.FromRgb(211, 5, 5));
|
||||
|
||||
Add(new Style(typeof(TabBar))
|
||||
{
|
||||
Setters =
|
||||
{
|
||||
new Setter { Property = Shell.TabBarBackgroundColorProperty, Value = Color.Black },
|
||||
new Setter { Property = Shell.TabBarTitleColorProperty, Value = PrimaryMauiColor },
|
||||
new Setter { Property = Shell.TabBarUnselectedColorProperty, Value = Color.FromRgb(0x82, 0x82, 0x82) }
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
40
Billing.Shared/Themes/Light.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Billing.Themes;
|
||||
|
||||
public class Light : BaseTheme
|
||||
{
|
||||
private static Light _instance;
|
||||
|
||||
public static Light Instance => _instance ??= new Light();
|
||||
|
||||
protected override Color PrimaryMauiColor => Color.FromRgb(0x18, 0x31, 0x53);
|
||||
protected override Color SecondaryMauiColor => Color.White;
|
||||
|
||||
public Light()
|
||||
{
|
||||
InitColors();
|
||||
InitResources();
|
||||
}
|
||||
|
||||
private void InitColors()
|
||||
{
|
||||
Add(WindowBackgroundColor, Color.White);
|
||||
Add(PromptBackgroundColor, Color.FromRgb(0xe0, 0xe0, 0xe0));
|
||||
Add(TabBarBackgroundColor, Color.White);
|
||||
Add(TabBarUnselectedColor, Color.FromRgb(0x82, 0x82, 0x82));
|
||||
Add(OutRangeDayColor, Color.LightGray);
|
||||
Add(TextColor, Color.FromRgb(0x33, 0x33, 0x33));
|
||||
Add(WeekendColor, Color.FromRgb(211, 64, 85));
|
||||
|
||||
Add(new Style(typeof(TabBar))
|
||||
{
|
||||
Setters =
|
||||
{
|
||||
new Setter { Property = Shell.TabBarBackgroundColorProperty, Value = Color.White },
|
||||
new Setter { Property = Shell.TabBarTitleColorProperty, Value = PrimaryMauiColor },
|
||||
new Setter { Property = Shell.TabBarUnselectedColorProperty, Value = Color.FromRgb(0x82, 0x82, 0x82) }
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
76
Billing.Shared/UI/BillingDate.xaml
Normal file
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:r="clr-namespace:Billing.Languages"
|
||||
xmlns:ui="clr-namespace:Billing.UI"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Billing.UI.BillingDate"
|
||||
x:DataType="ui:BillingDate"
|
||||
x:Name="billingDate"
|
||||
BindingContext="{x:Reference billingDate}">
|
||||
<ContentView.Resources>
|
||||
<Style x:Key="centerLabel" TargetType="Label">
|
||||
<Setter Property="HorizontalOptions" Value="Center"/>
|
||||
<Setter Property="FontSize" Value="Small"/>
|
||||
<Setter Property="TextColor" Value="{DynamicResource TextColor}"/>
|
||||
</Style>
|
||||
<Style x:Key="dateLabel" TargetType="Label">
|
||||
<Setter Property="HorizontalOptions" Value="Center"/>
|
||||
</Style>
|
||||
<ControlTemplate x:Key="weekDay">
|
||||
<Grid Padding="0, 8, 0, 0" RowDefinitions="Auto, 3" RowSpacing="0">
|
||||
<Grid.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding OnDayTapped, Source={x:Reference billingDate}}" CommandParameter="{TemplateBinding BillingDay}"/>
|
||||
</Grid.GestureRecognizers>
|
||||
<Label Style="{StaticResource dateLabel}" Text="{TemplateBinding BillingDay.Text}"
|
||||
TextColor="{DynamicResource TextColor}"
|
||||
FontFamily="{TemplateBinding BillingDay.FontFamily}"
|
||||
Opacity="{TemplateBinding BillingDay.TextOpacity}"/>
|
||||
<StackLayout Grid.Row="1"
|
||||
IsVisible="{TemplateBinding BillingDay.IsSelected}"
|
||||
BackgroundColor="{DynamicResource PrimaryColor}"
|
||||
Opacity="{TemplateBinding BillingDay.Opacity}"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="weekEnd">
|
||||
<Grid Padding="0, 8, 0, 0" RowDefinitions="Auto, 3" RowSpacing="0">
|
||||
<Grid.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding OnDayTapped, Source={x:Reference billingDate}}" CommandParameter="{TemplateBinding BillingDay}"/>
|
||||
</Grid.GestureRecognizers>
|
||||
<Label Style="{StaticResource dateLabel}" Text="{TemplateBinding BillingDay.Text}"
|
||||
TextColor="{DynamicResource WeekendColor}"
|
||||
FontFamily="{TemplateBinding BillingDay.FontFamily}"
|
||||
Opacity="{TemplateBinding BillingDay.TextOpacity}"/>
|
||||
<StackLayout Grid.Row="1"
|
||||
IsVisible="{TemplateBinding BillingDay.IsSelected}"
|
||||
BackgroundColor="{DynamicResource PrimaryColor}"
|
||||
Opacity="{TemplateBinding BillingDay.Opacity}"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
<Style TargetType="ui:BillingDayView">
|
||||
<Setter Property="ControlTemplate" Value="{StaticResource weekDay}"/>
|
||||
</Style>
|
||||
</ContentView.Resources>
|
||||
<ContentView.Content>
|
||||
<Grid Padding="0, 8, 0, 4" ColumnDefinitions="*,*,*,*,*,*,*" RowDefinitions="Auto, Auto">
|
||||
<Grid.GestureRecognizers>
|
||||
<PanGestureRecognizer PanUpdated="OnPanUpdated"/>
|
||||
</Grid.GestureRecognizers>
|
||||
|
||||
<Label Grid.Column="0" Text="{r:Text Sunday}" Style="{StaticResource centerLabel}"/>
|
||||
<Label Grid.Column="1" Text="{r:Text Monday}" Style="{StaticResource centerLabel}"/>
|
||||
<Label Grid.Column="2" Text="{r:Text Tuesday}" Style="{StaticResource centerLabel}"/>
|
||||
<Label Grid.Column="3" Text="{r:Text Wednesday}" Style="{StaticResource centerLabel}"/>
|
||||
<Label Grid.Column="4" Text="{r:Text Thursday}" Style="{StaticResource centerLabel}"/>
|
||||
<Label Grid.Column="5" Text="{r:Text Friday}" Style="{StaticResource centerLabel}"/>
|
||||
<Label Grid.Column="6" Text="{r:Text Saturday}" Style="{StaticResource centerLabel}"/>
|
||||
|
||||
<ui:BillingDayView Grid.Row="1" Grid.Column="0" BillingDay="{Binding Sunday}" ControlTemplate="{StaticResource weekEnd}"/>
|
||||
<ui:BillingDayView Grid.Row="1" Grid.Column="1" BillingDay="{Binding Monday}"/>
|
||||
<ui:BillingDayView Grid.Row="1" Grid.Column="2" BillingDay="{Binding Tuesday}"/>
|
||||
<ui:BillingDayView Grid.Row="1" Grid.Column="3" BillingDay="{Binding Wednesday}"/>
|
||||
<ui:BillingDayView Grid.Row="1" Grid.Column="4" BillingDay="{Binding Thursday}"/>
|
||||
<ui:BillingDayView Grid.Row="1" Grid.Column="5" BillingDay="{Binding Friday}"/>
|
||||
<ui:BillingDayView Grid.Row="1" Grid.Column="6" BillingDay="{Binding Saturday}" ControlTemplate="{StaticResource weekEnd}"/>
|
||||
</Grid>
|
||||
</ContentView.Content>
|
||||
</ContentView>
|
290
Billing.Shared/UI/BillingDate.xaml.cs
Normal file
@ -0,0 +1,290 @@
|
||||
using Billing.Themes;
|
||||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Billing.UI;
|
||||
|
||||
public partial class BillingDate : ContentView
|
||||
{
|
||||
#region UI Properties
|
||||
|
||||
private static readonly BindableProperty SundayProperty = BindableProperty.Create(nameof(Sunday), typeof(BillingDay), typeof(BillingDate));
|
||||
private static readonly BindableProperty MondayProperty = BindableProperty.Create(nameof(Monday), typeof(BillingDay), typeof(BillingDate));
|
||||
private static readonly BindableProperty TuesdayProperty = BindableProperty.Create(nameof(Tuesday), typeof(BillingDay), typeof(BillingDate));
|
||||
private static readonly BindableProperty WednesdayProperty = BindableProperty.Create(nameof(Wednesday), typeof(BillingDay), typeof(BillingDate));
|
||||
private static readonly BindableProperty ThursdayProperty = BindableProperty.Create(nameof(Thursday), typeof(BillingDay), typeof(BillingDate));
|
||||
private static readonly BindableProperty FridayProperty = BindableProperty.Create(nameof(Friday), typeof(BillingDay), typeof(BillingDate));
|
||||
private static readonly BindableProperty SaturdayProperty = BindableProperty.Create(nameof(Saturday), typeof(BillingDay), typeof(BillingDate));
|
||||
|
||||
public BillingDay Sunday => (BillingDay)GetValue(SundayProperty);
|
||||
public BillingDay Monday => (BillingDay)GetValue(MondayProperty);
|
||||
public BillingDay Tuesday => (BillingDay)GetValue(TuesdayProperty);
|
||||
public BillingDay Wednesday => (BillingDay)GetValue(WednesdayProperty);
|
||||
public BillingDay Thursday => (BillingDay)GetValue(ThursdayProperty);
|
||||
public BillingDay Friday => (BillingDay)GetValue(FridayProperty);
|
||||
public BillingDay Saturday => (BillingDay)GetValue(SaturdayProperty);
|
||||
|
||||
#endregion
|
||||
|
||||
private static BindableProperty GetWeekProperty(int week)
|
||||
{
|
||||
return (DayOfWeek)week switch
|
||||
{
|
||||
DayOfWeek.Monday => MondayProperty,
|
||||
DayOfWeek.Tuesday => TuesdayProperty,
|
||||
DayOfWeek.Wednesday => WednesdayProperty,
|
||||
DayOfWeek.Thursday => ThursdayProperty,
|
||||
DayOfWeek.Friday => FridayProperty,
|
||||
DayOfWeek.Saturday => SaturdayProperty,
|
||||
_ => SundayProperty
|
||||
};
|
||||
}
|
||||
|
||||
public static readonly BindableProperty LocatedDateProperty = BindableProperty.Create(nameof(LocatedDate), typeof(DateTime), typeof(BillingDate), propertyChanged: OnLocatedDatePropertyChanged);
|
||||
public static readonly BindableProperty SelectedDateProperty = BindableProperty.Create(nameof(SelectedDate), typeof(DateTime), typeof(BillingDate), propertyChanged: OnSelectedDatePropertyChanged);
|
||||
|
||||
private static void OnLocatedDatePropertyChanged(BindableObject obj, object old, object @new)
|
||||
{
|
||||
if (obj is BillingDate billingDate && @new is DateTime date)
|
||||
{
|
||||
var week = (int)date.DayOfWeek;
|
||||
var tmpDate = date.AddDays(-week);
|
||||
for (var i = 0; i < 7; i++)
|
||||
{
|
||||
var prop = GetWeekProperty(i);
|
||||
var day = new BillingDay(tmpDate);
|
||||
billingDate.SetValue(prop, day);
|
||||
tmpDate = tmpDate.AddDays(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnSelectedDatePropertyChanged(BindableObject obj, object old, object @new)
|
||||
{
|
||||
if (obj is BillingDate billingDate && @new is DateTime selected)
|
||||
{
|
||||
for (var i = 0; i < 7; i++)
|
||||
{
|
||||
var prop = GetWeekProperty(i);
|
||||
var day = (BillingDay)billingDate.GetValue(prop);
|
||||
day.Refresh(selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime LocatedDate
|
||||
{
|
||||
get => (DateTime)GetValue(LocatedDateProperty);
|
||||
set => SetValue(LocatedDateProperty, value);
|
||||
}
|
||||
public DateTime SelectedDate
|
||||
{
|
||||
get => (DateTime)GetValue(SelectedDateProperty);
|
||||
set => SetValue(SelectedDateProperty, value);
|
||||
}
|
||||
|
||||
public Command OnDayTapped { get; }
|
||||
|
||||
public event EventHandler<DateEventArgs> DateSelected;
|
||||
|
||||
private DateTime lastDate;
|
||||
private double? x1;
|
||||
private double x2;
|
||||
|
||||
public BillingDate()
|
||||
{
|
||||
OnDayTapped = new Command(OnDayChanged);
|
||||
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void SetDateTime(DateTime selectedDate, DateTime? locatedDate = null)
|
||||
{
|
||||
if (locatedDate != null)
|
||||
{
|
||||
LocatedDate = locatedDate.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
LocatedDate = selectedDate;
|
||||
}
|
||||
SelectedDate = selectedDate;
|
||||
DateSelected?.Invoke(this, new DateEventArgs(selectedDate));
|
||||
}
|
||||
|
||||
private void OnDayChanged(object o)
|
||||
{
|
||||
var selected = SelectedDate;
|
||||
if (o is BillingDay day && (selected.Year != day.Date.Year || selected.DayOfYear != day.Date.DayOfYear))
|
||||
{
|
||||
for (var i = 0; i < 7; i++)
|
||||
{
|
||||
var d = (BillingDay)GetValue(GetWeekProperty(i));
|
||||
if (d.IsSelected)
|
||||
{
|
||||
this.AbortAnimation("unselected");
|
||||
this.Animate("unselected", v =>
|
||||
{
|
||||
d.Opacity = v;
|
||||
},
|
||||
start: 1, end: 0,
|
||||
easing: Easing.CubicOut,
|
||||
finished: (v, b) =>
|
||||
{
|
||||
d.Opacity = 0;
|
||||
d.IsSelected = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
SelectedDate = day.Date;
|
||||
this.AbortAnimation("selected");
|
||||
this.Animate("selected", v =>
|
||||
{
|
||||
day.Opacity = v;
|
||||
},
|
||||
start: 0, end: 1,
|
||||
easing: Easing.CubicOut,
|
||||
finished: (v, b) =>
|
||||
{
|
||||
day.Opacity = 1;
|
||||
});
|
||||
DateSelected?.Invoke(this, new DateEventArgs(day.Date));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
|
||||
{
|
||||
if (e.StatusType == GestureStatus.Started)
|
||||
{
|
||||
lastDate = DateTime.Now;
|
||||
x1 = null;
|
||||
}
|
||||
else if (e.StatusType == GestureStatus.Running)
|
||||
{
|
||||
if (x1 == null)
|
||||
{
|
||||
x1 = e.TotalX;
|
||||
}
|
||||
x2 = e.TotalX;
|
||||
}
|
||||
else if (e.StatusType == GestureStatus.Completed)
|
||||
{
|
||||
if (x1 == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var totalX = x2 - x1.Value;
|
||||
x1 = null;
|
||||
var ms = (DateTime.Now - lastDate).TotalMilliseconds;
|
||||
var speed = totalX / ms;
|
||||
Helper.Debug($"completed, speed: {speed}");
|
||||
if (speed < -0.7)
|
||||
{
|
||||
LocatedDate = LocatedDate.AddDays(7);
|
||||
}
|
||||
else if (speed > 0.7)
|
||||
{
|
||||
LocatedDate = LocatedDate.AddDays(-7);
|
||||
}
|
||||
OnSelectedDatePropertyChanged(this, null, SelectedDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DateEventArgs : EventArgs
|
||||
{
|
||||
public DateTime Date { get; }
|
||||
|
||||
public DateEventArgs(DateTime date)
|
||||
{
|
||||
Date = date;
|
||||
}
|
||||
}
|
||||
|
||||
public class BillingDayView : ContentView
|
||||
{
|
||||
public static readonly BindableProperty BillingDayProperty = BindableProperty.Create(nameof(BillingDay), typeof(BillingDay), typeof(BillingDayView));
|
||||
public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(Command), typeof(BillingDayView));
|
||||
|
||||
public BillingDay BillingDay
|
||||
{
|
||||
get => (BillingDay)GetValue(BillingDayProperty);
|
||||
set => SetValue(BillingDayProperty, value);
|
||||
}
|
||||
public Command Command
|
||||
{
|
||||
get => (Command)GetValue(CommandProperty);
|
||||
set => SetValue(CommandProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public class BillingDay : BindableObject
|
||||
{
|
||||
private static readonly BindableProperty DateProperty = BindableProperty.Create(nameof(Date), typeof(DateTime), typeof(BillingDay), propertyChanged: OnDatePropertyChanged);
|
||||
private static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(BillingDay));
|
||||
private static readonly BindableProperty FontFamilyProperty = BindableProperty.Create(nameof(FontFamily), typeof(string), typeof(BillingDay), defaultValue: Definition.GetCascadiaRegularFontFamily());
|
||||
private static readonly BindableProperty IsSelectedProperty = BindableProperty.Create(nameof(IsSelected), typeof(bool), typeof(BillingDay));
|
||||
private static readonly BindableProperty OpacityProperty = BindableProperty.Create(nameof(Opacity), typeof(double), typeof(BillingDay), defaultValue: 1.0);
|
||||
private static readonly BindableProperty TextOpacityProperty = BindableProperty.Create(nameof(TextOpacity), typeof(double), typeof(BillingDay), defaultValue: 1.0);
|
||||
|
||||
private static void OnDatePropertyChanged(BindableObject obj, object old, object @new)
|
||||
{
|
||||
if (obj is BillingDay day && @new is DateTime date)
|
||||
{
|
||||
if (date.Day == 1)
|
||||
{
|
||||
day.SetValue(TextProperty, date.ToString("MMM"));
|
||||
}
|
||||
else
|
||||
{
|
||||
day.SetValue(TextProperty, date.Day.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime Date
|
||||
{
|
||||
get => (DateTime)GetValue(DateProperty);
|
||||
set => SetValue(DateProperty, value);
|
||||
}
|
||||
public string Text => (string)GetValue(TextProperty);
|
||||
public string FontFamily => (string)GetValue(FontFamilyProperty);
|
||||
public bool IsSelected
|
||||
{
|
||||
get => (bool)GetValue(IsSelectedProperty);
|
||||
set => SetValue(IsSelectedProperty, value);
|
||||
}
|
||||
public double Opacity
|
||||
{
|
||||
get => (double)GetValue(OpacityProperty);
|
||||
set => SetValue(OpacityProperty, value);
|
||||
}
|
||||
public double TextOpacity => (double)GetValue(TextOpacityProperty);
|
||||
|
||||
public BillingDay(DateTime date)
|
||||
{
|
||||
Date = date;
|
||||
}
|
||||
|
||||
public void Refresh(DateTime selected)
|
||||
{
|
||||
var date = Date;
|
||||
if (date.Year == selected.Year && date.DayOfYear == selected.DayOfYear)
|
||||
{
|
||||
SetValue(IsSelectedProperty, true);
|
||||
SetValue(FontFamilyProperty, Definition.GetCascadiaBoldFontFamily());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetValue(FontFamilyProperty, Definition.GetCascadiaRegularFontFamily());
|
||||
}
|
||||
if (date.Year == selected.Year && date.Month == selected.Month)
|
||||
{
|
||||
SetValue(TextOpacityProperty, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetValue(TextOpacityProperty, .4);
|
||||
}
|
||||
}
|
||||
}
|
12
Billing.Shared/UI/BillingPage.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Billing.Themes;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Billing.UI;
|
||||
|
||||
public abstract class BillingPage : ContentPage
|
||||
{
|
||||
public BillingPage()
|
||||
{
|
||||
SetDynamicResource(BackgroundColorProperty, BaseTheme.WindowBackgroundColor);
|
||||
}
|
||||
}
|
23
Billing.Shared/UI/Converters.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using Billing.Languages;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Billing.UI;
|
||||
|
||||
public class TitleDateConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is DateTime date)
|
||||
{
|
||||
return date.ToString(Resource.TitleDateFormat);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
31
Billing.Shared/UI/CustomControl.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Billing.UI;
|
||||
|
||||
public class TintImage : Image
|
||||
{
|
||||
public static readonly BindableProperty PrimaryColorProperty = BindableProperty.Create(nameof(PrimaryColor), typeof(Color?), typeof(TintImage));
|
||||
|
||||
public Color? PrimaryColor
|
||||
{
|
||||
get => (Color?)GetValue(PrimaryColorProperty);
|
||||
set => SetValue(PrimaryColorProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public class LongPressButton : Button
|
||||
{
|
||||
public event EventHandler LongPressed;
|
||||
|
||||
public LongPressButton()
|
||||
{
|
||||
Padding = 0;
|
||||
BackgroundColor = Color.Transparent;
|
||||
}
|
||||
|
||||
public void TriggerLongPress()
|
||||
{
|
||||
LongPressed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
9
Billing.Shared/UI/Definition.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Billing.UI;
|
||||
|
||||
public static partial class Definition
|
||||
{
|
||||
public static partial string GetCascadiaRegularFontFamily();
|
||||
public static partial string GetCascadiaBoldFontFamily();
|
||||
public static partial string GetRobotoCondensedRegularFontFamily();
|
||||
public static partial string GetRobotoCondensedBoldFontFamily();
|
||||
}
|
13
Billing.Shared/Views/AccountPage.xaml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ui:BillingPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:r="clr-namespace:Billing.Languages"
|
||||
xmlns:ui="clr-namespace:Billing.UI"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Billing.Views.AccountPage"
|
||||
Title="{r:Text Accounts}">
|
||||
<StackLayout>
|
||||
<Label Text="Welcome to Account Page!"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand" />
|
||||
</StackLayout>
|
||||
</ui:BillingPage>
|
11
Billing.Shared/Views/AccountPage.xaml.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using Billing.UI;
|
||||
|
||||
namespace Billing.Views;
|
||||
|
||||
public partial class AccountPage : BillingPage
|
||||
{
|
||||
public AccountPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
14
Billing.Shared/Views/AddBillPage.xaml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ui:BillingPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:ui="clr-namespace:Billing.UI"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Billing.Views.AddBillPage"
|
||||
x:DataType="v:AddBillPage"
|
||||
Title="Add Billing">
|
||||
|
||||
<StackLayout>
|
||||
<Label Text="Add a billing here..."
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand" />
|
||||
</StackLayout>
|
||||
</ui:BillingPage>
|
11
Billing.Shared/Views/AddBillPage.xaml.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using Billing.UI;
|
||||
|
||||
namespace Billing.Views;
|
||||
|
||||
public partial class AddBillPage : BillingPage
|
||||
{
|
||||
public AddBillPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
56
Billing.Shared/Views/BillPage.xaml
Normal file
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ui:BillingPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:r="clr-namespace:Billing.Languages"
|
||||
xmlns:ui="clr-namespace:Billing.UI"
|
||||
xmlns:v="clr-namespace:Billing.Views"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Billing.Views.BillPage"
|
||||
x:DataType="v:BillPage"
|
||||
x:Name="billPage"
|
||||
BindingContext="{x:Reference billPage}"
|
||||
Title="{r:Text Bills}">
|
||||
|
||||
<ContentPage.Resources>
|
||||
<ui:TitleDateConverter x:Key="titleDateConverter"/>
|
||||
</ContentPage.Resources>
|
||||
|
||||
<Shell.TitleView>
|
||||
<Grid ColumnSpacing="16" ColumnDefinitions="20,*,20">
|
||||
<ui:TintImage Source="calendar.png" WidthRequest="20" HeightRequest="20" VerticalOptions="Center"/>
|
||||
<ui:LongPressButton Grid.Column="1" Text="{Binding SelectedDate, Converter={StaticResource titleDateConverter}}"
|
||||
TextColor="{DynamicResource PrimaryColor}"
|
||||
HorizontalOptions="{OnPlatform iOS=Center, Android=Start}"
|
||||
FontFamily="{DynamicResource RobotoCondensedFontBold}"
|
||||
FontAttributes="Bold" FontSize="20" VerticalOptions="Center"
|
||||
LongPressed="OnTitleDateLongPressed"/>
|
||||
</Grid>
|
||||
</Shell.TitleView>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<ui:BillingDate x:Name="billingDate" SelectedDate="{Binding SelectedDate}" DateSelected="OnDateSelected"/>
|
||||
<ScrollView Grid.Row="1">
|
||||
<Grid Padding="8" ColumnSpacing="8" ColumnDefinitions="Auto, *, Auto"
|
||||
BackgroundColor="{DynamicResource PromptBackgroundColor}"
|
||||
VerticalOptions="Start">
|
||||
<ui:TintImage Source="bars.png" WidthRequest="23" HeightRequest="23"/>
|
||||
<Label Grid.Column="1" Text="{r:Text NoRecords}" TextColor="{DynamicResource TextColor}"
|
||||
VerticalOptions="Center"/>
|
||||
<StackLayout Grid.Column="2" Orientation="Horizontal" Spacing="6">
|
||||
<StackLayout.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding AddBilling}"/>
|
||||
</StackLayout.GestureRecognizers>
|
||||
<Label Text="{r:Text Memo}" TextColor="{DynamicResource PrimaryColor}"
|
||||
VerticalOptions="Center"/>
|
||||
<!--<Label Style="{DynamicResource IconLightStyle}"
|
||||
Text="{x:Static local:Definition.IconRight}"
|
||||
TextColor="{DynamicResource TabBarUnselectedColor}"/>-->
|
||||
<ui:TintImage Source="right.png" WidthRequest="24" HeightRequest="24"/>
|
||||
</StackLayout>
|
||||
</Grid>
|
||||
</ScrollView>
|
||||
<!--<ui:CircleButton Grid.Row="1" VerticalOptions="End" HorizontalOptions="End"
|
||||
Margin="20" Padding="0"
|
||||
BackgroundColor="{DynamicResource PrimaryColor}"
|
||||
ImageSource="plus.png" HeightRequest="24" WidthRequest="24"/>-->
|
||||
</Grid>
|
||||
</ui:BillingPage>
|
44
Billing.Shared/Views/BillPage.xaml.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using Billing.UI;
|
||||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Billing.Views;
|
||||
|
||||
public partial class BillPage : BillingPage
|
||||
{
|
||||
private static readonly BindableProperty SelectedDateProperty = BindableProperty.Create(nameof(SelectedDate), typeof(DateTime), typeof(BillPage));
|
||||
|
||||
public DateTime SelectedDate
|
||||
{
|
||||
get => (DateTime)GetValue(SelectedDateProperty);
|
||||
set => SetValue(SelectedDateProperty, value);
|
||||
}
|
||||
|
||||
public Command AddBilling { get; }
|
||||
|
||||
public BillPage()
|
||||
{
|
||||
AddBilling = new Command(OnAddBilling);
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
billingDate.SetDateTime(DateTime.Now);
|
||||
}
|
||||
|
||||
private void OnDateSelected(object sender, DateEventArgs e)
|
||||
{
|
||||
SelectedDate = e.Date;
|
||||
|
||||
// TODO: while selecting date
|
||||
}
|
||||
|
||||
private void OnTitleDateLongPressed(object sender, EventArgs e)
|
||||
{
|
||||
billingDate.SetDateTime(DateTime.Now);
|
||||
}
|
||||
|
||||
private async void OnAddBilling()
|
||||
{
|
||||
await Navigation.PushAsync(new AddBillPage());
|
||||
}
|
||||
}
|
13
Billing.Shared/Views/SettingPage.xaml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ui:BillingPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:r="clr-namespace:Billing.Languages"
|
||||
xmlns:ui="clr-namespace:Billing.UI"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Billing.Views.SettingPage"
|
||||
Title="{r:Text Settings}">
|
||||
<StackLayout>
|
||||
<Label Text="Welcome to Settings Page!"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand" />
|
||||
</StackLayout>
|
||||
</ui:BillingPage>
|
11
Billing.Shared/Views/SettingPage.xaml.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using Billing.UI;
|
||||
|
||||
namespace Billing.Views;
|
||||
|
||||
public partial class SettingPage : BillingPage
|
||||
{
|
||||
public SettingPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
70
Billing.sln
Normal file
@ -0,0 +1,70 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32210.308
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Billing.Android", "Billing\Billing.Android\Billing.Android.csproj", "{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Billing.iOS", "Billing\Billing.iOS\Billing.iOS.csproj", "{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}"
|
||||
EndProject
|
||||
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Billing.Shared", "Billing.Shared\Billing.Shared.shproj", "{6AC75D01-70D6-4A07-8685-BC52AFD97A7A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||
Billing.Shared\Billing.Shared.projitems*{5c4f1c35-6f66-4063-9605-a9f37fcabba8}*SharedItemsImports = 4
|
||||
Billing.Shared\Billing.Shared.projitems*{6ac75d01-70d6-4a07-8685-bc52afd97a7a}*SharedItemsImports = 13
|
||||
Billing.Shared\Billing.Shared.projitems*{b4cd3b27-c58f-4b6b-b60e-35e515a73e5b}*SharedItemsImports = 4
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|iPhone = Debug|iPhone
|
||||
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|iPhone = Release|iPhone
|
||||
Release|iPhoneSimulator = Release|iPhoneSimulator
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Release|iPhone.Deploy.0 = Release|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Debug|Any CPU.Build.0 = Debug|iPhone
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Debug|Any CPU.Deploy.0 = Debug|iPhone
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Debug|iPhone.Build.0 = Debug|iPhone
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Debug|iPhoneSimulator.Deploy.0 = Debug|iPhoneSimulator
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Release|Any CPU.Build.0 = Release|iPhoneSimulator
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Release|Any CPU.Deploy.0 = Release|iPhoneSimulator
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Release|iPhone.ActiveCfg = Release|iPhone
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Release|iPhone.Deploy.0 = Release|iPhone
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{5C4F1C35-6F66-4063-9605-A9F37FCABBA8}.Release|iPhoneSimulator.Deploy.0 = Release|iPhoneSimulator
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6C946C90-CF6E-4464-920A-CD31FF045FC8}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
19
Billing/Billing.Android/Assets/AboutAssets.txt
Normal file
@ -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");
|
BIN
Billing/Billing.Android/Assets/CascadiaCode-Bold.ttf
Normal file
BIN
Billing/Billing.Android/Assets/CascadiaCode-Regular.ttf
Normal file
BIN
Billing/Billing.Android/Assets/RobotoCondensed-Bold.ttf
Normal file
BIN
Billing/Billing.Android/Assets/RobotoCondensed-Regular.ttf
Normal file
192
Billing/Billing.Android/Billing.Android.csproj
Normal file
@ -0,0 +1,192 @@
|
||||
<?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>{B4CD3B27-C58F-4B6B-B60E-35E515A73E5B}</ProjectGuid>
|
||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<TemplateGuid>{6968b3a4-1835-46a3-ac5c-1ae33b475983}</TemplateGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>Billing.Droid</RootNamespace>
|
||||
<AssemblyName>Billing.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>
|
||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
||||
<TargetFrameworkVersion>v12.0</TargetFrameworkVersion>
|
||||
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
|
||||
<AndroidUseAapt2>true</AndroidUseAapt2>
|
||||
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<LangVersion>10.0</LangVersion>
|
||||
</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>
|
||||
<AotAssemblies>false</AotAssemblies>
|
||||
<EnableLLVM>false</EnableLLVM>
|
||||
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
|
||||
<BundleAssemblies>false</BundleAssemblies>
|
||||
<AndroidSupportedAbis>x86_64</AndroidSupportedAbis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidManagedSymbols>true</AndroidManagedSymbols>
|
||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||
<AotAssemblies>false</AotAssemblies>
|
||||
<EnableLLVM>false</EnableLLVM>
|
||||
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
|
||||
<BundleAssemblies>false</BundleAssemblies>
|
||||
<AndroidSupportedAbis>arm64-v8a</AndroidSupportedAbis>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Mono.Android" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2196" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.7.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Definition.cs" />
|
||||
<Compile Include="MainActivity.cs" />
|
||||
<Compile Include="PlatformCulture.cs" />
|
||||
<Compile Include="Renderers\LongPressButtonRenderer.cs" />
|
||||
<Compile Include="Renderers\TintImageRenderer.cs" />
|
||||
<Compile Include="Resources\Resource.designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidAsset Include="Assets\CascadiaCode-Bold.ttf" />
|
||||
<AndroidAsset Include="Assets\CascadiaCode-Regular.ttf" />
|
||||
<AndroidAsset Include="Assets\RobotoCondensed-Regular.ttf" />
|
||||
<AndroidAsset Include="Assets\RobotoCondensed-Bold.ttf" />
|
||||
<None Include="Resources\AboutResources.txt" />
|
||||
<None Include="Assets\AboutAssets.txt" />
|
||||
<None Include="Properties\AndroidManifest.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\values\styles.xml" />
|
||||
<AndroidResource Include="Resources\values\colors.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon_round.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\drawable\xamarin_logo.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\wallet.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\calendar.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\bars.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\bill.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\plus.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\right.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\settings.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\wallet.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-mdpi\bars.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-mdpi\bill.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-mdpi\plus.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-mdpi\right.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-mdpi\settings.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-mdpi\wallet.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\bars.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\bill.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\plus.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\right.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\settings.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\bars.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\bill.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\plus.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\right.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\settings.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\wallet.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-mdpi\calendar.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xhdpi\calendar.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable-xxhdpi\calendar.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\..\Billing.Shared\Billing.Shared.projitems" Label="Shared" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
</Project>
|
9
Billing/Billing.Android/Definition.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Billing.UI;
|
||||
|
||||
public static partial class Definition
|
||||
{
|
||||
public static partial string GetCascadiaRegularFontFamily() => "CascadiaCode-Regular.ttf#CascadiaCode-Regular";
|
||||
public static partial string GetCascadiaBoldFontFamily() => "CascadiaCode-Bold.ttf#CascadiaCode-Bold";
|
||||
public static partial string GetRobotoCondensedRegularFontFamily() => "RobotoCondensed-Regular.ttf#RobotoCondensed-Regular";
|
||||
public static partial string GetRobotoCondensedBoldFontFamily() => "RobotoCondensed-Bold.ttf#RobotoCondensed-Bold";
|
||||
}
|
31
Billing/Billing.Android/MainActivity.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using Android.App;
|
||||
using Android.Content.PM;
|
||||
using Android.Runtime;
|
||||
using Android.OS;
|
||||
|
||||
namespace Billing.Droid;
|
||||
|
||||
[Activity(
|
||||
Label = "Billing",
|
||||
Icon = "@mipmap/icon",
|
||||
RoundIcon = "@mipmap/icon_round",
|
||||
Theme = "@style/MainTheme",
|
||||
MainLauncher = true,
|
||||
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
|
||||
public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
|
||||
{
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
|
||||
Xamarin.Forms.Forms.Init(this, savedInstanceState);
|
||||
LoadApplication(new App());
|
||||
}
|
||||
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
|
||||
{
|
||||
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
}
|
66
Billing/Billing.Android/PlatformCulture.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using Billing.Droid;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
|
||||
namespace Billing.Languages;
|
||||
|
||||
public partial class PlatformCulture
|
||||
{
|
||||
public partial string GetNamespace()
|
||||
{
|
||||
return typeof(MainActivity).Namespace;
|
||||
}
|
||||
|
||||
public partial void Init()
|
||||
{
|
||||
var locale = Java.Util.Locale.Default;
|
||||
string lang = AndroidToDotnetLanguage($"{locale.Language}-{locale.Country}");
|
||||
|
||||
CultureInfo ci;
|
||||
Init(lang);
|
||||
try
|
||||
{
|
||||
ci = new CultureInfo(Language);
|
||||
}
|
||||
catch (CultureNotFoundException e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fallback = ToDotnetFallbackLanguage();
|
||||
Helper.Debug($"{lang} failed, trying {fallback} ({e.Message})");
|
||||
ci = new CultureInfo(fallback);
|
||||
}
|
||||
catch (CultureNotFoundException e1)
|
||||
{
|
||||
Helper.Error("culture.get", $"{lang} couldn't be set, using 'zh-CN' ({e1.Message})");
|
||||
ci = new CultureInfo("zh-CN");
|
||||
}
|
||||
}
|
||||
|
||||
Thread.CurrentThread.CurrentCulture = ci;
|
||||
Thread.CurrentThread.CurrentUICulture = ci;
|
||||
|
||||
Helper.Debug($"CurrentCulture set: {ci.Name}");
|
||||
}
|
||||
|
||||
private static string AndroidToDotnetLanguage(string androidLanguage)
|
||||
{
|
||||
//certain languages need to be converted to CultureInfo equivalent
|
||||
string netLanguage = androidLanguage switch
|
||||
{
|
||||
// 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,
|
||||
};
|
||||
Helper.Debug($"Android Language: {androidLanguage}, .NET Language/Locale: {netLanguage}");
|
||||
return netLanguage;
|
||||
}
|
||||
}
|
6
Billing/Billing.Android/Properties/AndroidManifest.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="org.tsanie.billing" android:installLocation="auto">
|
||||
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="31" />
|
||||
<application android:label="Billing" android:theme="@style/MainTheme"></application>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
</manifest>
|
29
Billing/Billing.Android/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.Reflection;
|
||||
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("Billing.Android")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Billing.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)]
|
33
Billing/Billing.Android/Renderers/LongPressButtonRenderer.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using Android.Content;
|
||||
using Billing.Droid.Renderers;
|
||||
using Billing.UI;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(LongPressButton), typeof(LongPressButtonRenderer))]
|
||||
namespace Billing.Droid.Renderers;
|
||||
|
||||
public class LongPressButtonRenderer : ButtonRenderer
|
||||
{
|
||||
public LongPressButtonRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (Element is LongPressButton && Control != null)
|
||||
{
|
||||
Control.LongClick += Control_LongClick;
|
||||
}
|
||||
}
|
||||
|
||||
private void Control_LongClick(object sender, LongClickEventArgs e)
|
||||
{
|
||||
if (Element is LongPressButton button)
|
||||
{
|
||||
button.TriggerLongPress();
|
||||
}
|
||||
}
|
||||
}
|
36
Billing/Billing.Android/Renderers/TintImageRenderer.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using Android.Content;
|
||||
using Billing.Droid.Renderers;
|
||||
using Billing.UI;
|
||||
using System.ComponentModel;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
|
||||
[assembly: ExportRenderer(typeof(TintImage), typeof(TintImageRenderer))]
|
||||
namespace Billing.Droid.Renderers;
|
||||
|
||||
public class TintImageRenderer : ImageRenderer
|
||||
{
|
||||
public TintImageRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
|
||||
if (e.PropertyName == nameof(TintImage.PrimaryColor) && Control?.Drawable != null && Element is TintImage image)
|
||||
{
|
||||
Control.Drawable.SetTint(image.PrimaryColor?.ToAndroid() ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (Control?.Drawable != null && Element is TintImage image)
|
||||
{
|
||||
Control.Drawable.SetTint(image.PrimaryColor?.ToAndroid() ?? 0);
|
||||
}
|
||||
}
|
||||
}
|
50
Billing/Billing.Android/Resources/AboutResources.txt
Normal file
@ -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.
|
29680
Billing/Billing.Android/Resources/Resource.designer.cs
generated
Normal file
BIN
Billing/Billing.Android/Resources/drawable-mdpi/bars.png
Normal file
After Width: | Height: | Size: 278 B |
BIN
Billing/Billing.Android/Resources/drawable-mdpi/bill.png
Normal file
After Width: | Height: | Size: 895 B |
BIN
Billing/Billing.Android/Resources/drawable-mdpi/calendar.png
Normal file
After Width: | Height: | Size: 536 B |
BIN
Billing/Billing.Android/Resources/drawable-mdpi/plus.png
Normal file
After Width: | Height: | Size: 588 B |
BIN
Billing/Billing.Android/Resources/drawable-mdpi/right.png
Normal file
After Width: | Height: | Size: 926 B |
BIN
Billing/Billing.Android/Resources/drawable-mdpi/settings.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
Billing/Billing.Android/Resources/drawable-mdpi/wallet.png
Normal file
After Width: | Height: | Size: 688 B |
BIN
Billing/Billing.Android/Resources/drawable-xhdpi/bars.png
Normal file
After Width: | Height: | Size: 509 B |
BIN
Billing/Billing.Android/Resources/drawable-xhdpi/bill.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
Billing/Billing.Android/Resources/drawable-xhdpi/calendar.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Billing/Billing.Android/Resources/drawable-xhdpi/plus.png
Normal file
After Width: | Height: | Size: 893 B |
BIN
Billing/Billing.Android/Resources/drawable-xhdpi/right.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
Billing/Billing.Android/Resources/drawable-xhdpi/settings.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
Billing/Billing.Android/Resources/drawable-xhdpi/wallet.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
Billing/Billing.Android/Resources/drawable-xxhdpi/bars.png
Normal file
After Width: | Height: | Size: 863 B |
BIN
Billing/Billing.Android/Resources/drawable-xxhdpi/bill.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
Billing/Billing.Android/Resources/drawable-xxhdpi/calendar.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
Billing/Billing.Android/Resources/drawable-xxhdpi/plus.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Billing/Billing.Android/Resources/drawable-xxhdpi/right.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
Billing/Billing.Android/Resources/drawable-xxhdpi/settings.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
Billing/Billing.Android/Resources/drawable-xxhdpi/wallet.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
Billing/Billing.Android/Resources/drawable/bars.png
Normal file
After Width: | Height: | Size: 420 B |
BIN
Billing/Billing.Android/Resources/drawable/bill.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Billing/Billing.Android/Resources/drawable/calendar.png
Normal file
After Width: | Height: | Size: 792 B |
BIN
Billing/Billing.Android/Resources/drawable/plus.png
Normal file
After Width: | Height: | Size: 734 B |
BIN
Billing/Billing.Android/Resources/drawable/right.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Billing/Billing.Android/Resources/drawable/settings.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Billing/Billing.Android/Resources/drawable/wallet.png
Normal file
After Width: | Height: | Size: 1002 B |
BIN
Billing/Billing.Android/Resources/drawable/xamarin_logo.png
Normal file
After Width: | Height: | Size: 21 KiB |
@ -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/launcher_background" />
|
||||
<foreground android:drawable="@mipmap/launcher_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/launcher_background" />
|
||||
<foreground android:drawable="@mipmap/launcher_foreground" />
|
||||
</adaptive-icon>
|
BIN
Billing/Billing.Android/Resources/mipmap-hdpi/icon.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 11 KiB |
BIN
Billing/Billing.Android/Resources/mipmap-mdpi/icon.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 6.3 KiB |
BIN
Billing/Billing.Android/Resources/mipmap-xhdpi/icon.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 18 KiB |
BIN
Billing/Billing.Android/Resources/mipmap-xxhdpi/icon.png
Normal file
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 33 KiB |
BIN
Billing/Billing.Android/Resources/mipmap-xxxhdpi/icon.png
Normal file
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 51 KiB |
7
Billing/Billing.Android/Resources/values/colors.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="launcher_background">#FFFFFF</color>
|
||||
<color name="colorPrimary">#183153</color>
|
||||
<color name="colorPrimaryDark">#2B0B98</color>
|
||||
<color name="colorAccent">#2B0B98</color>
|
||||
</resources>
|
18
Billing/Billing.Android/Resources/values/styles.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<resources>
|
||||
|
||||
<style name="MainTheme" parent="MainTheme.Base">
|
||||
<!-- As of Xamarin.Forms 4.6 the theme has moved into the Forms binary -->
|
||||
<!-- If you want to override anything you can do that here. -->
|
||||
<!-- Underneath are a couple of entries to get you started. -->
|
||||
|
||||
<!-- 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>-->
|
||||
</style>
|
||||
</resources>
|
26
Billing/Billing.iOS/AppDelegate.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
|
||||
namespace Billing.iOS;
|
||||
|
||||
// The UIApplicationDelegate for the application. This class is responsible for launching the
|
||||
// User Interface of the application, as well as listening (and optionally responding) to
|
||||
// application events from iOS.
|
||||
[Register(nameof(AppDelegate))]
|
||||
public partial class AppDelegate : Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
|
||||
{
|
||||
//
|
||||
// This method is invoked when the application has loaded and is ready to run. In this
|
||||
// method you should instantiate the window, load the UI into it and then make the window
|
||||
// visible.
|
||||
//
|
||||
// You have 17 seconds to return from this method, or iOS will terminate your application.
|
||||
//
|
||||
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
|
||||
{
|
||||
Xamarin.Forms.Forms.Init();
|
||||
LoadApplication(new App());
|
||||
|
||||
return base.FinishedLaunching(app, options);
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
{
|
||||
"images": [
|
||||
{
|
||||
"scale": "2x",
|
||||
"size": "20x20",
|
||||
"idiom": "iphone",
|
||||
"filename": "Icon40.png"
|
||||
},
|
||||
{
|
||||
"scale": "3x",
|
||||
"size": "20x20",
|
||||
"idiom": "iphone",
|
||||
"filename": "Icon60.png"
|
||||
},
|
||||
{
|
||||
"scale": "2x",
|
||||
"size": "29x29",
|
||||
"idiom": "iphone",
|
||||
"filename": "Icon58.png"
|
||||
},
|
||||
{
|
||||
"scale": "3x",
|
||||
"size": "29x29",
|
||||
"idiom": "iphone",
|
||||
"filename": "Icon87.png"
|
||||
},
|
||||
{
|
||||
"scale": "2x",
|
||||
"size": "40x40",
|
||||
"idiom": "iphone",
|
||||
"filename": "Icon80.png"
|
||||
},
|
||||
{
|
||||
"scale": "3x",
|
||||
"size": "40x40",
|
||||
"idiom": "iphone",
|
||||
"filename": "Icon120.png"
|
||||
},
|
||||
{
|
||||
"scale": "2x",
|
||||
"size": "60x60",
|
||||
"idiom": "iphone",
|
||||
"filename": "Icon120.png"
|
||||
},
|
||||
{
|
||||
"scale": "3x",
|
||||
"size": "60x60",
|
||||
"idiom": "iphone",
|
||||
"filename": "Icon180.png"
|
||||
},
|
||||
{
|
||||
"scale": "1x",
|
||||
"size": "20x20",
|
||||
"idiom": "ipad",
|
||||
"filename": "Icon20.png"
|
||||
},
|
||||
{
|
||||
"scale": "2x",
|
||||
"size": "20x20",
|
||||
"idiom": "ipad",
|
||||
"filename": "Icon40.png"
|
||||
},
|
||||
{
|
||||
"scale": "1x",
|
||||
"size": "29x29",
|
||||
"idiom": "ipad",
|
||||
"filename": "Icon29.png"
|
||||
},
|
||||
{
|
||||
"scale": "2x",
|
||||
"size": "29x29",
|
||||
"idiom": "ipad",
|
||||
"filename": "Icon58.png"
|
||||
},
|
||||
{
|
||||
"scale": "1x",
|
||||
"size": "40x40",
|
||||
"idiom": "ipad",
|
||||
"filename": "Icon40.png"
|
||||
},
|
||||
{
|
||||
"scale": "2x",
|
||||
"size": "40x40",
|
||||
"idiom": "ipad",
|
||||
"filename": "Icon80.png"
|
||||
},
|
||||
{
|
||||
"scale": "1x",
|
||||
"size": "76x76",
|
||||
"idiom": "ipad",
|
||||
"filename": "Icon76.png"
|
||||
},
|
||||
{
|
||||
"scale": "2x",
|
||||
"size": "76x76",
|
||||
"idiom": "ipad",
|
||||
"filename": "Icon152.png"
|
||||
},
|
||||
{
|
||||
"scale": "2x",
|
||||
"size": "83.5x83.5",
|
||||
"idiom": "ipad",
|
||||
"filename": "Icon167.png"
|
||||
},
|
||||
{
|
||||
"scale": "1x",
|
||||
"size": "1024x1024",
|
||||
"idiom": "ios-marketing",
|
||||
"filename": "Icon1024.png"
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 845 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.5 KiB |