Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cc6c37d70f | |||
| 0a57408cc5 | |||
| de40b0112a | |||
| 558f6ea8d3 | |||
| 8af38a7f24 | |||
| b497fcf8c6 | |||
| 180d2f0fff | |||
| 5b94f48522 | |||
| 29fb04e783 | |||
|
|
e0333e8279 | ||
|
|
209ff9626f | ||
| acfdf89ade | |||
| 56d8653a02 | |||
| a563554597 | |||
| 81fc3c9c34 | |||
| e5c15e9b83 | |||
| 76979b2cb0 | |||
| a6c8f3b3ed | |||
|
|
1548339205 |
41
.gitea/workflows/build-linux.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Build Linux
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
dotnet publish Clario.Desktop/Clario.Desktop.csproj \
|
||||
-r linux-x64 \
|
||||
-c Release \
|
||||
--self-contained true \
|
||||
-p:PublishSingleFile=true \
|
||||
-o ./publish/linux-x64
|
||||
|
||||
|
||||
- name: Package as tar.gz
|
||||
run: tar -czf Clario-linux-x64.tar.gz -C ./publish/linux-x64 .
|
||||
|
||||
- name: Upload artifact
|
||||
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
|
||||
with:
|
||||
name: Clario-linux-x64
|
||||
path: ./Clario-linux-x64.tar.gz
|
||||
|
||||
retention-days: 7
|
||||
40
.github/workflows/build-linux.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Build Linux
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
dotnet publish Clario.Desktop/Clario.Desktop.csproj \
|
||||
-r linux-x64 \
|
||||
-c Release \
|
||||
--self-contained true \
|
||||
-p:PublishSingleFile=true \
|
||||
-o ./publish/linux-x64
|
||||
|
||||
|
||||
- name: Package as tar.gz
|
||||
run: tar -czf Clario-linux-x64.tar.gz -C ./publish/linux-x64 .
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Clario-linux-x64
|
||||
path: ./publish/linux
|
||||
retention-days: 7
|
||||
456
.gitignore
vendored
@@ -1,454 +1,6 @@
|
||||
## 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
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
bin/
|
||||
obj/
|
||||
.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
|
||||
nunit-*.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/
|
||||
|
||||
# Tye
|
||||
.tye/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# 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
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# 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
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# 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
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# 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
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# 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/
|
||||
|
||||
# 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/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
##
|
||||
## Visual studio for Mac
|
||||
##
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
##
|
||||
## Visual Studio Code
|
||||
##
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.user
|
||||
*.suo
|
||||
@@ -13,16 +13,13 @@
|
||||
<RootNamespace>Clario.Android</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Icon.png">
|
||||
<Link>Resources\drawable\Icon.png</Link>
|
||||
</AndroidResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia.Android"/>
|
||||
<PackageReference Include="Avalonia.Svg.Skia" />
|
||||
<PackageReference Include="Deadpikle.AvaloniaProgressRing" />
|
||||
<PackageReference Include="FluentAvalonia.ProgressRing" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.WebAssembly" />
|
||||
<PackageReference Include="Supabase" />
|
||||
<PackageReference Include="Xamarin.AndroidX.Core.SplashScreen"/>
|
||||
</ItemGroup>
|
||||
@@ -30,4 +27,9 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Clario\Clario.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\drawable-night-v31\" />
|
||||
<Folder Include="Resources\drawable-v31\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
<animated-vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:name="vector"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<group
|
||||
android:name="wrapper"
|
||||
android:translateX="21"
|
||||
android:translateY="21">
|
||||
<group android:name="group">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 74.853 85.823 L 75.368 85.823 C 80.735 85.823 85.144 81.803 85.761 76.602 L 85.836 41.76 C 85.225 18.593 66.254 0 42.939 0 C 19.24 0 0.028 19.212 0.028 42.912 C 0.028 66.357 18.831 85.418 42.18 85.823 L 74.853 85.823 Z"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 43.059 14.614 C 29.551 14.614 18.256 24.082 15.445 36.743 C 18.136 37.498 20.109 39.968 20.109 42.899 C 20.109 45.831 18.136 48.301 15.445 49.055 C 18.256 61.716 29.551 71.184 43.059 71.184 C 47.975 71.184 52.599 69.93 56.628 67.723 L 56.628 70.993 L 71.344 70.993 L 71.344 44.072 C 71.357 43.714 71.344 43.26 71.344 42.899 C 71.344 27.278 58.68 14.614 43.059 14.614 Z M 29.51 42.899 C 29.51 35.416 35.576 29.35 43.059 29.35 C 50.541 29.35 56.607 35.416 56.607 42.899 C 56.607 50.382 50.541 56.448 43.059 56.448 C 35.576 56.448 29.51 50.382 29.51 42.899 Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 18.105 42.88 C 18.105 45.38 16.078 47.407 13.579 47.407 C 11.079 47.407 9.052 45.38 9.052 42.88 C 9.052 40.381 11.079 38.354 13.579 38.354 C 16.078 38.354 18.105 40.381 18.105 42.88 Z"
|
||||
android:strokeWidth="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="path">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="fillColor"
|
||||
android:duration="1000"
|
||||
android:valueFrom="#00ffffff"
|
||||
android:valueTo="#161c2d"
|
||||
android:valueType="colorType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="path_1">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="fillColor"
|
||||
android:duration="1000"
|
||||
android:valueFrom="#00ffffff"
|
||||
android:valueTo="#f9f9fb"
|
||||
android:valueType="colorType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="path_2">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="fillColor"
|
||||
android:duration="1000"
|
||||
android:valueFrom="#00ffffff"
|
||||
android:valueTo="#f9f9fb"
|
||||
android:valueType="colorType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
||||
@@ -1,71 +0,0 @@
|
||||
<animated-vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:name="vector"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<group
|
||||
android:name="wrapper"
|
||||
android:translateX="21"
|
||||
android:translateY="21">
|
||||
<group android:name="group">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 74.853 85.823 L 75.368 85.823 C 80.735 85.823 85.144 81.803 85.761 76.602 L 85.836 41.76 C 85.225 18.593 66.254 0 42.939 0 C 19.24 0 0.028 19.212 0.028 42.912 C 0.028 66.357 18.831 85.418 42.18 85.823 L 74.853 85.823 Z"
|
||||
android:fillColor="#00ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 43.059 14.614 C 29.551 14.614 18.256 24.082 15.445 36.743 C 18.136 37.498 20.109 39.968 20.109 42.899 C 20.109 45.831 18.136 48.301 15.445 49.055 C 18.256 61.716 29.551 71.184 43.059 71.184 C 47.975 71.184 52.599 69.93 56.628 67.723 L 56.628 70.993 L 71.344 70.993 L 71.344 44.072 C 71.357 43.714 71.344 43.26 71.344 42.899 C 71.344 27.278 58.68 14.614 43.059 14.614 Z M 29.51 42.899 C 29.51 35.416 35.576 29.35 43.059 29.35 C 50.541 29.35 56.607 35.416 56.607 42.899 C 56.607 50.382 50.541 56.448 43.059 56.448 C 35.576 56.448 29.51 50.382 29.51 42.899 Z"
|
||||
android:fillColor="#00ffffff"
|
||||
android:strokeWidth="1"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 18.105 42.88 C 18.105 45.38 16.078 47.407 13.579 47.407 C 11.079 47.407 9.052 45.38 9.052 42.88 C 9.052 40.381 11.079 38.354 13.579 38.354 C 16.078 38.354 18.105 40.381 18.105 42.88 Z"
|
||||
android:fillColor="#00ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="path_2">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="fillColor"
|
||||
android:startOffset="100"
|
||||
android:duration="900"
|
||||
android:valueFrom="#00ffffff"
|
||||
android:valueTo="#161c2d"
|
||||
android:valueType="colorType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="path">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="fillColor"
|
||||
android:duration="500"
|
||||
android:valueFrom="#00ffffff"
|
||||
android:valueTo="#f9f9fb"
|
||||
android:valueType="colorType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="path_1">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="fillColor"
|
||||
android:startOffset="100"
|
||||
android:duration="900"
|
||||
android:valueFrom="#00ffffff"
|
||||
android:valueTo="#161c2d"
|
||||
android:valueType="colorType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
||||
BIN
Clario.Android/Resources/drawable/Icon.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
@@ -5,7 +5,7 @@
|
||||
<color android:color="@color/splash_background"/>
|
||||
</item>
|
||||
|
||||
<item android:drawable="@drawable/icon"
|
||||
<item android:drawable="@drawable/Icon"
|
||||
android:width="120dp"
|
||||
android:height="120dp"
|
||||
android:gravity="center" />
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
|
||||
</adaptive-icon>
|
||||
BIN
Clario.Android/Resources/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
Clario.Android/Resources/mipmap-hdpi/ic_launcher_background.png
Normal file
|
After Width: | Height: | Size: 844 B |
BIN
Clario.Android/Resources/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
Clario.Android/Resources/mipmap-hdpi/ic_launcher_monochrome.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
Clario.Android/Resources/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
Clario.Android/Resources/mipmap-mdpi/ic_launcher_background.png
Normal file
|
After Width: | Height: | Size: 450 B |
BIN
Clario.Android/Resources/mipmap-mdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
Clario.Android/Resources/mipmap-mdpi/ic_launcher_monochrome.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
Clario.Android/Resources/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
Clario.Android/Resources/mipmap-xhdpi/ic_launcher_background.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Clario.Android/Resources/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
Clario.Android/Resources/mipmap-xhdpi/ic_launcher_monochrome.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
Clario.Android/Resources/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
BIN
Clario.Android/Resources/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
@@ -9,7 +9,6 @@
|
||||
<item name="android:windowBackground">@null</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowSplashScreenBackground">@color/splash_background</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/avalonia_anim</item>
|
||||
<item name="android:windowSplashScreenAnimationDuration">1000</item>
|
||||
<item name="postSplashScreenTheme">@style/MyTheme.Main</item>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="splash_background">#FFFFFF</color>
|
||||
<color name="splash_background">#0B0D12</color>
|
||||
</resources>
|
||||
|
||||
BIN
Clario.Android/play_store_512.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
@@ -9,7 +9,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia.Browser"/>
|
||||
<PackageReference Include="Avalonia.Svg.Skia" />
|
||||
<PackageReference Include="Deadpikle.AvaloniaProgressRing" />
|
||||
<PackageReference Include="FluentAvalonia.ProgressRing" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.WebAssembly" />
|
||||
<PackageReference Include="Supabase" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<!--If you are willing to use platform-specific APIs, use conditional compilation.
|
||||
See https://docs.avaloniaui.net/docs/guides/platforms/platform-specific-code/dotnet for more details.-->
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
@@ -19,7 +17,10 @@
|
||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Avalonia.Svg.Skia" />
|
||||
<PackageReference Include="Deadpikle.AvaloniaProgressRing" />
|
||||
<PackageReference Include="FluentAvalonia.ProgressRing" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.WebAssembly" />
|
||||
<PackageReference Include="Supabase" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Clario.Services;
|
||||
|
||||
namespace Clario.Desktop;
|
||||
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia.iOS"/>
|
||||
<PackageReference Include="Avalonia.Svg.Skia" />
|
||||
<PackageReference Include="Deadpikle.AvaloniaProgressRing" />
|
||||
<PackageReference Include="FluentAvalonia.ProgressRing" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.WebAssembly" />
|
||||
<PackageReference Include="Supabase" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Clario"
|
||||
xmlns:converters="clr-namespace:Clario.Converters"
|
||||
xmlns:views="clr-namespace:Clario.Views"
|
||||
xmlns:vm="clr-namespace:Clario.ViewModels"
|
||||
xmlns:styling="clr-namespace:FluentAvalonia.Styling;assembly=FluentAvalonia"
|
||||
x:Class="Clario.App"
|
||||
RequestedThemeVariant="Dark">
|
||||
RequestedThemeVariant="Default">
|
||||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
|
||||
|
||||
<Application.DataTemplates>
|
||||
<local:ViewLocator />
|
||||
</Application.DataTemplates>
|
||||
@@ -24,9 +26,12 @@
|
||||
<converters:DecimalSignConverter x:Key="DecimalSignConverter" />
|
||||
<converters:PercentageConverter x:Key="PercentageConverter" />
|
||||
<converters:DecimalColorConverter x:Key="DecimalColorConverter" />
|
||||
<converters:BoolToColorConverter x:Key="BoolToColorConverter" />
|
||||
<converters:BoolToCssConverter x:Key="BoolToCssConverter" />
|
||||
</Application.Resources>
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
<StyleInclude Source="../Theme/AppTheme.axaml" />
|
||||
<StyleInclude Source="avares://AvaloniaProgressRing/Styles/ProgressRing.xaml"/>
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
@@ -2,11 +2,10 @@ using System;
|
||||
using System.Globalization;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Data.Core;
|
||||
using Avalonia.Data.Core.Plugins;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Styling;
|
||||
using Clario.Data;
|
||||
using Clario.Services;
|
||||
using Clario.ViewModels;
|
||||
@@ -16,15 +15,42 @@ namespace Clario;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
public static bool IsMobile { get; private set; }
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
RequestedThemeVariant = ThemeVariant.Dark;
|
||||
}
|
||||
|
||||
public override async void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLoading)
|
||||
{
|
||||
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
|
||||
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
|
||||
DisableAvaloniaDataAnnotationValidation();
|
||||
|
||||
desktopLoading.MainWindow = new MainWindow
|
||||
{
|
||||
DataContext = new LoadingViewModel()
|
||||
};
|
||||
desktopLoading.MainWindow.Show();
|
||||
}
|
||||
|
||||
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatformLoading)
|
||||
{
|
||||
Console.WriteLine("ANDROID PATH HIT");
|
||||
singleViewPlatformLoading.MainView = new MainAppMobile()
|
||||
{
|
||||
DataContext = new LoadingViewModel()
|
||||
};
|
||||
}
|
||||
|
||||
IsMobile = ApplicationLifetime is ISingleViewApplicationLifetime;
|
||||
|
||||
var culture = new CultureInfo("en-US");
|
||||
|
||||
CultureInfo.DefaultThreadCurrentCulture = culture;
|
||||
@@ -36,7 +62,6 @@ public partial class App : Application
|
||||
}
|
||||
catch
|
||||
{
|
||||
/* session invalid or expired */
|
||||
}
|
||||
|
||||
var user = SupabaseService.Client.Auth.CurrentUser;
|
||||
@@ -53,19 +78,13 @@ public partial class App : Application
|
||||
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
|
||||
DisableAvaloniaDataAnnotationValidation();
|
||||
|
||||
desktop.MainWindow = new MainWindow
|
||||
{
|
||||
DataContext = user is not null ? new MainViewModel() : new AuthViewModel()
|
||||
};
|
||||
desktop.MainWindow.Show();
|
||||
desktop.MainWindow!.DataContext = user is not null ? new MainViewModel() : new AuthViewModel();
|
||||
}
|
||||
|
||||
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
|
||||
{
|
||||
singleViewPlatform.MainView = new MainView
|
||||
{
|
||||
DataContext = user is not null ? new MainViewModel() : new AuthViewModel()
|
||||
};
|
||||
Console.WriteLine("ANDROID PATH HIT");
|
||||
singleViewPlatform.MainView!.DataContext = user is not null ? new MainViewModel() : new AuthViewModel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
Clario/Assets/Icons/arrow-left-right.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-left-right-icon lucide-arrow-left-right"><path d="M8 3 4 7l4 4"/><path d="M4 7h16"/><path d="m16 21 4-4-4-4"/><path d="M20 17H4"/></svg>
|
||||
|
After Width: | Height: | Size: 344 B |
1
Clario/Assets/Icons/chart-bar.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chart-bar-icon lucide-chart-bar"><path d="M3 3v16a2 2 0 0 0 2 2h16"/><path d="M7 16h8"/><path d="M7 11h12"/><path d="M7 6h3"/></svg>
|
||||
|
After Width: | Height: | Size: 334 B |
1
Clario/Assets/Icons/chart-column.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chart-column-icon lucide-chart-column"><path d="M3 3v16a2 2 0 0 0 2 2h16"/><path d="M18 17V9"/><path d="M13 17V5"/><path d="M8 17v-3"/></svg>
|
||||
|
After Width: | Height: | Size: 343 B |
1
Clario/Assets/Icons/chevron-down.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down-icon lucide-chevron-down"><path d="m6 9 6 6 6-6"/></svg>
|
||||
|
After Width: | Height: | Size: 271 B |
1
Clario/Assets/Icons/receipt.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-receipt-icon lucide-receipt"><path d="M12 17V7"/><path d="M16 8h-6a2 2 0 0 0 0 4h4a2 2 0 0 1 0 4H8"/><path d="M4 3a1 1 0 0 1 1-1 1.3 1.3 0 0 1 .7.2l.933.6a1.3 1.3 0 0 0 1.4 0l.934-.6a1.3 1.3 0 0 1 1.4 0l.933.6a1.3 1.3 0 0 0 1.4 0l.933-.6a1.3 1.3 0 0 1 1.4 0l.934.6a1.3 1.3 0 0 0 1.4 0l.933-.6A1.3 1.3 0 0 1 19 2a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1 1.3 1.3 0 0 1-.7-.2l-.933-.6a1.3 1.3 0 0 0-1.4 0l-.934.6a1.3 1.3 0 0 1-1.4 0l-.933-.6a1.3 1.3 0 0 0-1.4 0l-.933.6a1.3 1.3 0 0 1-1.4 0l-.934-.6a1.3 1.3 0 0 0-1.4 0l-.933.6a1.3 1.3 0 0 1-.7.2 1 1 0 0 1-1-1z"/></svg>
|
||||
|
After Width: | Height: | Size: 758 B |
1
Clario/Assets/Icons/sliders-horizontal.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sliders-horizontal-icon lucide-sliders-horizontal"><path d="M10 5H3"/><path d="M12 19H3"/><path d="M14 3v4"/><path d="M16 17v4"/><path d="M21 12h-9"/><path d="M21 19h-5"/><path d="M21 5h-7"/><path d="M8 10v4"/><path d="M8 12H3"/></svg>
|
||||
|
After Width: | Height: | Size: 437 B |
BIN
Clario/Assets/Logo.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
Clario/Assets/logo-no-bg-no-color.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
6
Clario/Assets/logo-no-bg-no-color.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="400" height="400" viewBox="0 0 400 400" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M126.626 365.882C123.313 372.544 126.012 380.678 132.887 383.521C170.367 399.024 211.887 402.425 251.579 393.049C291.272 383.673 326.884 362.052 353.47 331.415C358.346 325.796 357.122 317.314 351.18 312.838L317.364 287.368C311.422 282.892 303.026 284.142 297.937 289.568C281.239 307.373 259.604 319.962 235.658 325.619C211.713 331.275 186.733 329.698 163.835 321.246C156.857 318.67 148.79 321.309 145.477 327.971L126.626 365.882Z" fill="#D9D9D9"/>
|
||||
<path d="M36.1852 130.258C29.3501 127.322 21.3816 130.472 18.9273 137.495C4.15218 179.781 4.42187 226.037 19.9494 268.347C35.477 310.657 65.1913 346.101 103.809 368.783C110.224 372.55 118.337 369.796 121.65 363.134L140.501 325.223C143.814 318.561 141.05 310.533 134.786 306.521C111.958 291.9 94.4015 270.153 84.9763 244.471C75.5511 218.789 74.8708 190.846 82.82 164.924C85.0015 157.811 81.9166 149.902 75.0814 146.966L36.1852 130.258Z" fill="#D9D9D9"/>
|
||||
<path d="M219.24 16.3331C219.888 8.92088 214.403 2.33719 206.965 2.20454C170.831 1.56007 135.136 11.0294 103.966 29.6733C72.7955 48.3173 47.5647 75.2901 31.0342 107.435C27.6317 114.052 30.8347 122.001 37.6698 124.937L76.5661 141.645C83.4012 144.581 91.2596 141.373 94.9148 134.892C105.519 116.092 120.864 100.295 139.517 89.1377C158.17 77.9805 179.345 71.9343 200.921 71.4863C208.358 71.3318 214.902 65.9253 215.55 58.5131L219.24 16.3331Z" fill="#D9D9D9"/>
|
||||
<path d="M353.471 88.3147C359.447 83.8846 360.736 75.4123 355.903 69.7563C341.041 52.3641 323.197 37.7107 303.173 26.5042C283.15 15.2977 261.329 7.75132 238.736 4.18055C231.388 3.0193 224.843 8.55036 224.195 15.9625L220.506 58.1426C219.857 65.5548 225.363 72.0157 232.66 73.4596C245.497 75.9993 257.881 80.55 269.349 86.9681C280.816 93.3862 291.173 101.563 300.051 111.177C305.099 116.642 313.484 117.955 319.461 113.525L353.471 88.3147Z" fill="#D9D9D9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
BIN
Clario/Assets/logo-no-bg.ico
Normal file
|
After Width: | Height: | Size: 171 KiB |
BIN
Clario/Assets/logo-no-bg.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
11
Clario/Assets/logo-textmark-no-color.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg width="599" height="200" viewBox="0 0 599 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M189.81 191.95V46.75H220.41V191.95H189.81Z" fill="white"/>
|
||||
<path d="M282.558 193.95C273.625 193.95 265.625 191.75 258.558 187.35C251.625 182.95 246.092 176.95 241.958 169.35C237.958 161.75 235.958 153.083 235.958 143.35C235.958 133.617 237.958 124.95 241.958 117.35C246.092 109.75 251.625 103.75 258.558 99.35C265.625 94.95 273.625 92.75 282.558 92.75C289.092 92.75 294.958 94.0167 300.159 96.55C305.492 99.0833 309.825 102.617 313.159 107.15C316.492 111.55 318.359 116.617 318.758 122.35V164.35C318.359 170.083 316.492 175.217 313.159 179.75C309.958 184.15 305.692 187.617 300.358 190.15C295.025 192.683 289.092 193.95 282.558 193.95ZM288.758 166.35C295.292 166.35 300.559 164.217 304.559 159.95C308.559 155.55 310.559 150.017 310.559 143.35C310.559 138.817 309.625 134.817 307.758 131.35C306.025 127.883 303.492 125.217 300.159 123.35C296.958 121.35 293.225 120.35 288.958 120.35C284.692 120.35 280.892 121.35 277.558 123.35C274.358 125.217 271.758 127.883 269.758 131.35C267.892 134.817 266.958 138.817 266.958 143.35C266.958 147.75 267.892 151.683 269.758 155.15C271.625 158.617 274.225 161.35 277.558 163.35C280.892 165.35 284.625 166.35 288.758 166.35ZM309.359 191.95V165.75L313.959 142.15L309.359 118.55V94.75H339.358V191.95H309.359Z" fill="white"/>
|
||||
<path d="M360.904 191.95V94.75H391.504V191.95H360.904ZM391.504 138.55L378.704 128.55C381.237 117.217 385.504 108.417 391.504 102.15C397.504 95.8833 405.837 92.75 416.504 92.75C421.17 92.75 425.237 93.4833 428.704 94.95C432.304 96.2833 435.437 98.4167 438.104 101.35L419.904 124.35C418.57 122.883 416.904 121.75 414.904 120.95C412.904 120.15 410.637 119.75 408.104 119.75C403.037 119.75 398.97 121.35 395.904 124.55C392.97 127.617 391.504 132.283 391.504 138.55Z" fill="white"/>
|
||||
<path d="M446.255 191.95V94.75H476.855V191.95H446.255ZM461.655 81.35C456.855 81.35 452.855 79.75 449.655 76.55C446.589 73.2167 445.055 69.2167 445.055 64.55C445.055 59.75 446.589 55.75 449.655 52.55C452.855 49.35 456.855 47.75 461.655 47.75C466.455 47.75 470.389 49.35 473.455 52.55C476.522 55.75 478.055 59.75 478.055 64.55C478.055 69.2167 476.522 73.2167 473.455 76.55C470.389 79.75 466.455 81.35 461.655 81.35Z" fill="white"/>
|
||||
<path d="M545.204 194.15C535.204 194.15 526.137 191.95 518.004 187.55C510.004 183.017 503.67 176.883 499.004 169.15C494.337 161.417 492.004 152.75 492.004 143.15C492.004 133.55 494.337 124.95 499.004 117.35C503.67 109.75 510.004 103.75 518.004 99.35C526.004 94.8167 535.07 92.55 545.204 92.55C555.337 92.55 564.404 94.75 572.404 99.15C580.404 103.55 586.737 109.617 591.404 117.35C596.07 124.95 598.404 133.55 598.404 143.15C598.404 152.75 596.07 161.417 591.404 169.15C586.737 176.883 580.404 183.017 572.404 187.55C564.404 191.95 555.337 194.15 545.204 194.15ZM545.204 166.35C549.604 166.35 553.47 165.417 556.804 163.55C560.137 161.55 562.67 158.817 564.404 155.35C566.27 151.75 567.204 147.683 567.204 143.15C567.204 138.617 566.27 134.683 564.404 131.35C562.537 127.883 559.937 125.217 556.604 123.35C553.404 121.35 549.604 120.35 545.204 120.35C540.937 120.35 537.137 121.35 533.804 123.35C530.47 125.217 527.87 127.883 526.004 131.35C524.137 134.817 523.204 138.817 523.204 143.35C523.204 147.75 524.137 151.75 526.004 155.35C527.87 158.817 530.47 161.55 533.804 163.55C537.137 165.417 540.937 166.35 545.204 166.35Z" fill="white"/>
|
||||
<path d="M58.3942 177.927C56.8103 181.056 58.1009 184.876 61.3877 186.211C79.3085 193.492 99.1607 195.089 118.139 190.686C137.118 186.282 154.145 176.128 166.857 161.741C169.188 159.102 168.603 155.118 165.762 153.016L149.593 141.055C146.752 138.953 142.738 139.54 140.304 142.088C132.32 150.45 121.976 156.362 110.527 159.018C99.0775 161.675 87.1337 160.934 76.1854 156.965C72.8486 155.755 68.9915 156.995 67.4076 160.123L58.3942 177.927Z" fill="white"/>
|
||||
<path d="M13.4482 64.2591C10.1788 62.8547 6.36734 64.3615 5.19343 67.7212C-1.87383 87.9474 -1.74484 110.073 5.68233 130.31C13.1095 150.548 27.3224 167.502 45.7942 178.351C48.8625 180.153 52.7433 178.836 54.3278 175.649L63.3447 157.515C64.9292 154.329 63.6073 150.489 60.6108 148.57C49.6917 141.577 41.2943 131.174 36.786 118.89C32.2777 106.606 31.9523 93.2397 35.7546 80.841C36.7981 77.4385 35.3225 73.6553 32.0531 72.2509L13.4482 64.2591Z" fill="white"/>
|
||||
<path d="M101.59 6.83964C101.899 3.2592 99.2892 0.0789703 95.751 0.0148925C78.5612 -0.296416 61.5802 4.27773 46.7519 13.2836C31.9237 22.2895 19.9208 35.3186 12.0569 50.8462C10.4383 54.0423 11.962 57.882 15.2136 59.3002L33.7174 67.371C36.969 68.7892 40.7074 67.2396 42.4462 64.1093C47.4908 55.028 54.7906 47.3972 63.6644 42.0077C72.5383 36.6182 82.6114 33.6976 92.8756 33.4812C96.4136 33.4066 99.5267 30.795 99.8352 27.2146L101.59 6.83964Z" fill="white"/>
|
||||
<path d="M167.422 40.8672C170.27 38.76 170.884 34.7301 168.581 32.0398C161.498 23.7672 152.994 16.7972 143.452 11.4668C133.909 6.13639 123.51 2.54693 112.743 0.848476C109.241 0.296127 106.122 2.92699 105.813 6.45263L104.055 26.5157C103.746 30.0414 106.37 33.1145 109.847 33.8013C115.965 35.0094 121.867 37.1739 127.332 40.2267C132.797 43.2795 137.732 47.1688 141.964 51.7416C144.369 54.3412 148.366 54.9659 151.214 52.8587L167.422 40.8672Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
BIN
Clario/Assets/logo-textmark.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
@@ -1,28 +1,47 @@
|
||||
<svg width="800" height="400" viewBox="0 0 800 400" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M211.696 66.3202C212.178 60.8183 208.105 55.9315 202.583 55.833C175.756 55.3546 149.254 62.3834 126.112 76.2222C102.97 90.061 84.238 110.082 71.9651 133.942C69.4389 138.853 71.817 144.754 76.8916 146.933L105.77 159.335C110.844 161.514 116.679 159.133 119.393 154.323C127.265 140.368 138.658 128.642 152.507 120.361C166.356 112.079 182.077 107.591 198.096 107.259C203.617 107.144 208.476 103.131 208.957 97.6291L211.696 66.3202Z" fill="url(#paint0_linear_104_124)"/>
|
||||
<path d="M76.8916 146.933C71.817 144.754 65.9008 147.092 64.0787 152.306C53.1091 183.693 53.3093 218.027 64.8376 249.432C76.3659 280.837 98.4269 307.147 127.098 323.983C131.861 326.779 137.885 324.735 140.344 319.79L154.34 291.649C156.799 286.704 154.748 280.746 150.097 277.768C133.148 266.915 120.114 250.773 113.116 231.71C106.118 212.647 105.613 191.906 111.515 172.665C113.135 167.385 110.844 161.514 105.77 159.335L76.8916 146.933Z" fill="url(#paint1_linear_104_124)"/>
|
||||
<path d="M140.344 319.79C137.885 324.735 139.889 330.772 144.992 332.882C172.819 344.389 203.645 346.914 233.115 339.955C262.584 332.995 289.023 316.946 308.762 294.206C312.383 290.035 311.474 283.739 307.062 280.417L281.956 261.511C277.544 258.189 271.311 259.116 267.532 263.144C255.135 276.36 239.072 285.704 221.294 289.903C203.516 294.102 184.97 292.931 167.97 286.657C162.789 284.745 156.799 286.704 154.34 291.649L140.344 319.79Z" fill="url(#paint2_linear_104_124)"/>
|
||||
<path d="M307.676 120.025C312.113 116.736 313.07 110.448 309.482 106.25C298.448 93.3399 285.199 82.4632 270.333 74.1449C255.467 65.8267 239.266 60.2252 222.492 57.5748C217.037 56.7128 212.178 60.8183 211.696 66.3202L208.957 97.6291C208.476 103.131 212.563 107.927 217.981 108.998C227.511 110.884 236.706 114.261 245.22 119.025C253.734 123.789 261.423 129.859 268.015 136.994C271.763 141.051 277.988 142.026 282.425 138.738L307.676 120.025Z" fill="url(#paint3_linear_104_124)"/>
|
||||
<path d="M105.77 159.335L76.8916 146.933M105.77 159.335C110.844 161.514 116.679 159.133 119.393 154.323C127.265 140.368 138.658 128.642 152.507 120.361C166.356 112.079 182.077 107.591 198.096 107.259C203.617 107.144 208.476 103.131 208.957 97.6291M105.77 159.335C110.844 161.514 113.135 167.385 111.515 172.665C105.613 191.906 106.118 212.647 113.116 231.71C120.114 250.773 133.148 266.915 150.097 277.768C154.748 280.746 156.799 286.704 154.34 291.649M76.8916 146.933C71.817 144.754 69.4389 138.853 71.9651 133.942C84.238 110.082 102.97 90.061 126.112 76.2222C149.254 62.3834 175.756 55.3546 202.583 55.833C208.105 55.9315 212.178 60.8183 211.696 66.3202M76.8916 146.933C71.817 144.754 65.9008 147.092 64.0787 152.306C53.1091 183.693 53.3093 218.027 64.8376 249.432C76.3659 280.837 98.4269 307.147 127.098 323.983C131.861 326.779 137.885 324.735 140.344 319.79M208.957 97.6291L211.696 66.3202M208.957 97.6291C208.476 103.131 212.563 107.927 217.981 108.998C227.511 110.884 236.706 114.261 245.22 119.025C253.734 123.789 261.423 129.859 268.015 136.994C271.763 141.051 277.988 142.026 282.425 138.738L307.676 120.025C312.113 116.736 313.07 110.448 309.482 106.25C298.448 93.3399 285.199 82.4632 270.333 74.1449C255.467 65.8267 239.266 60.2252 222.492 57.5748C217.037 56.7128 212.178 60.8183 211.696 66.3202M154.34 291.649L140.344 319.79M154.34 291.649C156.799 286.704 162.789 284.745 167.97 286.657C184.97 292.931 203.516 294.102 221.294 289.903C239.072 285.704 255.135 276.36 267.532 263.144C271.311 259.116 277.544 258.189 281.956 261.511L307.062 280.417C311.474 283.739 312.383 290.035 308.762 294.206C289.023 316.946 262.584 332.995 233.115 339.955C203.645 346.914 172.819 344.389 144.992 332.882C139.889 330.772 137.885 324.735 140.344 319.79" stroke="#13161E" stroke-width="5"/>
|
||||
<path d="M331.8 292V146.8H362.4V292H331.8ZM424.548 294C415.615 294 407.615 291.8 400.548 287.4C393.615 283 388.082 277 383.948 269.4C379.948 261.8 377.948 253.133 377.948 243.4C377.948 233.667 379.948 225 383.948 217.4C388.082 209.8 393.615 203.8 400.548 199.4C407.615 195 415.615 192.8 424.548 192.8C431.082 192.8 436.948 194.067 442.148 196.6C447.482 199.133 451.815 202.667 455.148 207.2C458.482 211.6 460.348 216.667 460.748 222.4V264.4C460.348 270.133 458.482 275.267 455.148 279.8C451.948 284.2 447.682 287.667 442.348 290.2C437.015 292.733 431.082 294 424.548 294ZM430.748 266.4C437.282 266.4 442.548 264.267 446.548 260C450.548 255.6 452.548 250.067 452.548 243.4C452.548 238.867 451.615 234.867 449.748 231.4C448.015 227.933 445.482 225.267 442.148 223.4C438.948 221.4 435.215 220.4 430.948 220.4C426.682 220.4 422.882 221.4 419.548 223.4C416.348 225.267 413.748 227.933 411.748 231.4C409.882 234.867 408.948 238.867 408.948 243.4C408.948 247.8 409.882 251.733 411.748 255.2C413.615 258.667 416.215 261.4 419.548 263.4C422.882 265.4 426.615 266.4 430.748 266.4ZM451.348 292V265.8L455.948 242.2L451.348 218.6V194.8H481.348V292H451.348ZM502.894 292V194.8H533.494V292H502.894ZM533.494 238.6L520.694 228.6C523.227 217.267 527.494 208.467 533.494 202.2C539.494 195.933 547.827 192.8 558.494 192.8C563.16 192.8 567.227 193.533 570.694 195C574.294 196.333 577.427 198.467 580.094 201.4L561.894 224.4C560.56 222.933 558.894 221.8 556.894 221C554.894 220.2 552.627 219.8 550.094 219.8C545.027 219.8 540.96 221.4 537.894 224.6C534.96 227.667 533.494 232.333 533.494 238.6ZM588.245 292V194.8H618.845V292H588.245ZM603.645 181.4C598.845 181.4 594.845 179.8 591.645 176.6C588.579 173.267 587.045 169.267 587.045 164.6C587.045 159.8 588.579 155.8 591.645 152.6C594.845 149.4 598.845 147.8 603.645 147.8C608.445 147.8 612.379 149.4 615.445 152.6C618.512 155.8 620.045 159.8 620.045 164.6C620.045 169.267 618.512 173.267 615.445 176.6C612.379 179.8 608.445 181.4 603.645 181.4ZM687.194 294.2C677.194 294.2 668.127 292 659.994 287.6C651.994 283.067 645.66 276.933 640.994 269.2C636.327 261.467 633.994 252.8 633.994 243.2C633.994 233.6 636.327 225 640.994 217.4C645.66 209.8 651.994 203.8 659.994 199.4C667.994 194.867 677.06 192.6 687.194 192.6C697.327 192.6 706.394 194.8 714.394 199.2C722.394 203.6 728.727 209.667 733.394 217.4C738.06 225 740.394 233.6 740.394 243.2C740.394 252.8 738.06 261.467 733.394 269.2C728.727 276.933 722.394 283.067 714.394 287.6C706.394 292 697.327 294.2 687.194 294.2ZM687.194 266.4C691.594 266.4 695.46 265.467 698.794 263.6C702.127 261.6 704.66 258.867 706.394 255.4C708.26 251.8 709.194 247.733 709.194 243.2C709.194 238.667 708.26 234.733 706.394 231.4C704.527 227.933 701.927 225.267 698.594 223.4C695.394 221.4 691.594 220.4 687.194 220.4C682.927 220.4 679.127 221.4 675.794 223.4C672.46 225.267 669.86 227.933 667.994 231.4C666.127 234.867 665.194 238.867 665.194 243.4C665.194 247.8 666.127 251.8 667.994 255.4C669.86 258.867 672.46 261.6 675.794 263.6C679.127 265.467 682.927 266.4 687.194 266.4Z" fill="url(#paint4_linear_104_124)"/>
|
||||
<path d="M331.8 292V146.8H362.4V292H331.8Z" fill="url(#paint0_linear_104_124)"/>
|
||||
<path d="M424.548 294C415.615 294 407.615 291.8 400.548 287.4C393.615 283 388.082 277 383.948 269.4C379.948 261.8 377.948 253.133 377.948 243.4C377.948 233.667 379.948 225 383.948 217.4C388.082 209.8 393.615 203.8 400.548 199.4C407.615 195 415.615 192.8 424.548 192.8C431.082 192.8 436.948 194.067 442.148 196.6C447.482 199.133 451.815 202.667 455.148 207.2C458.482 211.6 460.348 216.667 460.748 222.4V264.4C460.348 270.133 458.482 275.267 455.148 279.8C451.948 284.2 447.682 287.667 442.348 290.2C437.015 292.733 431.082 294 424.548 294ZM430.748 266.4C437.282 266.4 442.548 264.267 446.548 260C450.548 255.6 452.548 250.067 452.548 243.4C452.548 238.867 451.615 234.867 449.748 231.4C448.015 227.933 445.482 225.267 442.148 223.4C438.948 221.4 435.215 220.4 430.948 220.4C426.682 220.4 422.882 221.4 419.548 223.4C416.348 225.267 413.748 227.933 411.748 231.4C409.882 234.867 408.948 238.867 408.948 243.4C408.948 247.8 409.882 251.733 411.748 255.2C413.615 258.667 416.215 261.4 419.548 263.4C422.882 265.4 426.615 266.4 430.748 266.4ZM451.348 292V265.8L455.948 242.2L451.348 218.6V194.8H481.348V292H451.348Z" fill="url(#paint1_linear_104_124)"/>
|
||||
<path d="M502.894 292V194.8H533.494V292H502.894ZM533.494 238.6L520.694 228.6C523.227 217.267 527.494 208.467 533.494 202.2C539.494 195.933 547.827 192.8 558.494 192.8C563.16 192.8 567.227 193.533 570.694 195C574.294 196.333 577.427 198.467 580.094 201.4L561.894 224.4C560.56 222.933 558.894 221.8 556.894 221C554.894 220.2 552.627 219.8 550.094 219.8C545.027 219.8 540.96 221.4 537.894 224.6C534.96 227.667 533.494 232.333 533.494 238.6Z" fill="url(#paint2_linear_104_124)"/>
|
||||
<path d="M588.245 292V194.8H618.845V292H588.245ZM603.645 181.4C598.845 181.4 594.845 179.8 591.645 176.6C588.579 173.267 587.045 169.267 587.045 164.6C587.045 159.8 588.579 155.8 591.645 152.6C594.845 149.4 598.845 147.8 603.645 147.8C608.445 147.8 612.379 149.4 615.445 152.6C618.512 155.8 620.045 159.8 620.045 164.6C620.045 169.267 618.512 173.267 615.445 176.6C612.379 179.8 608.445 181.4 603.645 181.4Z" fill="url(#paint3_linear_104_124)"/>
|
||||
<path d="M687.194 294.2C677.194 294.2 668.127 292 659.994 287.6C651.994 283.067 645.66 276.933 640.994 269.2C636.327 261.467 633.994 252.8 633.994 243.2C633.994 233.6 636.327 225 640.994 217.4C645.66 209.8 651.994 203.8 659.994 199.4C667.994 194.867 677.06 192.6 687.194 192.6C697.327 192.6 706.394 194.8 714.394 199.2C722.394 203.6 728.727 209.667 733.394 217.4C738.06 225 740.394 233.6 740.394 243.2C740.394 252.8 738.06 261.467 733.394 269.2C728.727 276.933 722.394 283.067 714.394 287.6C706.394 292 697.327 294.2 687.194 294.2ZM687.194 266.4C691.594 266.4 695.46 265.467 698.794 263.6C702.127 261.6 704.66 258.867 706.394 255.4C708.26 251.8 709.194 247.733 709.194 243.2C709.194 238.667 708.26 234.733 706.394 231.4C704.527 227.933 701.927 225.267 698.594 223.4C695.394 221.4 691.594 220.4 687.194 220.4C682.927 220.4 679.127 221.4 675.794 223.4C672.46 225.267 669.86 227.933 667.994 231.4C666.127 234.867 665.194 238.867 665.194 243.4C665.194 247.8 666.127 251.8 667.994 255.4C669.86 258.867 672.46 261.6 675.794 263.6C679.127 265.467 682.927 266.4 687.194 266.4Z" fill="url(#paint4_linear_104_124)"/>
|
||||
<path d="M142.075 320.852C139.663 325.703 141.628 331.626 146.634 333.697C173.927 344.985 204.162 347.462 233.066 340.635C261.97 333.807 287.902 318.062 307.262 295.753C310.813 291.661 309.922 285.484 305.595 282.225L280.97 263.678C276.643 260.419 270.529 261.329 266.823 265.28C254.664 278.246 238.909 287.413 221.472 291.532C204.035 295.651 185.845 294.502 169.171 288.348C164.089 286.472 158.214 288.394 155.802 293.245L142.075 320.852Z" fill="url(#paint5_linear_104_124)"/>
|
||||
<path d="M76.2161 149.27C71.2388 147.132 65.4361 149.426 63.6489 154.541C52.8897 185.333 53.0861 219.017 64.3932 249.827C75.7004 280.637 97.3382 306.447 125.46 322.964C130.131 325.708 136.039 323.702 138.451 318.85L152.179 291.244C154.591 286.392 152.579 280.547 148.017 277.625C131.393 266.978 118.609 251.142 111.746 232.44C104.882 213.739 104.387 193.39 110.175 174.515C111.764 169.335 109.518 163.575 104.54 161.437L76.2161 149.27Z" fill="url(#paint6_linear_104_124)"/>
|
||||
<path d="M209.516 66.3108C209.988 60.9133 205.994 56.119 200.578 56.0225C174.265 55.5532 148.272 62.4487 125.574 76.0252C102.876 89.6016 84.5026 109.243 72.4651 132.651C69.9874 137.469 72.3198 143.258 77.2972 145.396L105.621 157.562C110.599 159.7 116.321 157.364 118.983 152.645C126.705 138.955 137.879 127.452 151.462 119.327C165.045 111.202 180.464 106.8 196.176 106.473C201.592 106.361 206.357 102.424 206.829 97.0263L209.516 66.3108Z" fill="url(#paint7_linear_104_124)"/>
|
||||
<path d="M307.263 118.728C311.615 115.502 312.553 109.332 309.034 105.213C298.212 92.5486 285.217 81.878 270.636 73.7174C256.055 65.5569 240.165 60.0616 223.713 57.4614C218.362 56.6158 213.597 60.6435 213.124 66.041L210.438 96.7565C209.966 102.154 213.975 106.859 219.289 107.91C228.636 109.76 237.655 113.073 246.005 117.747C254.356 122.421 261.897 128.375 268.363 135.376C272.038 139.356 278.145 140.312 282.497 137.086L307.263 118.728Z" fill="url(#paint8_linear_104_124)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_104_124" x1="317.366" y1="64.3917" x2="259.803" y2="159.58" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint0_linear_104_124" x1="745" y1="91.9999" x2="321" y2="344" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#7B9CFF"/>
|
||||
<stop offset="1" stop-color="#3B6AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_104_124" x1="317.366" y1="64.3917" x2="259.803" y2="159.58" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint1_linear_104_124" x1="745" y1="91.9999" x2="321" y2="344" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#7B9CFF"/>
|
||||
<stop offset="1" stop-color="#3B6AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_104_124" x1="317.366" y1="64.3917" x2="259.803" y2="159.58" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint2_linear_104_124" x1="745" y1="91.9999" x2="321" y2="344" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#7B9CFF"/>
|
||||
<stop offset="1" stop-color="#3B6AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear_104_124" x1="317.366" y1="64.3917" x2="259.803" y2="159.58" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint3_linear_104_124" x1="745" y1="91.9999" x2="321" y2="344" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#7B9CFF"/>
|
||||
<stop offset="1" stop-color="#3B6AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint4_linear_104_124" x1="745" y1="92" x2="321" y2="344" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint4_linear_104_124" x1="745" y1="91.9999" x2="321" y2="344" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#7B9CFF"/>
|
||||
<stop offset="1" stop-color="#3B6AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint5_linear_104_124" x1="315.701" y1="70.2952" x2="259.223" y2="163.668" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#7B9CFF"/>
|
||||
<stop offset="1" stop-color="#3B6AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint6_linear_104_124" x1="312.078" y1="68.2937" x2="255.6" y2="161.666" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#7B9CFF"/>
|
||||
<stop offset="1" stop-color="#3B6AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint7_linear_104_124" x1="313.159" y1="64.4189" x2="256.681" y2="157.791" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#7B9CFF"/>
|
||||
<stop offset="1" stop-color="#3B6AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint8_linear_104_124" x1="316.768" y1="64.1491" x2="260.29" y2="157.521" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#7B9CFF"/>
|
||||
<stop offset="1" stop-color="#3B6AFF"/>
|
||||
</linearGradient>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.0 KiB |
65
Clario/Behaviors/NumericInputBehavior.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Xaml.Interactivity;
|
||||
|
||||
namespace Clario.Behaviors;
|
||||
|
||||
public class NumericInputBehavior : Behavior<TextBox>
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
base.OnAttached();
|
||||
AssociatedObject!.AddHandler(TextBox.TextInputEvent, OnTextInput, RoutingStrategies.Tunnel);
|
||||
AssociatedObject.TextChanged += OnTextChanged;
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
base.OnDetaching();
|
||||
AssociatedObject!.RemoveHandler(TextBox.TextInputEvent, OnTextInput);
|
||||
AssociatedObject.TextChanged -= OnTextChanged;
|
||||
}
|
||||
|
||||
private void OnTextInput(object? sender, TextInputEventArgs e)
|
||||
{
|
||||
if (e.Text is null) return;
|
||||
foreach (var c in e.Text)
|
||||
{
|
||||
if (!char.IsDigit(c) && c != '.')
|
||||
{
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var current = (sender as TextBox)?.Text ?? "";
|
||||
if (e.Text.Contains('.') && current.Contains('.'))
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTextChanged(object? sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (sender is not TextBox tb) return;
|
||||
var text = tb.Text ?? "";
|
||||
|
||||
var clean = new string(text.Where(c => char.IsDigit(c) || c == '.').ToArray());
|
||||
|
||||
var dotIndex = clean.IndexOf('.');
|
||||
if (dotIndex >= 0)
|
||||
{
|
||||
clean = clean[..(dotIndex + 1)] + clean[(dotIndex + 1)..].Replace(".", "");
|
||||
}
|
||||
|
||||
if (clean != text)
|
||||
{
|
||||
var caret = tb.CaretIndex;
|
||||
tb.Text = clean;
|
||||
tb.CaretIndex = Math.Min(caret, clean.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,21 @@
|
||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm"/>
|
||||
<PackageReference Include="Deadpikle.AvaloniaProgressRing" />
|
||||
<PackageReference Include="FluentAvalonia.ProgressRing" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.WebAssembly" />
|
||||
<PackageReference Include="Supabase" />
|
||||
<PackageReference Include="Xaml.Behaviors.Interactions" />
|
||||
<PackageReference Include="Xaml.Behaviors.Interactivity" />
|
||||
<PackageReference Include="SkiaSharp" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="MobileViews\MainAppMobile.axaml.cs">
|
||||
<DependentUpon>MobileMainView.axaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -11,7 +11,7 @@ public class AccountFromIdConverter : IValueConverter
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not Guid) return null;
|
||||
var accounts = DataRepo.General.Accounts;
|
||||
var accounts = DataRepo.General.FetchAccounts().Result;
|
||||
if (accounts is null) return null;
|
||||
return accounts.FirstOrDefault(x => x.Id == (Guid)value)?.Name;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public class AccountMaskToStringConverter : IValueConverter
|
||||
{
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not string mask) return string.Empty;
|
||||
if (value is not string mask || string.IsNullOrWhiteSpace(mask)) return string.Empty;
|
||||
return $"•••• {mask}";
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,11 @@ public class AmountSignConverter : IMultiValueConverter
|
||||
{
|
||||
if (values.Any(x => x is null) || values.Count < 2) return 0;
|
||||
if (values[0] is decimal amount && values[1] is string type)
|
||||
return (type.Equals("income", StringComparison.CurrentCultureIgnoreCase) ? amount : -amount);
|
||||
if (parameter is string param && param.Equals("round"))
|
||||
return (type.Equals("income", StringComparison.CurrentCultureIgnoreCase) ? $"${Math.Round(amount)}" : $"-${Math.Round(amount)}");
|
||||
else
|
||||
return (type.Equals("income", StringComparison.CurrentCultureIgnoreCase) ? $"${amount}" : $"-${amount}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
33
Clario/Converters/BoolToColorConverter.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Avalonia;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace Clario.Converters;
|
||||
|
||||
// BoolToColorConverter.cs
|
||||
public class BoolToColorConverter : IValueConverter
|
||||
{
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not bool boolValue || parameter is not string colors)
|
||||
return AvaloniaProperty.UnsetValue;
|
||||
|
||||
var parts = colors.Split('|');
|
||||
if (parts.Length != 2) return AvaloniaProperty.UnsetValue;
|
||||
|
||||
var hex = boolValue ? parts[0] : parts[1];
|
||||
|
||||
if (targetType == typeof(IBrush) || targetType == typeof(SolidColorBrush))
|
||||
return SolidColorBrush.Parse(hex);
|
||||
|
||||
if (targetType == typeof(Color))
|
||||
return Color.Parse(hex);
|
||||
|
||||
return SolidColorBrush.Parse(hex);
|
||||
}
|
||||
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> throw new NotImplementedException();
|
||||
}
|
||||
25
Clario/Converters/BoolToCssConverter.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Avalonia;
|
||||
using Avalonia.Data.Converters;
|
||||
|
||||
namespace Clario.Converters;
|
||||
|
||||
// BoolToCssConverter.cs
|
||||
public class BoolToCssConverter : IValueConverter
|
||||
{
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not bool b || parameter is not string colors)
|
||||
return AvaloniaProperty.UnsetValue;
|
||||
|
||||
var parts = colors.Split('|');
|
||||
if (parts.Length != 2) return AvaloniaProperty.UnsetValue;
|
||||
|
||||
var hex = b ? parts[0] : parts[1];
|
||||
return $"path, circle, rect, ellipse, line, polyline, polygon, text, use {{ stroke: {hex}; }}";
|
||||
}
|
||||
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> throw new NotImplementedException();
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace Clario.Converters;
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ public class DecimalSignConverter : IValueConverter
|
||||
{
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is decimal d) return (d < 0 ? $"-${Math.Abs(Math.Round(d))}" : $"+${Math.Abs(Math.Round(d))}");
|
||||
if (value is decimal d)
|
||||
return (d < 0 ? $"-${Math.Abs(Math.Round(d))}" : $"+${Math.Abs(Math.Round(d))}");
|
||||
return "$0";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices.JavaScript;
|
||||
using Avalonia.Data.Converters;
|
||||
|
||||
namespace Clario.Converters;
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Avalonia.Data.Converters;
|
||||
using LiveChartsCore.SkiaSharpView.Avalonia;
|
||||
|
||||
namespace Clario.Converters;
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ public class PercentageConverter : IMultiValueConverter
|
||||
|
||||
if (value[0] is decimal part && value[1] is decimal total && part > 0)
|
||||
{
|
||||
var percentage = Math.Round(part / total, 2);
|
||||
return percentage.ToString("0%");
|
||||
var percentage = Math.Round(part / total, 3);
|
||||
return percentage.ToString("0.0%");
|
||||
}
|
||||
|
||||
return "0%";
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Avalonia.Data.Converters;
|
||||
using Clario.Data;
|
||||
|
||||
namespace Clario.Converters;
|
||||
|
||||
|
||||
@@ -1,50 +1,85 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:Clario.CustomControls">
|
||||
<Design.PreviewWith>
|
||||
<Border Padding="20">
|
||||
<!-- Add Controls for Previewer Here -->
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
|
||||
<Style Selector="local|DateRangePicker">
|
||||
<Setter Property="MinHeight" Value="15" />
|
||||
<Setter Property="MinWidth" Value="50" />
|
||||
<!-- <Setter Property="Background" Value="{TemplateBinding Background}" /> -->
|
||||
<!-- <Setter Property="Foreground" Value="{TemplateBinding Foreground}" /> -->
|
||||
<!-- <Setter Property="BorderBrush" Value="{TemplateBinding BorderBrush}" /> -->
|
||||
<!-- <Setter Property="CornerRadius" Value="{TemplateBinding CornerRadius}" /> -->
|
||||
<!-- <Setter Property="BorderThickness" Value="1" /> -->
|
||||
<Setter Property="Background" Value="{DynamicResource BgBase}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextSecondary}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource BorderSubtle}" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusControl}" />
|
||||
<Setter Property="Padding" Value="10,8 2 8" />
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Grid>
|
||||
|
||||
<!-- Button -->
|
||||
<!-- Trigger button -->
|
||||
<Button x:Name="PART_Button"
|
||||
Content="{TemplateBinding DisplayText}" HorizontalAlignment="Stretch"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
FontSize="{TemplateBinding FontSize}"
|
||||
FontWeight="{TemplateBinding FontWeight}"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}"
|
||||
Foreground="{TemplateBinding Foreground}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{TemplateBinding CornerRadius}" />
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
FontSize="{TemplateBinding FontSize}"
|
||||
FontWeight="{TemplateBinding FontWeight}">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<Svg Grid.Column="0"
|
||||
Path="../Assets/Icons/calendar-days.svg"
|
||||
Width="14" Height="14"
|
||||
Css="{DynamicResource SvgMuted}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,8,0" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{TemplateBinding DisplayText}"
|
||||
FontSize="{TemplateBinding FontSize}"
|
||||
Foreground="{TemplateBinding Foreground}"
|
||||
VerticalAlignment="Center"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<Svg Grid.Column="2"
|
||||
Path="../Assets/Icons/chevron-down.svg"
|
||||
Width="12" Height="12"
|
||||
Css="{DynamicResource SvgMuted}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="8,0,0,0" />
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<!-- Popup -->
|
||||
<Popup x:Name="PART_Popup"
|
||||
PlacementTarget="{Binding #PART_Button}"
|
||||
Placement="Bottom"
|
||||
IsLightDismissEnabled="True">
|
||||
|
||||
<Border Padding="8">
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{DynamicResource RadiusControl}"
|
||||
Padding="4"
|
||||
BoxShadow="0 8 32 0 #3C000000">
|
||||
<Calendar x:Name="PART_Calendar"
|
||||
SelectionMode="{TemplateBinding SelectionMode}" />
|
||||
SelectionMode="{TemplateBinding SelectionMode}"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderThickness="0" />
|
||||
</Border>
|
||||
|
||||
</Popup>
|
||||
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- pointerover -->
|
||||
<Style Selector="local|DateRangePicker:pointerover /template/ Button#PART_Button">
|
||||
<Setter Property="Background" Value="{DynamicResource BgHover}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource BorderAccent}" />
|
||||
</Style>
|
||||
|
||||
<!-- pressed -->
|
||||
<Style Selector="local|DateRangePicker:pressed /template/ Button#PART_Button">
|
||||
<Setter Property="Background" Value="{DynamicResource BorderSubtle}" />
|
||||
</Style>
|
||||
|
||||
</Styles>
|
||||
@@ -1,9 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Calendar = Avalonia.Controls.Calendar;
|
||||
|
||||
namespace Clario.CustomControls;
|
||||
|
||||
@@ -19,7 +23,6 @@ public class DateRangePicker : TemplatedControl
|
||||
set => SetValue(SelectionModeProperty, value);
|
||||
}
|
||||
|
||||
|
||||
public static readonly StyledProperty<IList<DateTime>> SelectedDatesProperty =
|
||||
AvaloniaProperty.Register<DateRangePicker, IList<DateTime>>(
|
||||
nameof(SelectedDates), new List<DateTime>());
|
||||
@@ -30,6 +33,16 @@ public class DateRangePicker : TemplatedControl
|
||||
set => SetValue(SelectedDatesProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<DateTime?> SelectedDateProperty =
|
||||
AvaloniaProperty.Register<DateRangePicker, DateTime?>(
|
||||
nameof(SelectedDate), null);
|
||||
|
||||
public DateTime? SelectedDate
|
||||
{
|
||||
get => GetValue(SelectedDateProperty);
|
||||
set => SetValue(SelectedDateProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<string> DisplayTextProperty =
|
||||
AvaloniaProperty.Register<DateRangePicker, string>(
|
||||
nameof(DisplayText), "Select Date");
|
||||
@@ -40,114 +53,223 @@ public class DateRangePicker : TemplatedControl
|
||||
set => SetValue(DisplayTextProperty, value);
|
||||
}
|
||||
|
||||
private Button _button;
|
||||
private Popup _popup;
|
||||
private Calendar _calendar;
|
||||
|
||||
private Button? _button;
|
||||
private Popup? _popup;
|
||||
private Calendar? _calendar;
|
||||
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
if (change.Property == SelectedDatesProperty && _calendar != null)
|
||||
{
|
||||
_calendar.SelectedDates.Clear();
|
||||
private bool _isSyncing = false;
|
||||
|
||||
foreach (var date in SelectedDates)
|
||||
{
|
||||
_calendar.SelectedDates.Add(date);
|
||||
}
|
||||
|
||||
if (SelectionMode == CalendarSelectionMode.SingleDate)
|
||||
_popup.IsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
|
||||
|
||||
if (_button != null) _button.Click -= OnButtonClick;
|
||||
if (_calendar != null)
|
||||
{
|
||||
_calendar.SelectedDatesChanged -= OnCalendarDatesChanged;
|
||||
_calendar.RemoveHandler(PointerReleasedEvent, OnCalendarPointerReleased);
|
||||
}
|
||||
|
||||
_button = e.NameScope.Find<Button>("PART_Button");
|
||||
_popup = e.NameScope.Find<Popup>("PART_Popup");
|
||||
_calendar = e.NameScope.Find<Calendar>("PART_Calendar");
|
||||
|
||||
if (_button != null)
|
||||
{
|
||||
_button.Click += (_, __) => _popup.IsOpen = true;
|
||||
_button.PointerEntered += (_, __) => PseudoClasses.Add(":pointerover");
|
||||
_button.PointerExited += (_, __) => PseudoClasses.Remove(":pointerover");
|
||||
_button.PointerPressed += (_, __) => PseudoClasses.Add(":pressed");
|
||||
_button.PointerReleased += (_, __) => PseudoClasses.Remove(":pressed");
|
||||
}
|
||||
_button.Click += OnButtonClick;
|
||||
|
||||
if (_calendar != null)
|
||||
{
|
||||
_calendar.SelectedDatesChanged += (_, __) =>
|
||||
{
|
||||
SelectedDates.Clear();
|
||||
foreach (var date in _calendar.SelectedDates)
|
||||
{
|
||||
SelectedDates.Add(date);
|
||||
}
|
||||
|
||||
if (SelectionMode == CalendarSelectionMode.SingleDate && SelectedDates.Count == 1) _popup.IsOpen = false;
|
||||
else if (SelectionMode == CalendarSelectionMode.SingleRange && SelectedDates.Count == 2) _popup.IsOpen = false;
|
||||
UpdateDisplayText();
|
||||
};
|
||||
_calendar.AllowTapRangeSelection = true;
|
||||
|
||||
|
||||
_calendar.SelectedDatesChanged += OnCalendarDatesChanged;
|
||||
_calendar.AddHandler(PointerReleasedEvent, OnCalendarPointerReleased, RoutingStrategies.Tunnel);
|
||||
|
||||
|
||||
SyncToCalendar();
|
||||
}
|
||||
|
||||
UpdateDisplayText();
|
||||
}
|
||||
|
||||
private void OnCalendarPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
if (_calendar!.SelectionMode != CalendarSelectionMode.SingleDate) return;
|
||||
|
||||
if (_isSyncing) return;
|
||||
|
||||
if (_popup is null || !_popup.IsOpen) return;
|
||||
|
||||
var newDates = _calendar!.SelectedDates.OrderBy(d => d).ToList();
|
||||
|
||||
_isSyncing = true;
|
||||
try
|
||||
{
|
||||
SelectedDates = newDates;
|
||||
|
||||
|
||||
SelectedDate = newDates.Count > 0 ? newDates[0] : null;
|
||||
|
||||
UpdateDisplayText();
|
||||
|
||||
|
||||
bool shouldClose = SelectionMode switch
|
||||
{
|
||||
CalendarSelectionMode.SingleDate => newDates.Count >= 1,
|
||||
CalendarSelectionMode.SingleRange => newDates.Count >= 2,
|
||||
_ => false
|
||||
};
|
||||
|
||||
if (shouldClose)
|
||||
_popup.IsOpen = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSyncing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnButtonClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_popup is null) return;
|
||||
|
||||
|
||||
SyncToCalendar();
|
||||
_popup.IsOpen = true;
|
||||
}
|
||||
|
||||
private void OnCalendarDatesChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (_calendar!.SelectionMode == CalendarSelectionMode.SingleDate) return;
|
||||
|
||||
if (_isSyncing) return;
|
||||
|
||||
if (_popup is null || !_popup.IsOpen) return;
|
||||
|
||||
var newDates = _calendar!.SelectedDates.OrderBy(d => d).ToList();
|
||||
|
||||
_isSyncing = true;
|
||||
try
|
||||
{
|
||||
SelectedDates = newDates;
|
||||
|
||||
|
||||
SelectedDate = newDates.Count > 0 ? newDates[0] : null;
|
||||
|
||||
UpdateDisplayText();
|
||||
|
||||
|
||||
bool shouldClose = SelectionMode switch
|
||||
{
|
||||
CalendarSelectionMode.SingleDate => newDates.Count >= 1,
|
||||
CalendarSelectionMode.SingleRange => newDates.Count >= 2,
|
||||
_ => false
|
||||
};
|
||||
|
||||
if (shouldClose)
|
||||
_popup.IsOpen = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSyncing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
||||
if (_isSyncing) return;
|
||||
|
||||
if (change.Property == SelectedDatesProperty)
|
||||
{
|
||||
_isSyncing = true;
|
||||
try
|
||||
{
|
||||
var dates = SelectedDates?.OrderBy(d => d).ToList() ?? new List<DateTime>();
|
||||
SelectedDate = dates.Count > 0 ? dates[0] : null;
|
||||
SyncToCalendar();
|
||||
UpdateDisplayText();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSyncing = false;
|
||||
}
|
||||
}
|
||||
else if (change.Property == SelectedDateProperty)
|
||||
{
|
||||
_isSyncing = true;
|
||||
try
|
||||
{
|
||||
SelectedDates = SelectedDate.HasValue
|
||||
? new List<DateTime> { SelectedDate.Value }
|
||||
: new List<DateTime>();
|
||||
SyncToCalendar();
|
||||
UpdateDisplayText();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSyncing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void SyncToCalendar()
|
||||
{
|
||||
if (_calendar is null || _isSyncing) return;
|
||||
|
||||
_isSyncing = true;
|
||||
try
|
||||
{
|
||||
_calendar.SelectedDates.Clear();
|
||||
if (SelectedDates is not null)
|
||||
{
|
||||
foreach (var date in SelectedDates)
|
||||
_calendar.SelectedDates.Add(date);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSyncing = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDisplayText()
|
||||
{
|
||||
if (SelectedDates == null || SelectedDates.Count == 0)
|
||||
var culture = new CultureInfo("en-US");
|
||||
|
||||
if (SelectedDates is null || SelectedDates.Count == 0)
|
||||
{
|
||||
switch (SelectionMode)
|
||||
DisplayText = SelectionMode switch
|
||||
{
|
||||
case CalendarSelectionMode.SingleDate:
|
||||
DisplayText = "Select Date";
|
||||
break;
|
||||
|
||||
case CalendarSelectionMode.SingleRange:
|
||||
DisplayText = "Select Date Range";
|
||||
break;
|
||||
default:
|
||||
DisplayText = "Select Date";
|
||||
break;
|
||||
}
|
||||
|
||||
CalendarSelectionMode.SingleDate => "Select Date",
|
||||
CalendarSelectionMode.SingleRange => "Select Date Range",
|
||||
_ => "Select Date"
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
var ordered = SelectedDates.OrderBy(d => d).ToList();
|
||||
|
||||
switch (SelectionMode)
|
||||
DisplayText = SelectionMode switch
|
||||
{
|
||||
case CalendarSelectionMode.SingleDate:
|
||||
DisplayText = ordered[0].ToString("MMM dd, yyyy");
|
||||
break;
|
||||
CalendarSelectionMode.SingleDate => ordered[0].ToString("MMM dd, yyyy", culture),
|
||||
|
||||
case CalendarSelectionMode.SingleRange:
|
||||
if (ordered.Count == 1)
|
||||
{
|
||||
DisplayText = ordered[0].ToString("MMM dd, yyyy");
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayText =
|
||||
$"{ordered.First():MMM dd, yyyy} → {ordered.Last():MMM dd, yyyy}";
|
||||
}
|
||||
CalendarSelectionMode.SingleRange => ordered.Count == 1
|
||||
? ordered[0].ToString("MMM dd, yyyy", culture)
|
||||
: $"{ordered.First().ToString("MMM dd, yyyy", culture)} → {ordered.Last().ToString("MMM dd, yyyy", culture)}",
|
||||
|
||||
break;
|
||||
CalendarSelectionMode.MultipleRange => string.Join(", ",
|
||||
ordered.Select(d => d.ToString("MMM dd, yyyy", culture))),
|
||||
|
||||
case CalendarSelectionMode.MultipleRange:
|
||||
DisplayText = string.Join(", ",
|
||||
ordered.Select(d => d.ToString("MMM dd, yyyy")));
|
||||
break;
|
||||
|
||||
default:
|
||||
DisplayText = ordered[0].ToString("MMM dd, yyyy");
|
||||
break;
|
||||
}
|
||||
_ => ordered[0].ToString("MMM dd, yyyy", culture)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -13,13 +13,15 @@ public class GeneralDataRepo
|
||||
public Profile? Profile { get; set; }
|
||||
public List<Category>? Categories { get; set; }
|
||||
public List<Account>? Accounts { get; set; }
|
||||
public List<Budget>? Budgets { get; set; }
|
||||
public List<Transaction>? Transactions { get; set; }
|
||||
|
||||
public async Task<Profile?> FetchProfileInfo()
|
||||
{
|
||||
if (Profile is not null) return Profile;
|
||||
|
||||
var profile = await SupabaseService.Client.From<Profile>().Get();
|
||||
return profile.Models.FirstOrDefault();
|
||||
Profile = profile.Model;
|
||||
return profile.Model;
|
||||
}
|
||||
|
||||
public async Task InsertProfileInfo(Profile profile)
|
||||
@@ -38,11 +40,42 @@ public class GeneralDataRepo
|
||||
}
|
||||
|
||||
public async Task<List<Transaction>> FetchTransactions()
|
||||
{
|
||||
if (Transactions is not null) return Transactions;
|
||||
var transactions = await SupabaseService.Client.From<Transaction>().Get();
|
||||
Transactions = transactions.Models;
|
||||
return transactions.Models;
|
||||
}
|
||||
|
||||
public async Task InsertTransaction(Transaction transaction)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transactions = await SupabaseService.Client.From<Transaction>().Get();
|
||||
return transactions.Models;
|
||||
await SupabaseService.Client.From<Transaction>().Insert(transaction);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateTransaction(Transaction transaction)
|
||||
{
|
||||
try
|
||||
{
|
||||
await SupabaseService.Client.From<Transaction>().Update(transaction);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteTransaction(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
await SupabaseService.Client.From<Transaction>().Where(x => x.Id == id).Delete();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -53,19 +86,10 @@ public class GeneralDataRepo
|
||||
|
||||
public async Task<List<Category>> FetchCategories()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Categories is not null) return Categories;
|
||||
var categories = await SupabaseService.Client.From<Category>().Get();
|
||||
Categories = categories.Models;
|
||||
// categories.Models.Select(x=>x.Icon).
|
||||
return categories.Models;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
if (Categories is not null) return Categories;
|
||||
var categories = await SupabaseService.Client.From<Category>().Get();
|
||||
Categories = categories.Models;
|
||||
return categories.Models;
|
||||
}
|
||||
|
||||
public async Task<List<Account>> FetchAccounts()
|
||||
@@ -75,4 +99,78 @@ public class GeneralDataRepo
|
||||
Accounts = accounts.Models;
|
||||
return accounts.Models;
|
||||
}
|
||||
|
||||
public async Task<List<Budget>> FetchBudgets()
|
||||
{
|
||||
if (Budgets is not null) return Budgets;
|
||||
var budgets = await SupabaseService.Client.From<Budget>().Get();
|
||||
Budgets = budgets.Models;
|
||||
return budgets.Models;
|
||||
}
|
||||
|
||||
public async Task<List<Budget>> FetchProcessedBudgets(DateTime CurrentPeriod)
|
||||
{
|
||||
var categories = await FetchCategories();
|
||||
var transactions = await FetchTransactions();
|
||||
var budgets = await FetchBudgets();
|
||||
var outputList = new List<Budget>();
|
||||
foreach (var budget in budgets)
|
||||
{
|
||||
budget.Category = categories.FirstOrDefault(x => x.Id == budget.CategoryId);
|
||||
|
||||
switch (budget.Period.ToLower())
|
||||
{
|
||||
case "monthly":
|
||||
var budgetTransactions = transactions.Where(x =>
|
||||
x.Date.Month == CurrentPeriod.Month && x.Date.Year == CurrentPeriod.Year && x.CategoryId == budget.CategoryId).ToList();
|
||||
budget.Spent = budgetTransactions.Sum(x => x.Amount);
|
||||
budget.TransactionsCount = budgetTransactions.Count;
|
||||
break;
|
||||
case "quarterly":
|
||||
var quarterTransactions = transactions.Where(x =>
|
||||
x.Date.Month >= CurrentPeriod.Month - 3 && x.Date.Month <= CurrentPeriod.Month && x.CategoryId == budget.CategoryId).ToList();
|
||||
budget.Spent = quarterTransactions.Sum(x => x.Amount);
|
||||
budget.TransactionsCount = quarterTransactions.Count;
|
||||
break;
|
||||
case "yearly":
|
||||
var yearTransactions = transactions.Where(x => x.Date.Year == CurrentPeriod.Year && x.CategoryId == budget.CategoryId).ToList();
|
||||
budget.Spent = yearTransactions.Sum(x => x.Amount);
|
||||
budget.TransactionsCount = yearTransactions.Count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (budgets.Any(x => x.IsOnTrack))
|
||||
{
|
||||
outputList.Add(new Budget() { Category = new Category() { Name = "ON TRACK" }, GroupHeader = true });
|
||||
var onTrack = budgets.Where(x => x.IsOnTrack).OrderByDescending(x => x.PercentageUsed).ToList();
|
||||
foreach (var budget in onTrack)
|
||||
{
|
||||
outputList.Add(budget);
|
||||
}
|
||||
}
|
||||
|
||||
if (budgets.Any(x => x.IsWarning))
|
||||
{
|
||||
outputList.Add(new Budget() { Category = new Category() { Name = "APPROACHING LIMIT" }, GroupHeader = true });
|
||||
var approaching = budgets.Where(x => x.IsWarning).OrderByDescending(x => x.PercentageUsed).ToList();
|
||||
foreach (var budget in approaching)
|
||||
{
|
||||
outputList.Add(budget);
|
||||
}
|
||||
}
|
||||
|
||||
if (budgets.Any(x => x.IsOverBudget))
|
||||
{
|
||||
outputList.Add(new Budget() { Category = new Category() { Name = "OVER BUDGET" }, GroupHeader = true });
|
||||
var overBudget = budgets.Where(x => x.IsOverBudget).OrderByDescending(x => x.PercentageUsed).ToList();
|
||||
foreach (var budget in overBudget)
|
||||
{
|
||||
outputList.Add(budget);
|
||||
}
|
||||
}
|
||||
|
||||
return outputList;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using LiveChartsCore.SkiaSharpView.Painting;
|
||||
using SkiaSharp;
|
||||
|
||||
480
Clario/MobileViews/AccountsViewMobile.axaml
Normal file
@@ -0,0 +1,480 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:Clario.ViewModels"
|
||||
xmlns:model="clr-namespace:Clario.Models"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Clario.MobileViews.AccountsViewMobile"
|
||||
x:DataType="vm:AccountsViewModel"
|
||||
x:Name="AccountsPage"
|
||||
Classes="mobile">
|
||||
<Design.DataContext>
|
||||
<vm:AccountsViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<!-- Root grid — content + overlay stacked -->
|
||||
<Grid>
|
||||
|
||||
<!-- ── Main content ───────────────────────── -->
|
||||
<Grid RowDefinitions="Auto,*"
|
||||
Background="{DynamicResource BgBase}">
|
||||
|
||||
<!-- Top bar -->
|
||||
<Grid Grid.Row="0"
|
||||
ColumnDefinitions="*,Auto"
|
||||
Margin="16,16,16,12">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Text="Accounts"
|
||||
FontSize="22"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
</StackPanel>
|
||||
<Button Grid.Column="1"
|
||||
Classes="accented"
|
||||
Padding="12,8"
|
||||
VerticalAlignment="Center">
|
||||
<Svg Path="../Assets/Icons/plus.svg"
|
||||
Width="16" Height="16"
|
||||
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #0D0F14; }" />
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<!-- Account list -->
|
||||
<ScrollViewer Grid.Row="1"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="16,0,16,24" Spacing="0">
|
||||
|
||||
<!-- Net worth banner -->
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="16,14"
|
||||
Margin="0,0,0,16">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<Border Grid.Column="0"
|
||||
Background="{DynamicResource IconBgBlue}"
|
||||
CornerRadius="10"
|
||||
Width="38" Height="38"
|
||||
Margin="0,0,12,0">
|
||||
<Svg Path="../Assets/Icons/circle-dollar-sign.svg"
|
||||
Width="17" Height="17"
|
||||
Css="{DynamicResource SvgBlue}" />
|
||||
</Border>
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="Total Net Worth"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding TotalBalance, StringFormat='$0.00'}"
|
||||
FontSize="17"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource AccentBlue}"
|
||||
VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Account cards -->
|
||||
<ItemsControl ItemsSource="{Binding VisibleAccounts}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Spacing="10" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="model:Account">
|
||||
<Panel>
|
||||
<!-- Group header -->
|
||||
<TextBlock Text="{Binding Name}"
|
||||
Classes="label"
|
||||
Margin="4,8,0,6"
|
||||
IsVisible="{Binding GroupHeader}" />
|
||||
|
||||
<!-- Account card -->
|
||||
<Button Classes="account"
|
||||
IsVisible="{Binding !GroupHeader}"
|
||||
HorizontalAlignment="Stretch"
|
||||
Command="{Binding DataContext.SelectAccountCommand, ElementName=AccountsPage}"
|
||||
CommandParameter="{Binding .}">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<!-- Icon -->
|
||||
<Border Grid.Column="0"
|
||||
CornerRadius="12"
|
||||
Width="44" Height="44"
|
||||
Margin="0,0,14,0">
|
||||
<Border.Background>
|
||||
<SolidColorBrush
|
||||
Color="{Binding Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=color}"
|
||||
Opacity="0.15" />
|
||||
</Border.Background>
|
||||
<Svg Path="{Binding Icon, Converter={StaticResource SvgPathFromName}}"
|
||||
Width="20" Height="20"
|
||||
Css="{Binding Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=css}" />
|
||||
</Border>
|
||||
<!-- Name + institution -->
|
||||
<StackPanel Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="3">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock Text="{Binding Institution}"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="{Binding Mask, Converter={StaticResource MaskToStringConverter}}"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<!-- Balance + trend -->
|
||||
<StackPanel Grid.Column="2"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="3">
|
||||
<TextBlock Text="{Binding CurrentBalance, StringFormat='$0.00'}"
|
||||
FontSize="15"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
HorizontalAlignment="Right" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="4" HorizontalAlignment="Right">
|
||||
<Svg Width="11" Height="11">
|
||||
<Svg.Path>
|
||||
<MultiBinding Converter="{StaticResource DecimalColorConverter}">
|
||||
<Binding Path="MonthlyIncrease" />
|
||||
<Binding Source="../Assets/Icons/trending-down.svg" />
|
||||
<Binding Source="../Assets/Icons/trending-up.svg" />
|
||||
</MultiBinding>
|
||||
</Svg.Path>
|
||||
<Svg.Css>
|
||||
<MultiBinding Converter="{StaticResource DecimalColorConverter}">
|
||||
<Binding Path="MonthlyIncrease" />
|
||||
<DynamicResource ResourceKey="SvgRed" />
|
||||
<DynamicResource ResourceKey="SvgGreen" />
|
||||
</MultiBinding>
|
||||
</Svg.Css>
|
||||
</Svg>
|
||||
<TextBlock Text="{Binding MonthlyIncrease, Converter={StaticResource DecimalSignConverter}}"
|
||||
FontSize="11">
|
||||
<TextBlock.Foreground>
|
||||
<MultiBinding Converter="{StaticResource DecimalColorConverter}">
|
||||
<Binding Path="MonthlyIncrease" />
|
||||
<DynamicResource ResourceKey="AccentRed" />
|
||||
<DynamicResource ResourceKey="AccentGreen" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Foreground>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Button>
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<!-- ── Bottom sheet overlay ───────────────── -->
|
||||
<Grid IsVisible="False"
|
||||
x:Name="OverlayGrid">
|
||||
|
||||
<!-- Dim background -->
|
||||
<Border Background="#80000000"
|
||||
x:Name="DimOverlay" />
|
||||
|
||||
<!-- Sheet -->
|
||||
<Border x:Name="BottomSheet"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
CornerRadius="20,20,0,0"
|
||||
VerticalAlignment="Bottom"
|
||||
MaxHeight="800"
|
||||
Padding="0,0,0,0">
|
||||
<Border.RenderTransform>
|
||||
<TranslateTransform Y="0" />
|
||||
</Border.RenderTransform>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
|
||||
<!-- Sheet handle + header -->
|
||||
<Grid Grid.Row="0" RowDefinitions="Auto,Auto">
|
||||
<!-- Drag handle -->
|
||||
<Border Grid.Row="0"
|
||||
Width="36" Height="4"
|
||||
Background="{DynamicResource BorderAccent}"
|
||||
CornerRadius="2"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,12,0,0" />
|
||||
|
||||
<!-- Header -->
|
||||
<Grid Grid.Row="1"
|
||||
ColumnDefinitions="Auto,*,Auto"
|
||||
Margin="20,16,20,0">
|
||||
<Border Grid.Column="0"
|
||||
CornerRadius="12"
|
||||
Width="44" Height="44"
|
||||
Margin="0,0,14,0">
|
||||
<Border.Background>
|
||||
<SolidColorBrush
|
||||
Color="{Binding SelectedAccount.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=color}"
|
||||
Opacity="0.15" />
|
||||
</Border.Background>
|
||||
<Svg Path="{Binding SelectedAccount.Icon, Converter={StaticResource SvgPathFromName}}"
|
||||
Width="20" Height="20"
|
||||
Css="{Binding SelectedAccount.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=css}" />
|
||||
</Border>
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center" Spacing="2">
|
||||
<TextBlock Text="{Binding SelectedAccount.Name}"
|
||||
FontSize="16"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<TextBlock Text="{Binding SelectedAccount.Institution}"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
</StackPanel>
|
||||
<!-- Close button -->
|
||||
<Button Grid.Column="2"
|
||||
Background="{DynamicResource BgBase}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="20"
|
||||
Width="34" Height="34"
|
||||
Padding="0"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalAlignment="Top"
|
||||
x:Name="CloseButton">
|
||||
<Svg Path="../Assets/Icons/x.svg"
|
||||
Width="14" Height="14"
|
||||
Css="{DynamicResource SvgMuted}" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Sheet scrollable content -->
|
||||
<ScrollViewer Grid.Row="1"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
Margin="0,16,0,0">
|
||||
<StackPanel Margin="20,0,20,32" Spacing="14">
|
||||
|
||||
<!-- Balance -->
|
||||
<Border Background="{DynamicResource BgBase}"
|
||||
CornerRadius="14"
|
||||
Padding="16,14">
|
||||
<StackPanel Spacing="4">
|
||||
<TextBlock Text="CURRENT BALANCE" Classes="label" />
|
||||
<TextBlock Text="{Binding SelectedAccount.CurrentBalance, StringFormat='$0.00'}"
|
||||
FontSize="28"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Details grid -->
|
||||
<Border Background="{DynamicResource BgBase}"
|
||||
CornerRadius="14"
|
||||
Padding="16,14">
|
||||
<Grid ColumnDefinitions="*,*" RowDefinitions="Auto,Auto,Auto">
|
||||
<StackPanel Grid.Column="0" Grid.Row="0" Spacing="3" Margin="0,0,0,14">
|
||||
<TextBlock Text="TYPE" Classes="label" />
|
||||
<TextBlock Text="{Binding SelectedAccount.Type}" FontSize="13" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Grid.Row="0" Spacing="3" Margin="0,0,0,14">
|
||||
<TextBlock Text="INSTITUTION" Classes="label" />
|
||||
<TextBlock Text="{Binding SelectedAccount.Institution}" FontSize="13" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="0" Grid.Row="1" Spacing="3" Margin="0,0,0,14">
|
||||
<TextBlock Text="ACCOUNT NO." Classes="label" />
|
||||
<TextBlock Text="{Binding SelectedAccount.Mask, Converter={StaticResource MaskToStringConverter}}" FontSize="13"
|
||||
FontWeight="SemiBold" Foreground="{DynamicResource TextPrimary}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Grid.Row="1" Spacing="3" Margin="0,0,0,14">
|
||||
<TextBlock Text="CURRENCY" Classes="label" />
|
||||
<TextBlock Text="{Binding SelectedAccount.Currency}" FontSize="13" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="0" Grid.Row="2" Spacing="3">
|
||||
<TextBlock Text="OPENED" Classes="label" />
|
||||
<TextBlock
|
||||
Text="{Binding SelectedAccount.OpenedAt, Converter={StaticResource DateFormatConverter}, ConverterParameter='MMM yyyy'}"
|
||||
FontSize="13" FontWeight="SemiBold" Foreground="{DynamicResource TextPrimary}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Grid.Row="2" Spacing="3">
|
||||
<TextBlock Text="TRANSACTIONS" Classes="label" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding SelectedAccount.TransactionsCount}" FontSize="13" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<TextBlock Text=" total" FontSize="13" FontWeight="SemiBold" Foreground="{DynamicResource TextPrimary}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Monthly flow -->
|
||||
<Border Background="{DynamicResource BgBase}" CornerRadius="14" Padding="16,14">
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock Text="This Month" FontSize="14" FontWeight="SemiBold" Foreground="{DynamicResource TextPrimary}" />
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<Border Grid.Column="0" Background="{DynamicResource IconBgGreen}" CornerRadius="8" Width="32" Height="32"
|
||||
Margin="0,0,12,0">
|
||||
<Svg Path="../Assets/Icons/arrow-down-left.svg" Width="14" Height="14" Css="{DynamicResource SvgGreen}" />
|
||||
</Border>
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center" Spacing="1">
|
||||
<TextBlock Text="Money In" FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="{Binding SelectedAccount.TotalIncomeThisMonth, StringFormat='$0.00'}" FontSize="14"
|
||||
FontWeight="SemiBold" Foreground="{DynamicResource AccentGreen}" />
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="2" Text="{Binding SelectedAccount.IncomeTransactionsThisMonth}" FontSize="11"
|
||||
Foreground="{DynamicResource TextDisabled}" VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<Border Grid.Column="0" Background="{DynamicResource IconBgRed}" CornerRadius="8" Width="32" Height="32"
|
||||
Margin="0,0,12,0">
|
||||
<Svg Path="../Assets/Icons/arrow-up-right.svg" Width="14" Height="14" Css="{DynamicResource SvgRed}" />
|
||||
</Border>
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center" Spacing="1">
|
||||
<TextBlock Text="Money Out" FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="{Binding SelectedAccount.TotalExpenseThisMonth, StringFormat='$0.00'}" FontSize="14"
|
||||
FontWeight="SemiBold" Foreground="{DynamicResource AccentRed}" />
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="2" Text="{Binding SelectedAccount.ExpenseTransactionsThisMonth}" FontSize="11"
|
||||
Foreground="{DynamicResource TextDisabled}" VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
<Separator />
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock Grid.Column="0" Text="Net" FontSize="13" FontWeight="SemiBold" Foreground="{DynamicResource TextMuted}"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Column="1" FontSize="14" FontWeight="Bold" Foreground="{DynamicResource AccentGreen}">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{StaticResource NetworthSumConverter}">
|
||||
<Binding Path="SelectedAccount.TotalIncomeThisMonth" />
|
||||
<Binding Path="SelectedAccount.TotalExpenseThisMonth" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Recent transactions -->
|
||||
<Border Background="{DynamicResource BgBase}" CornerRadius="14" Padding="16,14">
|
||||
<StackPanel Spacing="12">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock Grid.Column="0" Text="Recent Transactions" FontSize="14" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" VerticalAlignment="Center" />
|
||||
<Button Grid.Column="1" Background="Transparent" BorderThickness="0" Padding="0" Cursor="Hand"
|
||||
Command="{Binding ShowAccountTransactionsCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<TextBlock Text="View all" FontSize="12" Foreground="{DynamicResource AccentBlue}" VerticalAlignment="Center" />
|
||||
<Svg Path="../Assets/Icons/chevron-right.svg" Width="12" Height="12" Css="{DynamicResource SvgBlue}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
<ItemsControl ItemsSource="{Binding SelectedAccount.RecentTransactions}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Spacing="12" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="model:Transaction">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<Border Grid.Column="0" CornerRadius="8" Width="32" Height="32" Margin="0,0,12,0">
|
||||
<Border.Background>
|
||||
<SolidColorBrush
|
||||
Color="{Binding Category.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=color}"
|
||||
Opacity="0.15" />
|
||||
</Border.Background>
|
||||
<Svg Path="{Binding Category.Icon, Converter={StaticResource SvgPathFromName}}" Width="14" Height="14"
|
||||
Css="{Binding Category.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=css}" />
|
||||
</Border>
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center" Spacing="1">
|
||||
<TextBlock Text="{Binding Description}" FontSize="12" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<TextBlock
|
||||
Text="{Binding Date, Converter={StaticResource DateFormatConverter}, ConverterParameter='MMM d'}"
|
||||
FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="2" FontSize="12" FontWeight="SemiBold"
|
||||
Foreground="{Binding Type, Converter={StaticResource AmountColorConverter}}"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{StaticResource AmountSignConverter}">
|
||||
<Binding Path="Amount" />
|
||||
<Binding Path="Type" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Net worth share -->
|
||||
<Border Background="{DynamicResource BgBase}" CornerRadius="14" Padding="16,14">
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Text="Net Worth Share" FontSize="14" FontWeight="SemiBold" Foreground="{DynamicResource TextPrimary}" />
|
||||
<ProgressBar Classes="blue" Value="{Binding SelectedAccount.CurrentBalance}" Minimum="0" Maximum="{Binding TotalBalance}"
|
||||
Height="6" />
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock Grid.Column="0" Text="Share of total" FontSize="12" Foreground="{DynamicResource TextMuted}"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Column="1" FontSize="12" FontWeight="SemiBold" Foreground="{DynamicResource AccentBlue}">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{StaticResource PercentageConverter}">
|
||||
<Binding Path="SelectedAccount.CurrentBalance" />
|
||||
<Binding Path="TotalBalance" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Manage -->
|
||||
<Border Background="{DynamicResource BgBase}" CornerRadius="14" Padding="16,14">
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock Text="Manage" FontSize="14" FontWeight="SemiBold" Foreground="{DynamicResource TextPrimary}" Margin="0,0,0,2" />
|
||||
<Button Background="Transparent" BorderBrush="{DynamicResource BorderSubtle}" BorderThickness="1" CornerRadius="10"
|
||||
Padding="14,10" HorizontalAlignment="Stretch" HorizontalContentAlignment="Left">
|
||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||
<Svg Path="../Assets/Icons/archive.svg" Width="14" Height="14" Css="{DynamicResource SvgMuted}" />
|
||||
<StackPanel Spacing="1">
|
||||
<TextBlock Text="Archive Account" FontSize="12" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<TextBlock Text="Hide from active list, keep history" FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Background="#2A0D0D" BorderBrush="#3A1515" BorderThickness="1" CornerRadius="10" Padding="14,10"
|
||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Left">
|
||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||
<Svg Path="../Assets/Icons/trash-2.svg" Width="14" Height="14"
|
||||
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #FF5E5E; }" />
|
||||
<StackPanel Spacing="1">
|
||||
<TextBlock Text="Delete Account" FontSize="12" FontWeight="SemiBold" Foreground="#FF5E5E" />
|
||||
<TextBlock Text="Permanently removes all data" FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
118
Clario/MobileViews/AccountsViewMobile.axaml.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Animation.Easings;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
using Clario.Models;
|
||||
|
||||
namespace Clario.MobileViews;
|
||||
|
||||
public partial class AccountsViewMobile : UserControl
|
||||
{
|
||||
private bool _sheetVisible = false;
|
||||
|
||||
private TranslateTransform SheetTranslate =>
|
||||
(TranslateTransform)BottomSheet.RenderTransform!;
|
||||
|
||||
public AccountsViewMobile()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
DimOverlay.PointerPressed += async (_, _) => await HideSheet();
|
||||
CloseButton.Click += async (_, _) => await HideSheet();
|
||||
|
||||
AddHandler(Button.ClickEvent, async (sender, e) =>
|
||||
{
|
||||
if (e.Source is Button { DataContext: Account }) await ShowSheet();
|
||||
}, handledEventsToo: false);
|
||||
}
|
||||
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToVisualTree(e);
|
||||
BottomSheet.MaxHeight = Bounds.Height * 0.82;
|
||||
|
||||
// update if screen size changes
|
||||
PropertyChanged += (_, args) =>
|
||||
{
|
||||
if (args.Property == BoundsProperty)
|
||||
BottomSheet.MaxHeight = Bounds.Height * 0.82;
|
||||
};
|
||||
}
|
||||
|
||||
public async Task ShowSheet()
|
||||
{
|
||||
if (_sheetVisible) return;
|
||||
_sheetVisible = true;
|
||||
|
||||
OverlayGrid.IsVisible = true;
|
||||
DimOverlay.Opacity = 0;
|
||||
SheetTranslate.Y = 800;
|
||||
|
||||
var sheetAnim = new Animation
|
||||
{
|
||||
Duration = TimeSpan.FromMilliseconds(320),
|
||||
Easing = new CubicEaseOut(),
|
||||
FillMode = FillMode.Forward,
|
||||
Children =
|
||||
{
|
||||
new KeyFrame { Cue = new Cue(0d), Setters = { new Setter(TranslateTransform.YProperty, 800d) } },
|
||||
new KeyFrame { Cue = new Cue(1d), Setters = { new Setter(TranslateTransform.YProperty, 0d) } }
|
||||
}
|
||||
};
|
||||
|
||||
var dimAnim = new Animation
|
||||
{
|
||||
Duration = TimeSpan.FromMilliseconds(220),
|
||||
FillMode = FillMode.Forward,
|
||||
Children =
|
||||
{
|
||||
new KeyFrame { Cue = new Cue(0d), Setters = { new Setter(OpacityProperty, 0d) } },
|
||||
new KeyFrame { Cue = new Cue(1d), Setters = { new Setter(OpacityProperty, 1d) } }
|
||||
}
|
||||
};
|
||||
|
||||
await Task.WhenAll(sheetAnim.RunAsync(BottomSheet), dimAnim.RunAsync(DimOverlay));
|
||||
|
||||
SheetTranslate.Y = 0;
|
||||
DimOverlay.Opacity = 1;
|
||||
}
|
||||
|
||||
public async Task HideSheet()
|
||||
{
|
||||
if (!_sheetVisible) return;
|
||||
|
||||
var sheetAnim = new Animation
|
||||
{
|
||||
Duration = TimeSpan.FromMilliseconds(260),
|
||||
Easing = new CubicEaseIn(),
|
||||
FillMode = FillMode.Forward,
|
||||
Children =
|
||||
{
|
||||
new KeyFrame { Cue = new Cue(0d), Setters = { new Setter(TranslateTransform.YProperty, 0d) } },
|
||||
new KeyFrame { Cue = new Cue(1d), Setters = { new Setter(TranslateTransform.YProperty, 800d) } }
|
||||
}
|
||||
};
|
||||
|
||||
var dimAnim = new Animation
|
||||
{
|
||||
Duration = TimeSpan.FromMilliseconds(200),
|
||||
FillMode = FillMode.Forward,
|
||||
Children =
|
||||
{
|
||||
new KeyFrame { Cue = new Cue(0d), Setters = { new Setter(OpacityProperty, 1d) } },
|
||||
new KeyFrame { Cue = new Cue(1d), Setters = { new Setter(OpacityProperty, 0d) } }
|
||||
}
|
||||
};
|
||||
|
||||
await Task.WhenAll(sheetAnim.RunAsync(BottomSheet), dimAnim.RunAsync(DimOverlay));
|
||||
|
||||
_sheetVisible = false;
|
||||
OverlayGrid.IsVisible = false;
|
||||
SheetTranslate.Y = 0;
|
||||
DimOverlay.Opacity = 1;
|
||||
}
|
||||
}
|
||||
478
Clario/MobileViews/BudgetViewMobile.axaml
Normal file
@@ -0,0 +1,478 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:Clario.ViewModels"
|
||||
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
|
||||
xmlns:views="clr-namespace:Clario.Views"
|
||||
xmlns:model="clr-namespace:Clario.Models"
|
||||
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="800"
|
||||
x:Class="Clario.MobileViews.BudgetViewMobile"
|
||||
x:DataType="vm:BudgetViewModel"
|
||||
Classes="mobile">
|
||||
<Design.DataContext>
|
||||
<vm:BudgetViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Grid RowDefinitions="Auto,*"
|
||||
Background="{DynamicResource BgBase}">
|
||||
|
||||
<!-- ── Top bar ────────────────────────────── -->
|
||||
<Grid Grid.Row="0"
|
||||
ColumnDefinitions="*,Auto"
|
||||
Margin="16,16,16,12">
|
||||
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Text="{Binding CurrentPeriodFormatted}"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="Budget"
|
||||
FontSize="22"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
Margin="0,2,0,0" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Period navigator + add -->
|
||||
<StackPanel Grid.Column="1"
|
||||
Orientation="Horizontal"
|
||||
Spacing="8"
|
||||
VerticalAlignment="Center">
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Background="Transparent"
|
||||
Classes="nav"
|
||||
BorderThickness="0"
|
||||
Padding="8,8"
|
||||
Command="{Binding PreviousPeriodCommand}">
|
||||
<Svg Path="../Assets/Icons/chevron-left.svg"
|
||||
Width="14" Height="14"
|
||||
Css="{DynamicResource SvgMuted}" />
|
||||
</Button>
|
||||
<Button Background="Transparent"
|
||||
Classes="nav"
|
||||
BorderThickness="0"
|
||||
Padding="8,8"
|
||||
Command="{Binding NextPeriodCommand}">
|
||||
<Svg Path="../Assets/Icons/chevron-right.svg"
|
||||
Width="14" Height="14"
|
||||
Css="{DynamicResource SvgMuted}" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Button Classes="accented"
|
||||
Padding="10,8">
|
||||
<Svg Path="../Assets/Icons/plus.svg"
|
||||
Width="16" Height="16"
|
||||
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #0D0F14; }" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- ── Scrollable content ────────────────── -->
|
||||
<ScrollViewer Grid.Row="1"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="16,0,16,24" Spacing="14">
|
||||
|
||||
<!-- ── Period overview strip ─────────── -->
|
||||
<Grid ColumnDefinitions="*,*,*">
|
||||
|
||||
<!-- Budgeted -->
|
||||
<Border Grid.Column="0"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="12"
|
||||
Padding="12,10"
|
||||
Margin="0,0,4,0">
|
||||
<StackPanel Spacing="2">
|
||||
<TextBlock Text="Budgeted"
|
||||
FontSize="10"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="{Binding TotalBudgeted, StringFormat='$0'}"
|
||||
FontSize="13"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Spent -->
|
||||
<Border Grid.Column="1"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="12"
|
||||
Padding="12,10"
|
||||
Margin="4,0">
|
||||
<StackPanel Spacing="2">
|
||||
<TextBlock Text="Spent"
|
||||
FontSize="10"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="{Binding TotalSpent, StringFormat='$0'}"
|
||||
FontSize="13"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource AccentRed}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Remaining -->
|
||||
<Border Grid.Column="2"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="12"
|
||||
Padding="12,10"
|
||||
Margin="4,0,0,0">
|
||||
<StackPanel Spacing="2">
|
||||
<TextBlock Text="Left"
|
||||
FontSize="10"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="{Binding TotalLeftFormatted}"
|
||||
FontSize="13"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource AccentGreen}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- ── Overall progress bar ──────────── -->
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="16,14">
|
||||
<StackPanel Spacing="10">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="Overall Budget"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding SpentPercentageFormatted}"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
</Grid>
|
||||
<ProgressBar Classes="green"
|
||||
Value="{Binding TotalSpent}"
|
||||
Minimum="0"
|
||||
Maximum="{Binding TotalBudgeted}"
|
||||
Height="8" />
|
||||
<!-- Status summary -->
|
||||
<StackPanel Orientation="Horizontal" Spacing="12">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<Border Background="{DynamicResource IconBgGreen}" CornerRadius="4" Width="8" Height="8" VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding OnTrackCountFormatted}" FontSize="11" Foreground="{DynamicResource AccentGreen}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<Border Background="{DynamicResource BadgeBgYellow}" CornerRadius="4" Width="8" Height="8" VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding ApproachingCountFormatted}" FontSize="11" Foreground="{DynamicResource AccentYellow}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<Border Background="{DynamicResource BadgeBgRed}" CornerRadius="4" Width="8" Height="8" VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding OverBudgetCountFormatted}" FontSize="11" Foreground="{DynamicResource AccentRed}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ── Budget cards list ─────────────── -->
|
||||
<ItemsControl ItemsSource="{Binding VisibleBudgets}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Spacing="10" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="model:Budget">
|
||||
<Panel>
|
||||
<!-- Group header -->
|
||||
<TextBlock IsVisible="{Binding GroupHeader}"
|
||||
Text="{Binding Category.Name}"
|
||||
Classes="label"
|
||||
Margin="4,8,0,2" />
|
||||
|
||||
<!-- Budget card -->
|
||||
<Border IsVisible="{Binding !GroupHeader}"
|
||||
Classes.budget-card="{Binding IsOnTrack}"
|
||||
Classes.budget-card-warning="{Binding IsWarning}"
|
||||
Classes.budget-card-over="{Binding IsOverBudget}"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
CornerRadius="14"
|
||||
Padding="16">
|
||||
<StackPanel Spacing="12">
|
||||
|
||||
<!-- Header -->
|
||||
<Grid ColumnDefinitions="Auto,*,Auto,Auto">
|
||||
<Border Grid.Column="0"
|
||||
CornerRadius="10"
|
||||
Width="38" Height="38"
|
||||
Margin="0,0,12,0">
|
||||
<Border.Background>
|
||||
<SolidColorBrush
|
||||
Color="{Binding Category.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=color}"
|
||||
Opacity="0.15" />
|
||||
</Border.Background>
|
||||
<Svg Path="{Binding Category.Icon, Converter={StaticResource SvgPathFromName}}"
|
||||
Width="17" Height="17"
|
||||
Css="{Binding Category.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=css}" />
|
||||
</Border>
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center" Spacing="2">
|
||||
<TextBlock Text="{Binding Category.Name}"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding TransactionsCount}" FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text=" transactions" FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<!-- Spent / limit -->
|
||||
<StackPanel Grid.Column="2"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="2"
|
||||
Margin="0,0,10,0">
|
||||
<TextBlock Text="{Binding SpentFormatted}"
|
||||
FontSize="13"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
HorizontalAlignment="Right" />
|
||||
<TextBlock Text="{Binding AmountFormatted}"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource TextMuted}"
|
||||
HorizontalAlignment="Right" />
|
||||
</StackPanel>
|
||||
<!-- Menu -->
|
||||
<Button Grid.Column="3"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Padding="4"
|
||||
VerticalAlignment="Center">
|
||||
<Button.Flyout>
|
||||
<Flyout Placement="BottomEdgeAlignedRight"
|
||||
FlyoutPresenterTheme="{StaticResource TransparentFlyoutPresenter}">
|
||||
<views:BudgetCardMenuView />
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
<Svg Path="../Assets/Icons/ellipsis.svg"
|
||||
Width="15" Height="15"
|
||||
Css="{DynamicResource SvgMuted}" />
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<!-- Progress -->
|
||||
<StackPanel Spacing="6">
|
||||
<ProgressBar Classes.green="{Binding IsOnTrack}"
|
||||
Classes.yellow="{Binding IsWarning}"
|
||||
Classes.red="{Binding IsOverBudget}"
|
||||
Value="{Binding Spent}"
|
||||
Minimum="0"
|
||||
Maximum="{Binding LimitAmount}"
|
||||
Height="5" />
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<Border Grid.Column="0"
|
||||
Classes.badge-green="{Binding IsOnTrack}"
|
||||
Classes.badge-warning="{Binding IsWarning}"
|
||||
Classes.badge-over="{Binding IsOverBudget}"
|
||||
CornerRadius="20"
|
||||
Padding="6,2"
|
||||
HorizontalAlignment="Left">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<Svg Path="../Assets/Icons/triangle-alert.svg"
|
||||
Css="{DynamicResource SvgYellow}"
|
||||
IsVisible="{Binding IsWarning}"
|
||||
Height="11" VerticalAlignment="Center" />
|
||||
<Svg Path="../Assets/Icons/circle-alert.svg"
|
||||
Css="{DynamicResource SvgRed}"
|
||||
IsVisible="{Binding IsOverBudget}"
|
||||
Height="11" VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding PercentageFormatted}"
|
||||
FontSize="11"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding RemainingFormatted}"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource TextMuted}"
|
||||
VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<!-- ── Spending breakdown chart ──────── -->
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="16,14">
|
||||
<StackPanel Spacing="12">
|
||||
<TextBlock Text="Spending Breakdown"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<Border Height="130" ClipToBounds="True">
|
||||
<lvc:PieChart Series="{Binding SpendingBreakdownChartSeries}"
|
||||
Height="260"
|
||||
LegendPosition="Hidden"
|
||||
InitialRotation="-180"
|
||||
MaxAngle="180"
|
||||
FlowDirection="LeftToRight"
|
||||
VerticalAlignment="Top"
|
||||
Background="{DynamicResource BgSurface}" />
|
||||
</Border>
|
||||
<ItemsControl ItemsSource="{Binding SpendingBreakdownLegends}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel ItemSpacing="0" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="model:Budget">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4"
|
||||
IsVisible="{Binding !GroupHeader}"
|
||||
Margin="0,0,10,4">
|
||||
<Border Height="10" Width="10" CornerRadius="5"
|
||||
Background="{Binding Category.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=brush}" />
|
||||
<TextBlock Text="{Binding Category.Name}" FontSize="11" Foreground="{DynamicResource TextSecondary}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ── Period progress ───────────────── -->
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="16,14">
|
||||
<StackPanel Spacing="10">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<Border Grid.Column="0"
|
||||
Background="{DynamicResource IconBgBlue}"
|
||||
CornerRadius="8"
|
||||
Width="34" Height="34"
|
||||
Margin="0,0,12,0">
|
||||
<Svg Path="../Assets/Icons/calendar-days.svg"
|
||||
Width="16" Height="16"
|
||||
Css="{DynamicResource SvgBlue}" />
|
||||
</Border>
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center" Spacing="1">
|
||||
<TextBlock Text="Period Progress" FontSize="13" FontWeight="SemiBold" Foreground="{DynamicResource TextPrimary}" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding PeriodDaysPassed}" FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text=" of " FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="{Binding PeriodLength}" FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text=" days" FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding PeriodDaysLeftFormatted}"
|
||||
FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource AccentBlue}"
|
||||
VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
<ProgressBar Classes="blue"
|
||||
Value="{Binding PeriodDaysPassed}"
|
||||
Minimum="0"
|
||||
Maximum="{Binding PeriodLength}"
|
||||
Height="6" />
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<StackPanel Grid.Column="0" Spacing="1">
|
||||
<TextBlock Text="Daily budget left" FontSize="12" Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="Remaining ÷ days left" FontSize="10" Foreground="{DynamicResource TextDisabled}" />
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding DailyBudgetLeftFormatted}"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ── Savings goal ──────────────────── -->
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="16,14">
|
||||
<StackPanel Spacing="12">
|
||||
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="Savings Goal"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
VerticalAlignment="Center" />
|
||||
<Button Grid.Column="1"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Padding="4">
|
||||
<Svg Path="../Assets/Icons/pencil.svg" Width="14" Height="14" Css="{DynamicResource SvgMuted}" />
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Spacing="6">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock Grid.Column="0" Text="Monthly goal" FontSize="12" Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Grid.Column="1" Text="{Binding Profile.SavingsGoal, StringFormat='$0'}" FontSize="12" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
</Grid>
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock Grid.Column="0" Text="Projected savings" FontSize="12" Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Grid.Column="1" Text="{Binding TotalLeftFormatted}" FontSize="12" FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource AccentYellow}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
<ProgressBar Classes="yellow"
|
||||
Value="{Binding TotalLeft}"
|
||||
Minimum="0"
|
||||
Maximum="{Binding Profile.SavingsGoal}"
|
||||
Height="6" />
|
||||
|
||||
<Border Background="{DynamicResource BadgeBgYellow}"
|
||||
CornerRadius="10"
|
||||
Padding="12,8">
|
||||
<Grid ColumnDefinitions="Auto,*" ColumnSpacing="8">
|
||||
<Svg Grid.Column="0"
|
||||
Path="../Assets/Icons/info.svg"
|
||||
Width="14" Height="14"
|
||||
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #F5C842; }"
|
||||
VerticalAlignment="Top"
|
||||
Margin="0,1,0,0" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding SavingsHint}"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource AccentYellow}"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
13
Clario/MobileViews/BudgetViewMobile.axaml.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Clario.MobileViews;
|
||||
|
||||
public partial class BudgetViewMobile : UserControl
|
||||
{
|
||||
public BudgetViewMobile()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
480
Clario/MobileViews/DashboardViewMobile.axaml
Normal file
@@ -0,0 +1,480 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:Clario.ViewModels"
|
||||
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
|
||||
xmlns:model="clr-namespace:Clario.Models"
|
||||
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="800"
|
||||
x:DataType="vm:DashboardViewModel"
|
||||
x:Class="Clario.MobileViews.DashboardViewMobile">
|
||||
<Design.DataContext>
|
||||
<vm:DashboardViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Grid RowDefinitions="Auto,*"
|
||||
Background="{DynamicResource BgBase}">
|
||||
|
||||
<!-- ── Top bar ────────────────────────────── -->
|
||||
<Grid Grid.Row="0"
|
||||
ColumnDefinitions="*,Auto"
|
||||
Margin="16,16,16,12">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Text="Financial Overview"
|
||||
FontSize="22"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<TextBlock Classes="muted"
|
||||
Text="Friday, March 6, 2026"
|
||||
FontSize="12"
|
||||
Margin="0,2,0,0" />
|
||||
</StackPanel>
|
||||
<Button Grid.Column="1"
|
||||
Classes="accented"
|
||||
Padding="12,8"
|
||||
VerticalAlignment="Center">
|
||||
<Svg Path="../Assets/Icons/plus.svg"
|
||||
Width="16" Height="16"
|
||||
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #0D0F14; }" />
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<!-- ── Scrollable content ────────────────── -->
|
||||
<ScrollViewer Grid.Row="1"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="16,0,16,24" Spacing="14">
|
||||
|
||||
<!-- ── KPI cards ──────────────────────── -->
|
||||
<Grid ColumnDefinitions="*,*">
|
||||
|
||||
<!-- Income -->
|
||||
<Border Grid.Column="0"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="14,12"
|
||||
Margin="0,0,6,0">
|
||||
<StackPanel Spacing="8">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<Border Background="{DynamicResource IconBgGreen}"
|
||||
CornerRadius="{StaticResource RadiusIcon}"
|
||||
Padding="5">
|
||||
<Svg Path="../Assets/Icons/trending-up.svg"
|
||||
Height="12" Width="12"
|
||||
Css="{DynamicResource SvgGreen}" />
|
||||
</Border>
|
||||
<TextBlock Text="INCOME"
|
||||
Classes="label"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="{Binding MonthlyIncome, StringFormat='$0.00'}"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<Border Classes="badge-green" HorizontalAlignment="Left">
|
||||
<TextBlock Text="{Binding MonthlyIncomeChangeFormatted}"
|
||||
FontSize="10"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource AccentGreen}" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Expenses -->
|
||||
<Border Grid.Column="1"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="14,12"
|
||||
Margin="6,0,0,0">
|
||||
<StackPanel Spacing="8">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<Border Background="{DynamicResource IconBgOrange}"
|
||||
CornerRadius="{StaticResource RadiusIcon}"
|
||||
Padding="5">
|
||||
<Svg Path="../Assets/Icons/trending-down.svg"
|
||||
Height="12" Width="12"
|
||||
Css="{DynamicResource SvgRed}" />
|
||||
</Border>
|
||||
<TextBlock Text="EXPENSES"
|
||||
Classes="label"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="{Binding MonthlyExpenses, StringFormat='$0.00'}"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<Border Classes="badge-red" HorizontalAlignment="Left">
|
||||
<TextBlock Text="{Binding MonthlyExpenseChangeFormatted}"
|
||||
FontSize="10"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource AccentRed}" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- Savings rate full width -->
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="14,12">
|
||||
<StackPanel Spacing="8">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<Border Background="{DynamicResource IconBgPurple}"
|
||||
CornerRadius="{StaticResource RadiusIcon}"
|
||||
Padding="5">
|
||||
<Svg Path="../Assets/Icons/landmark.svg"
|
||||
Height="12" Width="12"
|
||||
Css="{DynamicResource SvgPurple}" />
|
||||
</Border>
|
||||
<TextBlock Text="SAVINGS RATE"
|
||||
Classes="label"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<ProgressBar Grid.Column="0"
|
||||
Classes="green"
|
||||
Minimum="0"
|
||||
Maximum="{Binding MonthlyIncome}"
|
||||
Value="{Binding MonthlyExpenses}"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Column="1"
|
||||
FontSize="15"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
Margin="12,0,0,0">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{StaticResource PercentageConverter}">
|
||||
<Binding Path="MonthlyExpenses" />
|
||||
<Binding Path="MonthlyIncome" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ── Spending by category chart ────── -->
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="14,14">
|
||||
<StackPanel Spacing="14">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Text="Spending by Category"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<TextBlock Classes="muted" Text="March 2026" FontSize="11" />
|
||||
</StackPanel>
|
||||
<ComboBox Grid.Column="1"
|
||||
SelectedIndex="0"
|
||||
ItemsSource="{Binding ChartTimePeriods}"
|
||||
SelectedItem="{Binding SelectedChartTimePeriod}"
|
||||
Background="{DynamicResource BgHover}"
|
||||
Foreground="{DynamicResource TextSecondary}"
|
||||
BorderBrush="{DynamicResource BorderAccent}"
|
||||
CornerRadius="{StaticResource RadiusIcon}"
|
||||
Padding="8,5"
|
||||
FontSize="12" />
|
||||
</Grid>
|
||||
|
||||
<lvc:CartesianChart Series="{Binding SpendingByCategoryChartSeries}"
|
||||
Height="180"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
LegendPosition="Hidden"
|
||||
TooltipPosition="Hidden">
|
||||
<lvc:CartesianChart.XAxes>
|
||||
<lvc:XamlAxis IsVisible="False" />
|
||||
</lvc:CartesianChart.XAxes>
|
||||
<lvc:CartesianChart.YAxes>
|
||||
<lvc:XamlLogarithmicAxis LogBase="10" IsVisible="False" MinLimit="1" />
|
||||
</lvc:CartesianChart.YAxes>
|
||||
</lvc:CartesianChart>
|
||||
|
||||
<!-- Category labels -->
|
||||
<ItemsControl ItemsSource="{Binding SpendingByCategoryChartData}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<UniformGrid Rows="1" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="model:ColumnChartData">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
HorizontalAlignment="Center"
|
||||
FontSize="10"
|
||||
Foreground="{DynamicResource TextDisabled}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<Border HorizontalAlignment="Stretch"
|
||||
Height="1"
|
||||
Background="{DynamicResource BorderSubtle}" />
|
||||
|
||||
<!-- Category amounts -->
|
||||
<ItemsControl ItemsSource="{Binding SpendingByCategoryChartData}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<UniformGrid Rows="1" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="model:ColumnChartData">
|
||||
<TextBlock Text="{Binding Values, Converter={StaticResource FirstValueConverter}, StringFormat='$0,00'}"
|
||||
HorizontalAlignment="Center"
|
||||
FontSize="10"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{Binding Fill, Converter={StaticResource SkPaintToBrushConverter}}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ── Recent transactions ───────────── -->
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="14,14">
|
||||
<StackPanel Spacing="14">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Text="Recent Transactions"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<TextBlock Classes="muted" Text="Last 5 transactions" FontSize="11" />
|
||||
</StackPanel>
|
||||
<Button Grid.Column="1"
|
||||
Background="Transparent"
|
||||
Foreground="{DynamicResource AccentBlue}"
|
||||
BorderThickness="0"
|
||||
FontSize="12"
|
||||
Padding="0"
|
||||
Content="View all →"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding ViewAllTransactionsCommand}" />
|
||||
</Grid>
|
||||
|
||||
<!-- Transaction rows -->
|
||||
<Border Background="{DynamicResource BorderSubtle}" CornerRadius="10">
|
||||
<ItemsControl ItemsSource="{Binding RecentTransactions}"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
CornerRadius="10">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Spacing="1" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="model:Transaction">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
Margin="12,10">
|
||||
<Border Grid.Column="0"
|
||||
CornerRadius="9"
|
||||
Width="36" Height="36"
|
||||
Margin="0,0,12,0">
|
||||
<Border.Background>
|
||||
<SolidColorBrush
|
||||
Color="{Binding Category.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=color}"
|
||||
Opacity="0.15" />
|
||||
</Border.Background>
|
||||
<Svg Path="{Binding Category.Icon, Converter={StaticResource SvgPathFromName}}"
|
||||
Height="16" Width="16"
|
||||
Css="{Binding Category.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=css}" />
|
||||
</Border>
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Description}"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextSecondary}" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<TextBlock Text="{Binding Category.Name}" Classes="muted" FontSize="11" />
|
||||
<TextBlock Text="·" Classes="muted" FontSize="11" />
|
||||
<TextBlock
|
||||
Text="{Binding Date, Converter={StaticResource DateFormatConverter}, ConverterParameter='MMM d'}"
|
||||
Classes="muted" FontSize="11" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="2"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{Binding Type, Converter={StaticResource AmountColorConverter}}"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{StaticResource AmountSignConverter}">
|
||||
<Binding Path="Amount" />
|
||||
<Binding Path="Type" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ── Budget tracker ────────────────── -->
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="14,14">
|
||||
<StackPanel Spacing="14">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Budget Tracker"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<TextBlock Classes="muted" Text="Monthly limits" FontSize="11" />
|
||||
</StackPanel>
|
||||
<ItemsControl ItemsSource="{Binding BudgetsTrackerData}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Spacing="14" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="model:Budget">
|
||||
<StackPanel Spacing="8">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="6">
|
||||
<Svg Path="{Binding Category.Icon, Converter={StaticResource SvgPathFromName}}"
|
||||
Height="13" Width="13"
|
||||
Css="{DynamicResource SvgSecondary}"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding Category.Name}"
|
||||
FontSize="13"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource TextSecondary}" />
|
||||
</StackPanel>
|
||||
<Panel Grid.Column="1">
|
||||
<StackPanel Orientation="Horizontal" IsVisible="{Binding !IsOverBudget}">
|
||||
<TextBlock Text="{Binding Spent, StringFormat='$0'}" FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text=" / " FontSize="11" Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="{Binding LimitAmount, StringFormat='$0'}" FontSize="11"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" IsVisible="{Binding IsOverBudget}">
|
||||
<TextBlock Text="{Binding Spent, StringFormat='$0'}" FontSize="11" Foreground="{DynamicResource AccentRed}" />
|
||||
<TextBlock Text=" / " FontSize="11" Foreground="{DynamicResource AccentRed}" />
|
||||
<TextBlock Text="{Binding LimitAmount, StringFormat='$0'}" FontSize="11"
|
||||
Foreground="{DynamicResource AccentRed}" />
|
||||
</StackPanel>
|
||||
</Panel>
|
||||
</Grid>
|
||||
<ProgressBar Classes.green="{Binding IsOnTrack}"
|
||||
Classes.yellow="{Binding IsWarning}"
|
||||
Classes.red="{Binding IsOverBudget}"
|
||||
Minimum="0"
|
||||
Value="{Binding Spent}"
|
||||
Maximum="{Binding LimitAmount}"
|
||||
Height="5" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ── Accounts summary ──────────────── -->
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14"
|
||||
Padding="14,14">
|
||||
<StackPanel Spacing="14">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Accounts"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<TextBlock Classes="muted" Text="{Binding AccountsSubtitle}" FontSize="11" />
|
||||
</StackPanel>
|
||||
|
||||
<Border Background="{DynamicResource BorderSubtle}" CornerRadius="10">
|
||||
<ItemsControl ItemsSource="{Binding AccountsSummaryData}"
|
||||
Background="{DynamicResource BgBase}"
|
||||
CornerRadius="10">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Spacing="1" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="model:Account">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto"
|
||||
Background="{DynamicResource BgBase}"
|
||||
Margin="12,10">
|
||||
<Border Grid.Column="0"
|
||||
CornerRadius="9"
|
||||
Width="34" Height="34"
|
||||
Margin="0,0,12,0">
|
||||
<Border.Background>
|
||||
<SolidColorBrush
|
||||
Color="{Binding Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=color}"
|
||||
Opacity="0.15" />
|
||||
</Border.Background>
|
||||
<Svg Path="{Binding Icon, Converter={StaticResource SvgPathFromName}}"
|
||||
Height="15" Width="15"
|
||||
Css="{Binding Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=css}" />
|
||||
</Border>
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextSecondary}" />
|
||||
<TextBlock Text="{Binding Mask, Converter={StaticResource MaskToStringConverter}}"
|
||||
FontSize="11"
|
||||
Classes="muted" />
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding CurrentBalance, StringFormat='$0'}"
|
||||
FontSize="13"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
VerticalAlignment="Center" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="Total Balance"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextMuted}"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding TotalNetworth, StringFormat=$0}"
|
||||
FontSize="17"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
13
Clario/MobileViews/DashboardViewMobile.axaml.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Clario.MobileViews;
|
||||
|
||||
public partial class DashboardViewMobile : UserControl
|
||||
{
|
||||
public DashboardViewMobile()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
11
Clario/MobileViews/MainAppMobile.axaml
Normal file
@@ -0,0 +1,11 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:views="clr-namespace:Clario.Views"
|
||||
xmlns:vm="clr-namespace:Clario.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Clario.Views.MainAppMobile"
|
||||
x:CompileBindings="False">
|
||||
<ContentControl Content="{Binding}" />
|
||||
</UserControl>
|
||||
11
Clario/MobileViews/MainAppMobile.axaml.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Clario.Views;
|
||||
|
||||
public partial class MainAppMobile : UserControl
|
||||
{
|
||||
public MainAppMobile()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
123
Clario/MobileViews/MainViewMobile.axaml
Normal file
@@ -0,0 +1,123 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:Clario.ViewModels"
|
||||
xmlns:views="clr-namespace:Clario.Views"
|
||||
xmlns:mobileViews="clr-namespace:Clario.MobileViews"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Clario.MobileViews.MainViewMobile"
|
||||
x:DataType="vm:MainViewModel"
|
||||
Classes="mobile"
|
||||
x:Name="MainControl">
|
||||
<Design.DataContext>
|
||||
<vm:MainViewModel />
|
||||
</Design.DataContext>
|
||||
<Grid RowDefinitions="*,Auto"
|
||||
Background="{DynamicResource BgBase}">
|
||||
<mobileViews:TransactionFormViewMobile Grid.Row="0" Grid.RowSpan="2" ZIndex="2"
|
||||
DataContext="{Binding TransactionFormViewModel}"
|
||||
IsVisible="{Binding DataContext.IsTransactionFormVisible,ElementName=MainControl}">
|
||||
</mobileViews:TransactionFormViewMobile>
|
||||
<!-- ── Content area ──────────────────────── -->
|
||||
<ContentControl Grid.Row="0"
|
||||
Content="{Binding CurrentView}" />
|
||||
|
||||
<!-- ── Bottom tab bar ────────────────────── -->
|
||||
<Border Grid.Row="1"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="0,1,0,0"
|
||||
Padding="8,10,8,14">
|
||||
<Grid ColumnDefinitions="*,*,*,*,*">
|
||||
|
||||
<!-- Dashboard -->
|
||||
<Button Grid.Column="0"
|
||||
Classes="nav"
|
||||
Classes.active="{Binding isOnDashboard}"
|
||||
Command="{Binding GoToDashboardCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
Padding="0,6">
|
||||
<StackPanel Spacing="4" HorizontalAlignment="Center">
|
||||
<Svg Path="../Assets/Icons/layout-dashboard.svg"
|
||||
Width="22" Height="22"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Home"
|
||||
FontSize="10"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<!-- Transactions -->
|
||||
<Button Grid.Column="1"
|
||||
Classes="nav"
|
||||
Classes.active="{Binding isOnTransactions}"
|
||||
Command="{Binding GoToTransactionsCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
Padding="0,6">
|
||||
<StackPanel Spacing="4" HorizontalAlignment="Center">
|
||||
<Svg Path="../Assets/Icons/arrow-right-left.svg"
|
||||
Width="22" Height="22"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Transactions"
|
||||
FontSize="10"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<!-- Add (center FAB-style) -->
|
||||
<Button Grid.Column="2"
|
||||
Classes="accented"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Width="52" Height="52"
|
||||
CornerRadius="26"
|
||||
Padding="0" Command="{Binding OpenAddTransactionCommand}">
|
||||
<Svg Path="../Assets/Icons/plus.svg"
|
||||
Width="22" Height="22"
|
||||
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #0D0F14; }" />
|
||||
</Button>
|
||||
|
||||
<!-- Accounts -->
|
||||
<Button Grid.Column="3"
|
||||
Classes="nav"
|
||||
Classes.active="{Binding isOnAccounts}"
|
||||
Command="{Binding GoToAccountsCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
Padding="0,6">
|
||||
<StackPanel Spacing="4" HorizontalAlignment="Center">
|
||||
<Svg Path="../Assets/Icons/chart-pie.svg"
|
||||
Width="22" Height="22"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Accounts"
|
||||
FontSize="10"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<!-- Budget -->
|
||||
<Button Grid.Column="4"
|
||||
Classes="nav"
|
||||
Classes.active="{Binding isOnBudget}"
|
||||
Command="{Binding GoToBudgetCommand}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
Padding="0,6">
|
||||
<StackPanel Spacing="4" HorizontalAlignment="Center">
|
||||
<Svg Path="../Assets/Icons/wallet.svg"
|
||||
Width="22" Height="22"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Budget"
|
||||
FontSize="10"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
11
Clario/MobileViews/MainViewMobile.axaml.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Clario.MobileViews;
|
||||
|
||||
public partial class MainViewMobile : UserControl
|
||||
{
|
||||
public MainViewMobile()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
440
Clario/MobileViews/TransactionFormViewMobile.axaml
Normal file
@@ -0,0 +1,440 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:Clario.ViewModels"
|
||||
xmlns:cc="clr-namespace:Clario.CustomControls"
|
||||
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="800"
|
||||
x:Class="Clario.MobileViews.TransactionFormViewMobile"
|
||||
x:DataType="vm:TransactionFormViewModel"
|
||||
Classes="mobile">
|
||||
<Design.DataContext>
|
||||
<vm:TransactionFormViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Grid RowDefinitions="Auto,*,Auto"
|
||||
Background="{DynamicResource BgBase}">
|
||||
|
||||
<!-- ── Top bar ────────────────────────────── -->
|
||||
<Grid Grid.Row="0"
|
||||
ColumnDefinitions="Auto,*,Auto"
|
||||
Margin="16,16,16,0">
|
||||
|
||||
<!-- Close -->
|
||||
<Button Grid.Column="0"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="20"
|
||||
Width="36" Height="36"
|
||||
Padding="0"
|
||||
HorizontalContentAlignment="Center"
|
||||
Command="{Binding CancelCommand}">
|
||||
<Svg Path="../Assets/Icons/x.svg"
|
||||
Width="14" Height="14"
|
||||
Css="{DynamicResource SvgMuted}" />
|
||||
</Button>
|
||||
|
||||
<!-- Title -->
|
||||
<StackPanel Grid.Column="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="1">
|
||||
<TextBlock Text="{Binding FormTitle}"
|
||||
FontSize="15"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="{Binding FormSubtitle}"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource TextMuted}"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Delete (edit mode only) -->
|
||||
<Button Grid.Column="2"
|
||||
Background="#1A0808"
|
||||
BorderBrush="#3A1515"
|
||||
BorderThickness="1"
|
||||
CornerRadius="20"
|
||||
Width="36" Height="36"
|
||||
Padding="0"
|
||||
HorizontalContentAlignment="Center"
|
||||
IsVisible="{Binding IsEditMode}"
|
||||
Command="{Binding RequestDeleteCommand}">
|
||||
<Svg Path="../Assets/Icons/trash-2.svg"
|
||||
Width="14" Height="14"
|
||||
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #FF5E5E; }" />
|
||||
</Button>
|
||||
|
||||
<!-- placeholder to keep title centered when not in edit mode -->
|
||||
<Border Grid.Column="2"
|
||||
Width="36"
|
||||
IsVisible="{Binding !IsEditMode}" />
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- ── Scrollable form ────────────────────── -->
|
||||
<ScrollViewer Grid.Row="1"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
Margin="0,16,0,0">
|
||||
<StackPanel Margin="16,0,16,16" Spacing="0">
|
||||
<TextBlock Text="TYPE" Classes="label" Margin="0,0,0,6" />
|
||||
<Border Background="{DynamicResource BgBase}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{DynamicResource RadiusControl}"
|
||||
Padding="3"
|
||||
Margin="0,0,0,20"
|
||||
Height="50">
|
||||
<Grid ColumnDefinitions="*,*">
|
||||
<!-- Expense -->
|
||||
<Button Grid.Column="0"
|
||||
Classes="nav"
|
||||
Classes.accented="{Binding IsExpense}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalAlignment="Stretch"
|
||||
CornerRadius="7"
|
||||
Padding="0,8"
|
||||
Focusable="False"
|
||||
Command="{Binding SetTypeCommand}"
|
||||
CommandParameter="expense">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<Svg Path="../Assets/Icons/arrow-up-right.svg"
|
||||
Width="16" Height="16" />
|
||||
<TextBlock Text="Expense"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<!-- Income -->
|
||||
<Button Grid.Column="1"
|
||||
Classes="nav"
|
||||
Classes.accented="{Binding IsIncome}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalAlignment="Stretch"
|
||||
CornerRadius="7"
|
||||
Padding="0,8"
|
||||
Focusable="False"
|
||||
Command="{Binding SetTypeCommand}"
|
||||
CommandParameter="income">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<Svg Path="../Assets/Icons/arrow-down-left.svg"
|
||||
Width="16" Height="16" />
|
||||
<TextBlock Text="Income"
|
||||
FontSize="16"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ── Amount ──────────────────────── -->
|
||||
<TextBlock Text="AMOUNT" Classes="label" FontSize="14" Margin="0,0,0,6" />
|
||||
<Border Background="{DynamicResource BgBase}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{DynamicResource RadiusControl}"
|
||||
Padding="14,0"
|
||||
Margin="0,0,0,16"
|
||||
Height="64">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="$"
|
||||
FontSize="32"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextMuted}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Padding="0 0 0 2" />
|
||||
<TextBox Grid.Column="1"
|
||||
Classes="ghost numeric"
|
||||
Text="{Binding Amount, Mode=TwoWay}"
|
||||
Watermark="0.00"
|
||||
FontSize="32"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
Height="54"
|
||||
Padding="0 0 0 2"
|
||||
VerticalContentAlignment="Center">
|
||||
</TextBox>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding Currency}"
|
||||
FontSize="18"
|
||||
Foreground="{DynamicResource TextDisabled}"
|
||||
VerticalAlignment="Center"
|
||||
Padding="0 0 0 2" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ── Description ─────────────────── -->
|
||||
<TextBlock Text="DESCRIPTION" Classes="label" FontSize="14" Margin="0,0,0,6" />
|
||||
<TextBox Text="{Binding Description, Mode=TwoWay}"
|
||||
Watermark="e.g. Grocery Shopping"
|
||||
FontSize="16"
|
||||
Height="48"
|
||||
Padding="12,0"
|
||||
VerticalContentAlignment="Center"
|
||||
Margin="0,0,0,16" />
|
||||
|
||||
<!-- ── Category + Account ──────────── -->
|
||||
<Grid ColumnDefinitions="*,14,*" Margin="0,0,0,16">
|
||||
|
||||
<!-- Category -->
|
||||
<StackPanel Grid.Column="0" Spacing="6">
|
||||
<TextBlock Text="CATEGORY" Classes="label" FontSize="14" />
|
||||
<Border Background="{DynamicResource BgBase}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{DynamicResource RadiusControl}">
|
||||
<Grid ColumnDefinitions="Auto,*" Height="42">
|
||||
<Border Grid.Column="0"
|
||||
CornerRadius="7"
|
||||
Width="36" Height="36"
|
||||
Margin="3,0"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
<Border.Background>
|
||||
<SolidColorBrush
|
||||
Color="{Binding SelectedCategory.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=color}"
|
||||
Opacity="0.15" />
|
||||
</Border.Background>
|
||||
<Svg Path="{Binding SelectedCategory.Icon, Converter={StaticResource SvgPathFromName}}"
|
||||
Width="14" Height="14"
|
||||
Css="{Binding SelectedCategory.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=css}" />
|
||||
</Border>
|
||||
<ComboBox Grid.Column="1"
|
||||
VerticalAlignment="Stretch"
|
||||
ItemsSource="{Binding Categories}"
|
||||
SelectedItem="{Binding SelectedCategory, Mode=TwoWay}"
|
||||
DisplayMemberBinding="{Binding Name}"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Padding="8,10"
|
||||
FontSize="13"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Account -->
|
||||
<StackPanel Grid.Column="2" Spacing="6">
|
||||
<TextBlock Text="ACCOUNT" Classes="label" FontSize="14" />
|
||||
<Border Background="{DynamicResource BgBase}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{DynamicResource RadiusControl}">
|
||||
<Grid ColumnDefinitions="Auto,*" Height="42">
|
||||
<Border Grid.Column="0"
|
||||
CornerRadius="7"
|
||||
Width="36" Height="36"
|
||||
Margin="3,0"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
<Border.Background>
|
||||
<SolidColorBrush
|
||||
Color="{Binding SelectedAccount.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=color}"
|
||||
Opacity="0.15" />
|
||||
</Border.Background>
|
||||
<Svg Path="{Binding SelectedAccount.Icon, Converter={StaticResource SvgPathFromName}}"
|
||||
Width="14" Height="14"
|
||||
Css="{Binding SelectedAccount.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=css}" />
|
||||
</Border>
|
||||
<ComboBox Grid.Column="1"
|
||||
VerticalAlignment="Stretch"
|
||||
ItemsSource="{Binding Accounts}"
|
||||
SelectedItem="{Binding SelectedAccount, Mode=TwoWay}"
|
||||
DisplayMemberBinding="{Binding Name}"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Padding="8,10"
|
||||
FontSize="13"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- ── Date ────────────────────────── -->
|
||||
<TextBlock Text="DATE" Classes="label" FontSize="14" Margin="0,0,0,6" />
|
||||
<Border Background="{DynamicResource BgBase}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{DynamicResource RadiusControl}"
|
||||
Margin="0,0,0,16">
|
||||
<Grid ColumnDefinitions="*,Auto" Height="42">
|
||||
<cc:DateRangePicker Grid.Column="0"
|
||||
Classes="ghost"
|
||||
SelectionMode="SingleDate"
|
||||
SelectedDates="{Binding Dates}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Padding="12,10" />
|
||||
<Button Grid.Column="1"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Padding="8,0"
|
||||
Cursor="Hand"
|
||||
CornerRadius="{DynamicResource RadiusControl}"
|
||||
Margin="1"
|
||||
VerticalAlignment="Stretch"
|
||||
VerticalContentAlignment="Center"
|
||||
Command="{Binding SetTodayCommand}">
|
||||
<TextBlock Text="Today"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource AccentBlue}" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ── Note ────────────────────────── -->
|
||||
<TextBlock Text="NOTE (OPTIONAL)" Classes="label" FontSize="14" Margin="0,0,0,6" />
|
||||
<TextBox Text="{Binding Note, Mode=TwoWay}"
|
||||
Watermark="Add a note..."
|
||||
FontSize="16"
|
||||
Height="42"
|
||||
Padding="12,0"
|
||||
VerticalContentAlignment="Center"
|
||||
Margin="0,0,0,8" />
|
||||
|
||||
<!-- ── Validation error ─────────────── -->
|
||||
<Border Background="{DynamicResource BadgeBgRed}"
|
||||
BorderBrush="{DynamicResource AccentRed}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Padding="12,8"
|
||||
Margin="0,8,0,16"
|
||||
IsVisible="{Binding HasError}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Svg Path="../Assets/Icons/circle-alert.svg"
|
||||
Width="13" Height="13"
|
||||
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #FF5E5E; }" />
|
||||
<TextBlock Text="{Binding ErrorMessage}"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource AccentRed}"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- ── Bottom action bar ──────────────────── -->
|
||||
<Border Grid.Row="2"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="0,1,0,0"
|
||||
Padding="16,12,16,20">
|
||||
<Grid ColumnDefinitions="*,*">
|
||||
<Button Grid.Column="0"
|
||||
Classes="base"
|
||||
Margin="0,0,6,0"
|
||||
Padding="0,13"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
FontSize="14"
|
||||
Content="Cancel"
|
||||
Command="{Binding CancelCommand}" />
|
||||
<Button Grid.Column="1"
|
||||
Classes="accented"
|
||||
Margin="6,0,0,0"
|
||||
Padding="0,13"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
IsEnabled="{Binding IsValid}"
|
||||
Command="{Binding SaveCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Svg Path="../Assets/Icons/check.svg"
|
||||
Width="14" Height="14"
|
||||
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #0D0F14; }" />
|
||||
<TextBlock Text="{Binding SaveButtonLabel}"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource BgBase}"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Grid Grid.Row="0" Grid.RowSpan="3" IsVisible="{Binding ShowDeleteConfirm}">
|
||||
<Border Background="#50000000" />
|
||||
<Border HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource AccentRed}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="18"
|
||||
Padding="28"
|
||||
Width="340"
|
||||
BoxShadow="0 24 72 0 #60000000">
|
||||
<StackPanel Spacing="0">
|
||||
|
||||
<!-- Icon -->
|
||||
<Border Background="#2A0D0D"
|
||||
CornerRadius="14"
|
||||
Width="52" Height="52"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,0,0,16">
|
||||
<Svg Path="../Assets/Icons/trash-2.svg"
|
||||
Width="22" Height="22"
|
||||
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #FF5E5E; }" />
|
||||
</Border>
|
||||
|
||||
<!-- Title -->
|
||||
<TextBlock Text="Delete Transaction"
|
||||
FontSize="16"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,0,0,8" />
|
||||
|
||||
<!-- Description -->
|
||||
<TextBlock Text="This action cannot be undone. The transaction will be permanently removed from your records."
|
||||
FontSize="13"
|
||||
Foreground="{DynamicResource TextMuted}"
|
||||
TextWrapping="Wrap"
|
||||
TextAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,0,0,24" />
|
||||
|
||||
<!-- Actions -->
|
||||
<UniformGrid Rows="1">
|
||||
<Button Classes="base"
|
||||
Margin="0,0,6,0"
|
||||
Padding="0,11"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
FontSize="13"
|
||||
Content="Cancel"
|
||||
Command="{Binding CancelDeleteCommand}" />
|
||||
<Button Margin="6,0,0,0"
|
||||
Padding="0,11"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
Background="#FF5E5E"
|
||||
BorderThickness="0"
|
||||
CornerRadius="{DynamicResource RadiusControl}"
|
||||
Command="{Binding ConfirmDeleteCommand}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Svg Path="../Assets/Icons/trash-2.svg"
|
||||
Width="13" Height="13"
|
||||
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #FFFFFF; }" />
|
||||
<TextBlock Text="Delete"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#FFFFFF"
|
||||
VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</UniformGrid>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
13
Clario/MobileViews/TransactionFormViewMobile.axaml.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Clario.MobileViews;
|
||||
|
||||
public partial class TransactionFormViewMobile : UserControl
|
||||
{
|
||||
public TransactionFormViewMobile()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
356
Clario/MobileViews/TransactionsViewMobile.axaml
Normal file
@@ -0,0 +1,356 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="clr-namespace:Clario.Models"
|
||||
xmlns:vm="clr-namespace:Clario.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Clario.MobileViews.TransactionsViewMobile"
|
||||
x:DataType="vm:TransactionsViewModel"
|
||||
Classes="mobile">
|
||||
<Grid RowDefinitions="Auto,Auto,*,Auto"
|
||||
Background="{DynamicResource BgBase}">
|
||||
|
||||
<!-- ── Top Bar ───────────────────────────── -->
|
||||
<Grid Grid.Row="0"
|
||||
ColumnDefinitions="*,Auto"
|
||||
Margin="16,16,16,0">
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Text="Transactions"
|
||||
FontSize="22"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
</StackPanel>
|
||||
<!-- Filter button -->
|
||||
<Button Grid.Column="1"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Padding="10,8"
|
||||
Cursor="Hand">
|
||||
<Button.Flyout>
|
||||
<Flyout Placement="BottomEdgeAlignedRight"
|
||||
FlyoutPresenterTheme="{StaticResource TransparentFlyoutPresenter}">
|
||||
<Border Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="16"
|
||||
Padding="20"
|
||||
Width="300"
|
||||
BoxShadow="0 8 32 0 #3C000000">
|
||||
<StackPanel Spacing="0">
|
||||
|
||||
<TextBlock Text="FILTERS"
|
||||
Classes="label"
|
||||
Margin="0,0,0,14" />
|
||||
|
||||
<!-- Search -->
|
||||
<TextBox Watermark="Search transactions..."
|
||||
Text="{Binding SearchText}"
|
||||
FontSize="13"
|
||||
Height="38"
|
||||
Padding="12,0"
|
||||
VerticalContentAlignment="Center"
|
||||
Margin="0,0,0,14" />
|
||||
|
||||
<!-- Date range -->
|
||||
<TextBlock Classes="label" Text="DATE RANGE" Margin="0,0,0,6" />
|
||||
<ComboBox HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding DateRangeOptions}"
|
||||
SelectedItem="{Binding SelectedDateRangeOption}"
|
||||
Padding="10,8"
|
||||
FontSize="13"
|
||||
Margin="0,0,0,14" />
|
||||
|
||||
<!-- Type toggle -->
|
||||
<TextBlock Classes="label" Text="TYPE" Margin="0,0,0,6" />
|
||||
<Border Background="{DynamicResource BgBase}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{DynamicResource RadiusControl}"
|
||||
Padding="3"
|
||||
Margin="0,0,0,14">
|
||||
<Grid ColumnDefinitions="*,*,*">
|
||||
<Button Grid.Column="0"
|
||||
Classes="nav"
|
||||
Classes.accented="{Binding FilterTypeAll}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
Focusable="False"
|
||||
CornerRadius="7"
|
||||
Padding="0,6"
|
||||
Command="{Binding SetTransactionTypeCommand}"
|
||||
CommandParameter="all">
|
||||
<TextBlock Text="All" FontSize="12" FontWeight="SemiBold" HorizontalAlignment="Center" />
|
||||
</Button>
|
||||
<Button Grid.Column="1"
|
||||
Classes="nav"
|
||||
Classes.accented="{Binding FilterTypeIncome}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
Focusable="False"
|
||||
CornerRadius="7"
|
||||
Padding="0,6"
|
||||
Command="{Binding SetTransactionTypeCommand}"
|
||||
CommandParameter="income">
|
||||
<TextBlock Text="Income" FontSize="12" HorizontalAlignment="Center" />
|
||||
</Button>
|
||||
<Button Grid.Column="2"
|
||||
Classes="nav"
|
||||
Classes.accented="{Binding FilterTypeExpense}"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
Focusable="False"
|
||||
CornerRadius="7"
|
||||
Padding="0,6"
|
||||
Command="{Binding SetTransactionTypeCommand}"
|
||||
CommandParameter="expense">
|
||||
<TextBlock Text="Expense" FontSize="12" HorizontalAlignment="Center" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Category -->
|
||||
<TextBlock Classes="label" Text="CATEGORY" Margin="0,0,0,6" />
|
||||
<ComboBox HorizontalAlignment="Stretch"
|
||||
SelectedItem="{Binding SelectedCategory}"
|
||||
ItemsSource="{Binding Categories}"
|
||||
DisplayMemberBinding="{Binding Name}"
|
||||
Padding="10,8"
|
||||
FontSize="13"
|
||||
Margin="0,0,0,14" />
|
||||
|
||||
<!-- Account -->
|
||||
<TextBlock Classes="label" Text="ACCOUNT" Margin="0,0,0,6" />
|
||||
<ComboBox HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Accounts}"
|
||||
SelectedItem="{Binding SelectedAccount}"
|
||||
DisplayMemberBinding="{Binding Name}"
|
||||
Padding="10,8"
|
||||
FontSize="13"
|
||||
Margin="0,0,0,14" />
|
||||
|
||||
<!-- Sort -->
|
||||
<TextBlock Classes="label" Text="SORT BY" Margin="0,0,0,6" />
|
||||
<ComboBox HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding SortOptions}"
|
||||
SelectedItem="{Binding SelectedSortOption}"
|
||||
Padding="10,8"
|
||||
FontSize="13"
|
||||
Margin="0,0,0,16" />
|
||||
|
||||
<!-- Actions -->
|
||||
<Grid ColumnDefinitions="*,*">
|
||||
<Button Grid.Column="0"
|
||||
Classes="base"
|
||||
Margin="0,0,6,0"
|
||||
Padding="0,10"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
FontSize="13"
|
||||
Command="{Binding ResetFiltersCommand}"
|
||||
Content="Reset" />
|
||||
<Button Grid.Column="1"
|
||||
Classes="accented"
|
||||
Margin="6,0,0,0"
|
||||
Padding="0,10"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Center"
|
||||
Command="{Binding ApplyFiltersCommand}">
|
||||
<TextBlock Text="Apply"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource BgBase}"
|
||||
HorizontalAlignment="Center" />
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
<Svg Path="../Assets/Icons/sliders-horizontal.svg"
|
||||
Width="16" Height="16"
|
||||
Css="{DynamicResource SvgSecondary}" />
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<!-- ── Summary strip ─────────────────────── -->
|
||||
<Grid Grid.Row="1"
|
||||
ColumnDefinitions="*,*,*"
|
||||
Margin="16,12,16,0">
|
||||
|
||||
<!-- Income -->
|
||||
<Border Grid.Column="0"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="12"
|
||||
Padding="12,10"
|
||||
Margin="0,0,4,0">
|
||||
<StackPanel Spacing="2">
|
||||
<TextBlock Text="Income"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="{Binding TotalIncome, StringFormat='$0.00'}"
|
||||
FontSize="13"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource AccentGreen}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Expenses -->
|
||||
<Border Grid.Column="1"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="12"
|
||||
Padding="12,10"
|
||||
Margin="4,0">
|
||||
<StackPanel Spacing="2">
|
||||
<TextBlock Text="Expenses"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="{Binding TotalExpenses, StringFormat='$0.00'}"
|
||||
FontSize="13"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource AccentRed}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Net -->
|
||||
<Border Grid.Column="2"
|
||||
Background="{DynamicResource BgSurface}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="12"
|
||||
Padding="12,10"
|
||||
Margin="4,0,0,0">
|
||||
<StackPanel Spacing="2">
|
||||
<TextBlock Text="Net"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock FontSize="13"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource AccentBlue}">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{StaticResource NetworthSumConverter}">
|
||||
<Binding Path="TotalIncome" />
|
||||
<Binding Path="TotalExpenses" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- ── Transaction list ──────────────────── -->
|
||||
<ScrollViewer Grid.Row="2"
|
||||
Margin="0,12,0,0"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel>
|
||||
<ItemsControl ItemsSource="{Binding FilteredTransactions}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="model:Transaction">
|
||||
<Panel>
|
||||
|
||||
<!-- Date group header -->
|
||||
<Border Padding="16,14,16,6"
|
||||
IsVisible="{Binding GroupHeader}">
|
||||
<TextBlock Text="{Binding Description}"
|
||||
Classes="label" />
|
||||
</Border>
|
||||
|
||||
<!-- Transaction row -->
|
||||
<Border Padding="16,12"
|
||||
IsVisible="{Binding !GroupHeader}"
|
||||
BorderBrush="{DynamicResource BorderSubtle}"
|
||||
BorderThickness="0,1,0,0">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
|
||||
<!-- Icon -->
|
||||
<Border Grid.Column="0"
|
||||
CornerRadius="{DynamicResource RadiusIcon}"
|
||||
Width="38" Height="38"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,12,0">
|
||||
<Border.Background>
|
||||
<SolidColorBrush
|
||||
Color="{Binding Category.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=color}"
|
||||
Opacity="0.15" />
|
||||
</Border.Background>
|
||||
<Svg Path="{Binding Category.Icon, Converter={StaticResource SvgPathFromName}}"
|
||||
Width="17" Height="17"
|
||||
Css="{Binding Category.Color, Converter={StaticResource HexToColorConverter}, ConverterParameter=css}" />
|
||||
</Border>
|
||||
|
||||
<!-- Description + meta -->
|
||||
<StackPanel Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="2">
|
||||
<TextBlock Text="{Binding Description}"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<TextBlock Text="{Binding Category.Name}"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
<TextBlock Text="·"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource TextDisabled}" />
|
||||
<TextBlock Text="{Binding Date, Converter={StaticResource DateFormatConverter}}"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource TextMuted}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Amount -->
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding Amount, StringFormat='$0.00'}"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{Binding Type, Converter={StaticResource AmountColorConverter}}"
|
||||
VerticalAlignment="Center" />
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<!-- Empty state -->
|
||||
<StackPanel HorizontalAlignment="Center"
|
||||
Spacing="12"
|
||||
Margin="0,60"
|
||||
IsVisible="{Binding HasNoTransactions}">
|
||||
<Svg Path="../Assets/Icons/search.svg"
|
||||
Css="{DynamicResource SvgMuted}"
|
||||
Height="36" Width="36"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="No transactions found"
|
||||
FontSize="15"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource TextPrimary}"
|
||||
HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Try adjusting your filters."
|
||||
FontSize="13"
|
||||
Foreground="{DynamicResource TextMuted}"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
11
Clario/MobileViews/TransactionsViewMobile.axaml.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Clario.MobileViews;
|
||||
|
||||
public partial class TransactionsViewMobile : UserControl
|
||||
{
|
||||
public TransactionsViewMobile()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using Supabase.Postgrest.Attributes;
|
||||
using Supabase.Postgrest.Models;
|
||||
|
||||
@@ -23,7 +24,7 @@ public class Account : BaseModel
|
||||
[Column("currency")] public string Currency { get; set; } = "USD";
|
||||
|
||||
[Column("opening_balance")] public decimal OpeningBalance { get; set; }
|
||||
public decimal CurrentBalance { get; set; }
|
||||
[JsonIgnore] public decimal CurrentBalance { get; set; }
|
||||
|
||||
[Column("credit_limit")] public decimal? CreditLimit { get; set; }
|
||||
|
||||
@@ -36,13 +37,13 @@ public class Account : BaseModel
|
||||
[Column("icon")] public string Icon { get; set; } = string.Empty;
|
||||
|
||||
[Column("color")] public string Color { get; set; } = string.Empty;
|
||||
|
||||
public int TransactionsCount { get; set; }
|
||||
public int IncomeTransactionsThisMonth { get; set; }
|
||||
public int ExpenseTransactionsThisMonth { get; set; }
|
||||
public decimal TotalIncomeThisMonth { get; set; }
|
||||
public decimal TotalExpenseThisMonth { get; set; }
|
||||
public decimal MonthlyIncrease { get; set; }
|
||||
public List<Transaction>? RecentTransactions { get; set; }
|
||||
public bool GroupHeader { get; set; } = false;
|
||||
|
||||
[JsonIgnore] public int TransactionsCount { get; set; }
|
||||
[JsonIgnore] public int IncomeTransactionsThisMonth { get; set; }
|
||||
[JsonIgnore] public int ExpenseTransactionsThisMonth { get; set; }
|
||||
[JsonIgnore] public decimal TotalIncomeThisMonth { get; set; }
|
||||
[JsonIgnore] public decimal TotalExpenseThisMonth { get; set; }
|
||||
[JsonIgnore] public decimal MonthlyIncrease { get; set; }
|
||||
[JsonIgnore] public List<Transaction>? RecentTransactions { get; set; }
|
||||
[JsonIgnore] public bool GroupHeader { get; set; } = false;
|
||||
}
|
||||
50
Clario/Models/Budget.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Supabase.Postgrest.Attributes;
|
||||
using Supabase.Postgrest.Models;
|
||||
|
||||
|
||||
namespace Clario.Models;
|
||||
|
||||
[Table("budgets")]
|
||||
public class Budget : BaseModel
|
||||
{
|
||||
[PrimaryKey("id", false)] public Guid Id { get; set; }
|
||||
|
||||
[Column("user_id")] public Guid UserId { get; set; }
|
||||
|
||||
[Column("category_id")] public Guid CategoryId { get; set; }
|
||||
|
||||
[Column("amount")] public decimal LimitAmount { get; set; }
|
||||
|
||||
[Column("period")] public string Period { get; set; } = "monthly";
|
||||
|
||||
[Column("alert_threshold")] public int AlertThreshold { get; set; } = 80;
|
||||
|
||||
[Column("rollover")] public bool Rollover { get; set; }
|
||||
|
||||
[Column("created_at")] public DateTime CreatedAt { get; set; }
|
||||
|
||||
// ── not in DB ──────────────────────────────────────
|
||||
|
||||
[JsonIgnore] public Category? Category { get; set; }
|
||||
[JsonIgnore] public int TransactionsCount { get; set; }
|
||||
[JsonIgnore] public decimal Spent { get; set; } // populated after joining with transactions
|
||||
|
||||
[JsonIgnore] public decimal Remaining => LimitAmount - Spent;
|
||||
[JsonIgnore] public double PercentageUsed => LimitAmount > 0 ? Math.Round((double)(Spent / LimitAmount), 2) : 0;
|
||||
[JsonIgnore] public bool IsOverBudget => Spent > LimitAmount;
|
||||
[JsonIgnore] public bool IsWarning => !IsOverBudget && PercentageUsed * 100 >= AlertThreshold;
|
||||
[JsonIgnore] public bool IsOnTrack => !IsOverBudget && PercentageUsed * 100 < AlertThreshold;
|
||||
|
||||
[JsonIgnore] public string SpentFormatted => $"${Spent:N0}";
|
||||
[JsonIgnore] public string AmountFormatted => $"of ${LimitAmount:N0}";
|
||||
[JsonIgnore] public string PercentageFormatted => $"{PercentageUsed:P0} used";
|
||||
|
||||
[JsonIgnore]
|
||||
public string RemainingFormatted => IsOverBudget
|
||||
? $"${Math.Abs(Remaining):N0} over"
|
||||
: $"${Remaining:N0} left";
|
||||
|
||||
[JsonIgnore] public bool GroupHeader { get; set; } = false;
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Supabase.Postgrest.Attributes;
|
||||
using Supabase.Postgrest.Models;
|
||||
|
||||
|
||||
18
Clario/Models/ColumnChartData.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using LiveChartsCore.Kernel;
|
||||
using LiveChartsCore.SkiaSharpView.Painting;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Clario.Models;
|
||||
|
||||
public partial class ColumnChartData : ObservableObject
|
||||
{
|
||||
public Guid id;
|
||||
[ObservableProperty] private string _name;
|
||||
[ObservableProperty] private double[] _values;
|
||||
[ObservableProperty] private SolidColorPaint _fill;
|
||||
|
||||
|
||||
[JsonIgnore] public Func<ChartPoint, string> ToolTipFormatter => point => $"${point.Coordinate.PrimaryValue:N0}";
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using ExCSS;
|
||||
using Supabase.Postgrest.Attributes;
|
||||
using Supabase.Postgrest.Models;
|
||||
|
||||
@@ -14,6 +13,7 @@ public class Profile : BaseModel
|
||||
[Column("currency")] public string Currency { get; set; }
|
||||
[Column("theme")] public string Theme { get; set; }
|
||||
[Column("language")] public string Language { get; set; }
|
||||
[Column("savings_goal")] public decimal? SavingsGoal { get; set; }
|
||||
[Column("created_at")] public DateTime CreatedAt { get; set; }
|
||||
[Column("updated_at")] public DateTime UpdatedAt { get; set; }
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Clario.Data;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Newtonsoft.Json;
|
||||
using Supabase.Postgrest.Attributes;
|
||||
using Supabase.Postgrest.Models;
|
||||
|
||||
@@ -26,11 +26,12 @@ public class Transaction : BaseModel
|
||||
{
|
||||
_categoryId = value;
|
||||
|
||||
Category = DataRepo.General.Categories?.FirstOrDefault(x => x.Id == value);
|
||||
Category = DataRepo.General.FetchCategories().Result.FirstOrDefault(x => x.Id == value);
|
||||
}
|
||||
}
|
||||
|
||||
public Category? Category { get; set; }
|
||||
[JsonIgnore] public Category? Category { get; set; }
|
||||
|
||||
[Column("amount")] public decimal Amount { get; set; }
|
||||
|
||||
[Column("type")] public string Type { get; set; } = string.Empty; // "income" or "expense"
|
||||
@@ -40,8 +41,8 @@ public class Transaction : BaseModel
|
||||
[Column("note")] public string? Note { get; set; }
|
||||
|
||||
[Column("date")] public DateTime Date { get; set; }
|
||||
|
||||
|
||||
[Column("created_at")] public DateTime CreatedAt { get; set; }
|
||||
|
||||
public bool GroupHeader { get; set; } = false;
|
||||
[JsonIgnore] public bool GroupHeader { get; set; } = false;
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using Avalonia;
|
||||
using Avalonia;
|
||||
using Avalonia.Styling;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Clario.Services;
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
<StyleInclude Source="Styles/ToggleSwitchStyles.axaml" />
|
||||
<StyleInclude Source="Styles/CalenderItemStyles.axaml" />
|
||||
<!-- <StyleInclude Source="Styles/CalenderItemStyles.axaml" /> -->
|
||||
<StyleInclude Source="Styles/CalendarStyles.axaml" />
|
||||
<StyleInclude Source="../CustomControls/DateRangePicker.axaml" />
|
||||
<Styles.Resources>
|
||||
<ResourceDictionary>
|
||||
@@ -87,7 +88,6 @@
|
||||
|
||||
<!-- ACCENTS -->
|
||||
<SolidColorBrush x:Key="AccentBlue" Color="#7B9CFF" />
|
||||
|
||||
<SolidColorBrush x:Key="AccentGreen" Color="#2ECC8A" />
|
||||
<SolidColorBrush x:Key="AccentYellow" Color="#F5C842" />
|
||||
<SolidColorBrush x:Key="AccentRed" Color="#FF5E5E" />
|
||||
@@ -306,18 +306,21 @@
|
||||
<Setter Property="Background" Value="{DynamicResource BadgeBgGreen}" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusPill}" />
|
||||
<Setter Property="Padding" Value="{DynamicResource BadgePadding}" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource AccentGreen}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Border.badge-red">
|
||||
<Setter Property="Background" Value="{DynamicResource BadgeBgRed}" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusPill}" />
|
||||
<Setter Property="Padding" Value="{DynamicResource BadgePadding}" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource AccentRed}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Border.badge-yellow">
|
||||
<Setter Property="Background" Value="{DynamicResource BadgeBgYellow}" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusPill}" />
|
||||
<Setter Property="Padding" Value="{DynamicResource BadgePadding}" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource AccentYellow}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Border.badge-blue">
|
||||
@@ -463,8 +466,8 @@
|
||||
|
||||
<Style Selector="Button.nav">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextDisabled}" />
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgDisabled}" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextMuted}" />
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgMuted}" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Padding" Value="{DynamicResource NavButtonPadding}" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusControl}" />
|
||||
@@ -487,8 +490,40 @@
|
||||
|
||||
<Style Selector="Button.nav:disabled /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextDisabled}" />
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgDisabled}" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextMuted}" />
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgMuted}" />
|
||||
<Setter Property="Opacity" Value="0.4" />
|
||||
</Style>
|
||||
|
||||
|
||||
<Style Selector=".mobile Button.nav">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextMuted}" />
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgMuted}" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Padding" Value="{DynamicResource NavButtonPadding}" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusControl}" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
<Setter Property="FocusAdorner" Value="{x:Null}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector=".mobile Button.nav:pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource BgHover}" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextSecondary}" />
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgSecondary}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector=".mobile Button.nav:pressed /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource BgHover}" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextPrimary}" />
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgPrimary}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector=".mobile Button.nav:disabled /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextMuted}" />
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgMuted}" />
|
||||
<Setter Property="Opacity" Value="0.4" />
|
||||
</Style>
|
||||
|
||||
@@ -513,12 +548,24 @@
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgBlue}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector=".mobile Button.nav:pressed /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextDisabled}" />
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgDisabled}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector=".mobile Button.nav:pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextDisabled}" />
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgDisabled}" />
|
||||
</Style>
|
||||
|
||||
<!-- ACCENTED BUTTON -->
|
||||
|
||||
<Style Selector="Button.accented">
|
||||
<Setter Property="Background" Value="{DynamicResource AccentBlue}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource BgBase}" />
|
||||
<Setter Property="Svg.Css" Value="{DynamicResource SvgBase}" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource FontSizeBody}" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusControl}" />
|
||||
@@ -559,11 +606,15 @@
|
||||
|
||||
<Style Selector="Button.base:pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource BgHover}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource BorderSubtle}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource TextPrimary}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Button.base:pressed /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource BorderSubtle}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource BorderSubtle}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Button.base:disabled /template/ ContentPresenter">
|
||||
@@ -578,6 +629,19 @@
|
||||
</Style>
|
||||
|
||||
|
||||
<Style Selector="Border.editable Button.reveal">
|
||||
<Setter Property="IsVisible" Value="False" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusSmall}" />
|
||||
</Style>
|
||||
<Style Selector="Border.editable:pointerover Button.reveal">
|
||||
<Setter Property="IsVisible" Value="True" />
|
||||
</Style>
|
||||
<Style Selector="Border.editable Svg.hide">
|
||||
<Setter Property="IsVisible" Value="True" />
|
||||
</Style>
|
||||
<Style Selector="Border.editable:pointerover Svg.hide">
|
||||
<Setter Property="IsVisible" Value="False" />
|
||||
</Style>
|
||||
<!-- TOGGLE BUTTON -->
|
||||
|
||||
<Style Selector="ToggleButton">
|
||||
@@ -663,6 +727,12 @@
|
||||
</Style>
|
||||
|
||||
|
||||
<Style Selector=".mobile TextBox.numeric">
|
||||
<Setter Property="(TextInputOptions.ContentType)" Value="Number" />
|
||||
<Setter Property="(TextInputOptions.ReturnKeyType)" Value="Next" />
|
||||
<Setter Property="(TextInputOptions.Multiline)" Value="False" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="TextBox.ghost">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
@@ -685,6 +755,25 @@
|
||||
<Setter Property="Opacity" Value="1" />
|
||||
</Style>
|
||||
|
||||
<!-- DATE RANGE PICKER -->
|
||||
|
||||
<Style Selector="cc|DateRangePicker.ghost">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextPrimary}" />
|
||||
<Setter Property="FontSize" Value="13" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="cc|DateRangePicker.ghost:pointerover /template/ Button#PART_Button">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="cc|DateRangePicker.ghost:pressed /template/ Button#PART_Button">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
</Style>
|
||||
|
||||
<!-- COMBOBOX -->
|
||||
|
||||
<Style Selector="ComboBox">
|
||||
|
||||
278
Clario/Theme/Styles/CalendarStyles.axaml
Normal file
@@ -0,0 +1,278 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<Design.PreviewWith>
|
||||
<Border Padding="20" Background="#0D0F14">
|
||||
<Calendar SelectionMode="SingleRange"/>
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
|
||||
<!-- ── FluentCalendarButton (header + prev/next) ──────── -->
|
||||
<Style Selector="Button.FluentCalendarButton, Button#PART_HeaderButton, Button#PART_PreviousButton, Button#PART_NextButton">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextPrimary}"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusAdorner" Value="{x:Null}"/>
|
||||
</Style>
|
||||
<Style Selector="Button.FluentCalendarButton:pointerover, Button#PART_HeaderButton:pointerover, Button#PART_PreviousButton:pointerover, Button#PART_NextButton:pointerover">
|
||||
<Setter Property="Background" Value="{DynamicResource BgHover}"/>
|
||||
</Style>
|
||||
<Style Selector="Button.FluentCalendarButton:pressed, Button#PART_HeaderButton:pressed, Button#PART_PreviousButton:pressed, Button#PART_NextButton:pressed">
|
||||
<Setter Property="Background" Value="{DynamicResource BorderSubtle}"/>
|
||||
</Style>
|
||||
|
||||
<!-- ── Calendar root ──────────────────────────────────── -->
|
||||
<Style Selector="Calendar">
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusControl}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource BgSurface}"/>
|
||||
<Setter Property="Background" Value="{DynamicResource BgSurface}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextPrimary}"/>
|
||||
</Style>
|
||||
|
||||
<!-- ── CalendarItem (the main container) ─────────────── -->
|
||||
<Style Selector="CalendarItem">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextPrimary}"/>
|
||||
<Setter Property="Background" Value="{DynamicResource BgSurface}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource BorderSubtle}"/>
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusControl}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Border BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
ClipToBounds="True">
|
||||
<Grid VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
RowDefinitions="44,*"
|
||||
MinWidth="294"
|
||||
Background="{TemplateBinding Background}">
|
||||
|
||||
<!-- Header row: title + prev/next -->
|
||||
<Grid ColumnDefinitions="*,36,36" Margin="8,0,4,0">
|
||||
<Button Name="PART_HeaderButton"
|
||||
Theme="{StaticResource FluentCalendarButton}"
|
||||
Foreground="{TemplateBinding Foreground}"
|
||||
Padding="8,0,0,0"
|
||||
CornerRadius="{DynamicResource RadiusControl}"
|
||||
HorizontalContentAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"/>
|
||||
<Button Name="PART_PreviousButton"
|
||||
Grid.Column="1"
|
||||
Theme="{StaticResource FluentCalendarButton}"
|
||||
Foreground="{TemplateBinding Foreground}"
|
||||
CornerRadius="{DynamicResource RadiusControl}"
|
||||
Width="32" Height="32"
|
||||
Padding="0"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<Path Stroke="{DynamicResource TextMuted}"
|
||||
StrokeThickness="1.5"
|
||||
Data="M 0,8 L 8,0 L 16,8"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Button>
|
||||
<Button Name="PART_NextButton"
|
||||
Grid.Column="2"
|
||||
Theme="{StaticResource FluentCalendarButton}"
|
||||
Foreground="{TemplateBinding Foreground}"
|
||||
CornerRadius="{DynamicResource RadiusControl}"
|
||||
Width="32" Height="32"
|
||||
Padding="0"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<Path Stroke="{DynamicResource TextMuted}"
|
||||
StrokeThickness="1.5"
|
||||
Data="M 0,0 L 8,8 L 16,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<!-- Separator under header -->
|
||||
<Border Grid.Row="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Height="1"
|
||||
Background="{DynamicResource BorderSubtle}"
|
||||
Margin="8,0"/>
|
||||
|
||||
<!-- Month grid -->
|
||||
<Grid Name="PART_MonthView"
|
||||
Grid.Row="1"
|
||||
IsVisible="False"
|
||||
MinHeight="290"
|
||||
Background="{TemplateBinding Background}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
</Grid>
|
||||
|
||||
<!-- Year/decade grid -->
|
||||
<Grid Name="PART_YearView"
|
||||
Grid.Row="1"
|
||||
MinHeight="290"
|
||||
IsVisible="False"
|
||||
Background="{TemplateBinding Background}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- ── CalendarDayButton ──────────────────────────────── -->
|
||||
<Style Selector="CalendarDayButton">
|
||||
<Setter Property="Width" Value="38"/>
|
||||
<Setter Property="Height" Value="38"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextSecondary}"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusAdorner" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Panel>
|
||||
<Border Name="Root"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="{DynamicResource RadiusIcon}"
|
||||
ClipToBounds="True">
|
||||
<ContentPresenter Name="PART_ContentPresenter"
|
||||
Content="{TemplateBinding Content}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
Foreground="{TemplateBinding Foreground}"/>
|
||||
</Border>
|
||||
<Border Name="Border"
|
||||
BorderThickness="2"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
CornerRadius="{DynamicResource RadiusIcon}"/>
|
||||
</Panel>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- hover -->
|
||||
<Style Selector="CalendarDayButton:pointerover /template/ Border#Root">
|
||||
<Setter Property="Background" Value="{DynamicResource BgHover}"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarDayButton:pointerover /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextPrimary}"/>
|
||||
</Style>
|
||||
|
||||
<!-- pressed -->
|
||||
<Style Selector="CalendarDayButton:pressed /template/ Border#Root">
|
||||
<Setter Property="Background" Value="{DynamicResource BorderSubtle}"/>
|
||||
</Style>
|
||||
|
||||
<!-- selected -->
|
||||
<Style Selector="CalendarDayButton:selected /template/ Border#Root">
|
||||
<Setter Property="Background" Value="{DynamicResource AccentBlue}"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarDayButton:selected /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Setter Property="Foreground" Value="{DynamicResource BgBase}"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarDayButton:selected:pointerover /template/ Border#Root">
|
||||
<Setter Property="Background" Value="{DynamicResource AccentBlue}"/>
|
||||
</Style>
|
||||
|
||||
<!-- today -->
|
||||
<Style Selector="CalendarDayButton:today /template/ Border#Root">
|
||||
<Setter Property="Background" Value="{DynamicResource IconBgBlue}"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarDayButton:today /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Setter Property="Foreground" Value="{DynamicResource AccentBlue}"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarDayButton:today:selected /template/ Border#Root">
|
||||
<Setter Property="Background" Value="{DynamicResource AccentBlue}"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarDayButton:today:selected /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Setter Property="Foreground" Value="{DynamicResource BgBase}"/>
|
||||
</Style>
|
||||
|
||||
<!-- inactive (days from prev/next month) -->
|
||||
<Style Selector="CalendarDayButton:inactive /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextDisabled}"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarDayButton:inactive /template/ Border#Root">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
</Style>
|
||||
|
||||
<!-- blackout -->
|
||||
<Style Selector="CalendarDayButton:blackout /template/ ContentPresenter#PART_ContentPresenter">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextDisabled}"/>
|
||||
<Setter Property="Opacity" Value="0.4"/>
|
||||
</Style>
|
||||
|
||||
<!-- ── CalendarButton (month/year picker cells) ──────── -->
|
||||
<Style Selector="CalendarButton">
|
||||
<Setter Property="Width" Value="60"/>
|
||||
<Setter Property="Height" Value="52"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextSecondary}"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusAdorner" Value="{x:Null}"/>
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusControl}"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarButton:pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource BgHover}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextPrimary}"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarButton:pressed /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource BorderSubtle}"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarButton:selected /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource AccentBlue}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource BgBase}"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarButton:today /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource IconBgBlue}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource AccentBlue}"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</Style>
|
||||
|
||||
</Styles>
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<Style Selector="Calendar">
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource RadiusControl}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource BgSurface}"></Setter>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource BgSurface}"/>
|
||||
</Style>
|
||||
<Style Selector="CalendarItem">
|
||||
<Setter Property="Foreground" Value="{DynamicResource CalendarViewForeground}" />
|
||||
|
||||
@@ -22,6 +22,14 @@ public class ViewLocator : IDataTemplate
|
||||
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
|
||||
var type = Type.GetType(name);
|
||||
|
||||
if (App.IsMobile)
|
||||
{
|
||||
var mobileName = name.Replace(".Views.", ".MobileViews.") + "Mobile";
|
||||
var mobileType = Type.GetType(mobileName);
|
||||
if (mobileType != null)
|
||||
return (Control)Activator.CreateInstance(mobileType)!;
|
||||
}
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return (Control)Activator.CreateInstance(type)!;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Clario.Data;
|
||||
using Clario.Models;
|
||||
using Clario.Services;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
@@ -15,30 +13,29 @@ namespace Clario.ViewModels;
|
||||
public partial class AccountsViewModel : ViewModelBase
|
||||
{
|
||||
public required ViewModelBase parentViewModel;
|
||||
private List<Account> _accounts = new();
|
||||
public required List<Account> Accounts = new();
|
||||
public required List<Transaction> Transactions = new();
|
||||
[ObservableProperty] private ObservableCollection<Account> _visibleAccounts = new();
|
||||
[ObservableProperty] private decimal _totalBalance = 0;
|
||||
[ObservableProperty] private Account _selectedAccount;
|
||||
[ObservableProperty] private Account? _selectedAccount;
|
||||
|
||||
public AccountsViewModel()
|
||||
{
|
||||
_ = Initialize();
|
||||
|
||||
}
|
||||
|
||||
private async Task Initialize()
|
||||
public async Task Initialize()
|
||||
{
|
||||
_accounts = await DataRepo.General.FetchAccounts();
|
||||
await FetchAndProcessAccountInfo();
|
||||
FetchAndProcessAccountInfo();
|
||||
GroupAccounts();
|
||||
SelectedAccount = VisibleAccounts.First(x => !x.GroupHeader);
|
||||
SelectedAccount = VisibleAccounts.FirstOrDefault(x => !x.GroupHeader);
|
||||
}
|
||||
|
||||
private async Task FetchAndProcessAccountInfo()
|
||||
private void FetchAndProcessAccountInfo()
|
||||
{
|
||||
var transactions = await DataRepo.General.FetchTransactions();
|
||||
foreach (var account in _accounts)
|
||||
foreach (var account in Accounts)
|
||||
{
|
||||
var accountTransactions = transactions.Where(t => t.AccountId == account.Id).ToList();
|
||||
var accountTransactions = Transactions.Where(t => t.AccountId == account.Id).ToList();
|
||||
account.TransactionsCount = accountTransactions.Count;
|
||||
account.CurrentBalance = account.OpeningBalance + accountTransactions.Sum(t => t.Type == "income" ? t.Amount : -t.Amount);
|
||||
account.TotalIncomeThisMonth = accountTransactions.Where(t => t.Date.Month == DateTime.Now.Month && t.Type == "income").Sum(t => t.Amount);
|
||||
@@ -65,7 +62,7 @@ public partial class AccountsViewModel : ViewModelBase
|
||||
|
||||
foreach (var type in accountTypes)
|
||||
{
|
||||
var accountsOfType = _accounts.Where(a => a.Type == type.Key).ToList();
|
||||
var accountsOfType = Accounts.Where(a => a.Type == type.Key).ToList();
|
||||
if (accountsOfType.Any())
|
||||
{
|
||||
var header = new Account { Name = type.Value.ToUpper(), GroupHeader = true };
|
||||
|
||||
@@ -3,10 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Clario.Data;
|
||||
using Clario.Models.GeneralModels;
|
||||
using Clario.Services;
|
||||
using Clario.Views;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Supabase.Gotrue;
|
||||
@@ -37,6 +34,7 @@ public partial class AuthViewModel : ViewModelBase
|
||||
|
||||
public AuthViewModel()
|
||||
{
|
||||
Console.WriteLine("auth vm loaded");
|
||||
setDefaults();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Clario.ViewModels;
|
||||
namespace Clario.ViewModels;
|
||||
|
||||
public partial class BudgetCardMenuViewModel : ViewModelBase
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Clario.ViewModels;
|
||||
namespace Clario.ViewModels;
|
||||
|
||||
public partial class BudgetFormViewModel : ViewModelBase
|
||||
{
|
||||
|
||||