Compare commits
1 Commits
feature/ba
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 758686bd32 |
@@ -1,25 +1,17 @@
|
|||||||
**/.dockerignore
|
# Ignore the node_modules directory
|
||||||
**/.env
|
node_modules
|
||||||
**/.git
|
|
||||||
**/.gitignore
|
# Ignore the dist directory
|
||||||
**/.project
|
www
|
||||||
**/.settings
|
|
||||||
**/.toolstarget
|
# Ignore the .git directory
|
||||||
**/.vs
|
.git
|
||||||
**/.vscode
|
|
||||||
**/.idea
|
# Ignore the .gitignore file
|
||||||
**/*.*proj.user
|
.gitignore
|
||||||
**/*.dbmdl
|
|
||||||
**/*.jfm
|
# Ignore the .dockerignore file
|
||||||
**/azds.yaml
|
.dockerignore
|
||||||
**/bin
|
Dockerfile
|
||||||
**/charts
|
|
||||||
**/docker-compose*
|
.vscode/*
|
||||||
**/Dockerfile*
|
|
||||||
**/node_modules
|
|
||||||
**/npm-debug.log
|
|
||||||
**/obj
|
|
||||||
**/secrets.dev.yaml
|
|
||||||
**/values.dev.yaml
|
|
||||||
LICENSE
|
|
||||||
README.md
|
|
||||||
|
|||||||
462
.gitignore
vendored
462
.gitignore
vendored
@@ -1,432 +1,70 @@
|
|||||||
### Csharp template
|
# Specifies intentionally untracked files to ignore when using Git
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
# http://git-scm.com/docs/gitignore
|
||||||
## files generated by popular Visual Studio add-ons.
|
|
||||||
##
|
|
||||||
## Get latest from https://github.com/github/gitignore/blob/main/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
|
|
||||||
.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/
|
|
||||||
|
|
||||||
# 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
|
|
||||||
*.tlog
|
|
||||||
*.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
|
*.sw[mnpcod]
|
||||||
*.dbproj.schemaview
|
.tmp
|
||||||
*.jfm
|
*.tmp
|
||||||
*.pfx
|
*.tmp.*
|
||||||
*.publishsettings
|
UserInterfaceState.xcuserstate
|
||||||
orleans.codegen.cs
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
# Including strong name files can present a security risk
|
*.log
|
||||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
log.txt
|
||||||
#*.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
|
/.sourcemaps
|
||||||
Generated_Code/
|
/.versions
|
||||||
|
/coverage
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
# Ionic
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
/.ionic
|
||||||
# because we have git ;-)
|
/www
|
||||||
_UpgradeReport_Files/
|
/platforms
|
||||||
Backup*/
|
/plugins
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
ServiceFabricBackup/
|
|
||||||
*.rptproj.bak
|
|
||||||
|
|
||||||
# SQL Server files
|
# Compiled output
|
||||||
*.mdf
|
/dist
|
||||||
*.ldf
|
/tmp
|
||||||
*.ndf
|
/out-tsc
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
# Business Intelligence projects
|
# Node
|
||||||
*.rdl.data
|
/node_modules
|
||||||
*.bim.layout
|
npm-debug.log
|
||||||
*.bim_*.settings
|
yarn-error.log
|
||||||
*.rptproj.rsuser
|
|
||||||
*- [Bb]ackup.rdl
|
|
||||||
*- [Bb]ackup ([0-9]).rdl
|
|
||||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
|
||||||
|
|
||||||
# Microsoft Fakes
|
# IDEs and editors
|
||||||
FakesAssemblies/
|
.idea/
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-project
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
# Visual Studio Code
|
||||||
*.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 6 auto-generated project file (contains which files were open etc.)
|
|
||||||
*.vbp
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
|
||||||
*.dsw
|
|
||||||
*.dsp
|
|
||||||
|
|
||||||
# Visual Studio 6 technical files
|
|
||||||
*.ncb
|
|
||||||
*.aps
|
|
||||||
|
|
||||||
# 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/
|
|
||||||
|
|
||||||
# Visual Studio History (VSHistory) files
|
|
||||||
.vshistory/
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# VS Code files for those working on multiple tools
|
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/settings.json
|
!.vscode/settings.json
|
||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
*.code-workspace
|
.history/*
|
||||||
|
|
||||||
# Local History for Visual Studio Code
|
|
||||||
.history/
|
|
||||||
|
|
||||||
# Windows Installer files from build outputs
|
# Miscellaneous
|
||||||
*.cab
|
/.angular
|
||||||
*.msi
|
/.angular/cache
|
||||||
*.msix
|
|
||||||
*.msm
|
|
||||||
*.msp
|
|
||||||
|
|
||||||
# JetBrains Rider
|
|
||||||
*.sln.iml
|
|
||||||
|
|
||||||
### Angular template
|
|
||||||
## Angular ##
|
|
||||||
# compiled output
|
|
||||||
dist/
|
|
||||||
tmp/
|
|
||||||
app/**/*.js
|
|
||||||
app/**/*.js.map
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
node_modules/
|
|
||||||
bower_components/
|
|
||||||
|
|
||||||
# IDEs and editors
|
|
||||||
.idea/
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.sass-cache/
|
.sass-cache/
|
||||||
connect.lock/
|
/.nx
|
||||||
coverage/
|
/.nx/cache
|
||||||
libpeerconnection.log/
|
/connect.lock
|
||||||
npm-debug.log
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
testem.log
|
testem.log
|
||||||
typings/
|
/typings
|
||||||
.angular/
|
|
||||||
|
|
||||||
# e2e
|
|
||||||
e2e/*.js
|
|
||||||
e2e/*.map
|
|
||||||
|
|
||||||
# System Files
|
|
||||||
.DS_Store/
|
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|||||||
@@ -1,116 +1,62 @@
|
|||||||
|
image: node:lts-alpine
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- install
|
- install
|
||||||
- lint
|
- lint
|
||||||
- build
|
- build
|
||||||
- test
|
|
||||||
- publish
|
- publish
|
||||||
|
|
||||||
install-mobile:
|
install:
|
||||||
stage: install
|
stage: install
|
||||||
image: node:lts-alpine
|
|
||||||
before_script:
|
|
||||||
- cd src/WorkTime.WebMobile
|
|
||||||
script:
|
script:
|
||||||
- npm install --prefer-offline
|
- npm install --prefer-offline
|
||||||
cache:
|
cache:
|
||||||
key:
|
key:
|
||||||
files:
|
files:
|
||||||
- src/WorkTime.WebMobile/package.json
|
- package.json
|
||||||
paths:
|
paths:
|
||||||
- src/WorkTime.WebMobile/node_modules
|
- node_modules
|
||||||
|
|
||||||
install-backend:
|
lint:
|
||||||
stage: install
|
|
||||||
image: mcr.microsoft.com/dotnet/sdk:9.0
|
|
||||||
script:
|
|
||||||
- dotnet restore
|
|
||||||
|
|
||||||
lint-mobile:
|
|
||||||
stage: lint
|
stage: lint
|
||||||
image: node:lts-alpine
|
needs: ["install"]
|
||||||
needs: ["install-mobile"]
|
|
||||||
before_script:
|
|
||||||
- cd src/WorkTime.WebMobile
|
|
||||||
script:
|
script:
|
||||||
- npm run lint
|
- npm run lint
|
||||||
cache:
|
cache:
|
||||||
key:
|
key:
|
||||||
files:
|
files:
|
||||||
- src/WorkTime.WebMobile/package.json
|
- package.json
|
||||||
paths:
|
paths:
|
||||||
- src/WorkTime.WebMobile/node_modules
|
- node_modules
|
||||||
policy: pull
|
policy: pull
|
||||||
|
|
||||||
build-mobile:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
image: node:lts-alpine
|
needs: ["lint"]
|
||||||
needs: ["lint-mobile"]
|
|
||||||
before_script:
|
|
||||||
- cd src/WorkTime.WebMobile
|
|
||||||
script:
|
script:
|
||||||
- npm run build
|
- npm run build
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- $CI_PROJECT_DIR/src/WorkTime.WebMobile/www
|
- $CI_PROJECT_DIR/www
|
||||||
expire_in: 10 minutes
|
expire_in: 10 minutes
|
||||||
cache:
|
cache:
|
||||||
key:
|
key:
|
||||||
files:
|
files:
|
||||||
- src/WorkTime.WebMobile/package.json
|
- package.json
|
||||||
paths:
|
paths:
|
||||||
- src/WorkTime.WebMobile/node_modules
|
- node_modules
|
||||||
policy: pull
|
policy: pull
|
||||||
|
|
||||||
build-backend:
|
publish:
|
||||||
stage: build
|
|
||||||
image: mcr.microsoft.com/dotnet/sdk:9.0
|
|
||||||
script:
|
|
||||||
- dotnet restore
|
|
||||||
- dotnet build --configuration Release --no-restore
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- "**/bin/Release"
|
|
||||||
expire_in: 10 minutes
|
|
||||||
dependencies:
|
|
||||||
- install-backend
|
|
||||||
|
|
||||||
test-backend:
|
|
||||||
stage: test
|
|
||||||
image: mcr.microsoft.com/dotnet/sdk:9.0
|
|
||||||
script:
|
|
||||||
- dotnet test --verbosity normal
|
|
||||||
dependencies:
|
|
||||||
- build-backend
|
|
||||||
|
|
||||||
publish-mobile:
|
|
||||||
stage: publish
|
stage: publish
|
||||||
needs: ["build-mobile"]
|
needs: ["build"]
|
||||||
image: docker:latest
|
tags:
|
||||||
services:
|
- docker
|
||||||
- name: docker:dind
|
|
||||||
alias: docker
|
|
||||||
before_script:
|
|
||||||
- cd src/WorkTime.WebMobile
|
|
||||||
script:
|
script:
|
||||||
- export VERSION=$(echo $CI_COMMIT_TAG | sed 's/^v//')
|
- export VERSION=$(echo $CI_COMMIT_TAG | sed 's/^v//')
|
||||||
- docker login -u leon.hoppe -p ${CI_REGISTRY_PASSWORD} registry.leon-hoppe.de
|
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin registry.leon-hoppe.de
|
||||||
- docker build -t registry.leon-hoppe.de/leon.hoppe/worktime/mobile:$VERSION -t registry.leon-hoppe.de/leon.hoppe/worktime/mobile:latest .
|
- docker build -t registry.leon-hoppe.de/leon.hoppe/worktime:$VERSION -t registry.leon-hoppe.de/leon.hoppe/worktime:latest .
|
||||||
- docker push registry.leon-hoppe.de/leon.hoppe/worktime/mobile:$VERSION
|
- docker push registry.leon-hoppe.de/leon.hoppe/worktime:$VERSION
|
||||||
- docker push registry.leon-hoppe.de/leon.hoppe/worktime/mobile:latest
|
- docker push registry.leon-hoppe.de/leon.hoppe/worktime:latest
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
|
|
||||||
publish-backend:
|
|
||||||
stage: publish
|
|
||||||
image: docker:latest
|
|
||||||
services:
|
|
||||||
- name: docker:dind
|
|
||||||
alias: docker
|
|
||||||
script:
|
|
||||||
- export VERSION=$(echo $CI_COMMIT_TAG | sed 's/^v//')
|
|
||||||
- docker login -u leon.hoppe -p ${CI_REGISTRY_PASSWORD} registry.leon-hoppe.de
|
|
||||||
- docker build -t registry.leon-hoppe.de/leon.hoppe/worktime/api:$VERSION -t registry.leon-hoppe.de/leon.hoppe/worktime/api:latest -f src/WorkTime.Api/Dockerfile .
|
|
||||||
- docker push registry.leon-hoppe.de/leon.hoppe/worktime/api:$VERSION
|
|
||||||
- docker push registry.leon-hoppe.de/leon.hoppe/worktime/api:latest
|
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
|
|||||||
13
.idea/.gitignore
generated
vendored
13
.idea/.gitignore
generated
vendored
@@ -1,13 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Rider ignored files
|
|
||||||
/contentModel.xml
|
|
||||||
/.idea.WorkTime.iml
|
|
||||||
/modules.xml
|
|
||||||
/projectSettingsUpdater.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
||||||
13
.idea/.idea.WorkTime/.idea/.gitignore
generated
vendored
13
.idea/.idea.WorkTime/.idea/.gitignore
generated
vendored
@@ -1,13 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Rider ignored files
|
|
||||||
/modules.xml
|
|
||||||
/contentModel.xml
|
|
||||||
/projectSettingsUpdater.xml
|
|
||||||
/.idea.WorkTime.iml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
||||||
4
.idea/.idea.WorkTime/.idea/encodings.xml
generated
4
.idea/.idea.WorkTime/.idea/encodings.xml
generated
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
|
||||||
</project>
|
|
||||||
11
.idea/.idea.WorkTime/.idea/indexLayout.xml
generated
11
.idea/.idea.WorkTime/.idea/indexLayout.xml
generated
@@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="UserContentModel">
|
|
||||||
<attachedFolders>
|
|
||||||
<Path>src/WorkTime.Mobile</Path>
|
|
||||||
<Path>src/WorkTime.WebMobile</Path>
|
|
||||||
</attachedFolders>
|
|
||||||
<explicitIncludes />
|
|
||||||
<explicitExcludes />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
14
.idea/.idea.WorkTime/.idea/misc.xml
generated
14
.idea/.idea.WorkTime/.idea/misc.xml
generated
@@ -1,14 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DiscordProjectSettings">
|
|
||||||
<option name="show" value="ASK" />
|
|
||||||
<option name="description" value="" />
|
|
||||||
<option name="applicationTheme" value="default" />
|
|
||||||
<option name="iconsTheme" value="default" />
|
|
||||||
<option name="button1Title" value="" />
|
|
||||||
<option name="button1Url" value="" />
|
|
||||||
<option name="button2Title" value="" />
|
|
||||||
<option name="button2Url" value="" />
|
|
||||||
<option name="customApplicationId" value="" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
6
.idea/.idea.WorkTime/.idea/vcs.xml
generated
6
.idea/.idea.WorkTime/.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
4
.idea/encodings.xml
generated
4
.idea/encodings.xml
generated
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
|
||||||
</project>
|
|
||||||
8
.idea/indexLayout.xml
generated
8
.idea/indexLayout.xml
generated
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="UserContentModel">
|
|
||||||
<attachedFolders />
|
|
||||||
<explicitIncludes />
|
|
||||||
<explicitExcludes />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
14
.idea/misc.xml
generated
14
.idea/misc.xml
generated
@@ -1,14 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DiscordProjectSettings">
|
|
||||||
<option name="show" value="ASK" />
|
|
||||||
<option name="description" value="" />
|
|
||||||
<option name="applicationTheme" value="default" />
|
|
||||||
<option name="iconsTheme" value="default" />
|
|
||||||
<option name="button1Title" value="" />
|
|
||||||
<option name="button1Url" value="" />
|
|
||||||
<option name="button2Title" value="" />
|
|
||||||
<option name="button2Url" value="" />
|
|
||||||
<option name="customApplicationId" value="" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
50
WorkTime.sln
50
WorkTime.sln
@@ -1,50 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{25C5A6B2-A1F9-4244-9538-18E3FE76D382}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkTime.Host", "src\WorkTime.Host\WorkTime.Host.csproj", "{6F5D4D47-1484-44EA-A5DD-D00AAD2F2F68}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkTime.ServiceDefaults", "src\WorkTime.ServiceDefaults\WorkTime.ServiceDefaults.csproj", "{B66AA463-03D5-4814-B1D4-71663804248C}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkTime.Shared", "src\WorkTime.Shared\WorkTime.Shared.csproj", "{E6A73E21-39B8-4FA7-8D6D-D5DDB8FB8AF0}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkTime.Api", "src\WorkTime.Api\WorkTime.Api.csproj", "{CED653D6-A0B6-432B-9C36-FBB58EEA8229}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{8CB1F4C6-F95B-4935-81AA-751015E69FEC}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkTime.Mobile", "src\WorkTime.Mobile\WorkTime.Mobile.csproj", "{640DF179-F955-4497-B798-43ABE2AAABF6}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(NestedProjects) = preSolution
|
|
||||||
{6F5D4D47-1484-44EA-A5DD-D00AAD2F2F68} = {25C5A6B2-A1F9-4244-9538-18E3FE76D382}
|
|
||||||
{B66AA463-03D5-4814-B1D4-71663804248C} = {25C5A6B2-A1F9-4244-9538-18E3FE76D382}
|
|
||||||
{CED653D6-A0B6-432B-9C36-FBB58EEA8229} = {25C5A6B2-A1F9-4244-9538-18E3FE76D382}
|
|
||||||
{640DF179-F955-4497-B798-43ABE2AAABF6} = {8CB1F4C6-F95B-4935-81AA-751015E69FEC}
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{6F5D4D47-1484-44EA-A5DD-D00AAD2F2F68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{6F5D4D47-1484-44EA-A5DD-D00AAD2F2F68}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{6F5D4D47-1484-44EA-A5DD-D00AAD2F2F68}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{6F5D4D47-1484-44EA-A5DD-D00AAD2F2F68}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{B66AA463-03D5-4814-B1D4-71663804248C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{B66AA463-03D5-4814-B1D4-71663804248C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{B66AA463-03D5-4814-B1D4-71663804248C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{B66AA463-03D5-4814-B1D4-71663804248C}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{E6A73E21-39B8-4FA7-8D6D-D5DDB8FB8AF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{E6A73E21-39B8-4FA7-8D6D-D5DDB8FB8AF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{E6A73E21-39B8-4FA7-8D6D-D5DDB8FB8AF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{E6A73E21-39B8-4FA7-8D6D-D5DDB8FB8AF0}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{CED653D6-A0B6-432B-9C36-FBB58EEA8229}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{CED653D6-A0B6-432B-9C36-FBB58EEA8229}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{CED653D6-A0B6-432B-9C36-FBB58EEA8229}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{CED653D6-A0B6-432B-9C36-FBB58EEA8229}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{640DF179-F955-4497-B798-43ABE2AAABF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{640DF179-F955-4497-B798-43ABE2AAABF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{640DF179-F955-4497-B798-43ABE2AAABF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{640DF179-F955-4497-B798-43ABE2AAABF6}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
using System.Security.Claims;
|
|
||||||
using System.Text.Encodings.Web;
|
|
||||||
using Microsoft.AspNetCore.Authentication;
|
|
||||||
using Microsoft.AspNetCore.OpenApi;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using WorkTime.Shared.Services;
|
|
||||||
|
|
||||||
namespace WorkTime.Api;
|
|
||||||
|
|
||||||
public class AuthHandler(
|
|
||||||
IOptionsMonitor<AuthenticationSchemeOptions> options,
|
|
||||||
ILoggerFactory logger,
|
|
||||||
UrlEncoder encoder,
|
|
||||||
IAuthService authService)
|
|
||||||
: AuthenticationHandler<AuthenticationSchemeOptions>(options, logger, encoder) {
|
|
||||||
|
|
||||||
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() {
|
|
||||||
if (! await authService.IsAuthenticated()) {
|
|
||||||
return AuthenticateResult.Fail("Invalid or missing Guid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var guid = await authService.GetCurrentUserId();
|
|
||||||
|
|
||||||
var claims = new[] { new Claim(ClaimTypes.NameIdentifier, guid.ToString()) };
|
|
||||||
var identity = new ClaimsIdentity(claims, Scheme.Name);
|
|
||||||
var principal = new ClaimsPrincipal(identity);
|
|
||||||
var ticket = new AuthenticationTicket(principal, Scheme.Name);
|
|
||||||
|
|
||||||
return AuthenticateResult.Success(ticket);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Task ConfigureOpenApi(OpenApiDocument document, OpenApiDocumentTransformerContext transformerContext, CancellationToken token) {
|
|
||||||
document.Components ??= new OpenApiComponents();
|
|
||||||
document.Components.SecuritySchemes ??= new Dictionary<string, OpenApiSecurityScheme>();
|
|
||||||
document.SecurityRequirements ??= new List<OpenApiSecurityRequirement>();
|
|
||||||
|
|
||||||
document.Components.SecuritySchemes.Add(nameof(AuthHandler), new OpenApiSecurityScheme {
|
|
||||||
Type = SecuritySchemeType.Http,
|
|
||||||
In = ParameterLocation.Header,
|
|
||||||
Name = IAuthService.HeaderName,
|
|
||||||
Scheme = "Bearer",
|
|
||||||
Description = "GUID Authorization header using a custom scheme.\nExample: \"Authorization: {GUID}\""
|
|
||||||
});
|
|
||||||
|
|
||||||
//TODO: only add security requirement to authorized endpoints
|
|
||||||
document.SecurityRequirements.Add(new() {
|
|
||||||
{
|
|
||||||
new() {
|
|
||||||
Reference = new OpenApiReference {
|
|
||||||
Type = ReferenceType.SecurityScheme,
|
|
||||||
Id = nameof(AuthHandler)
|
|
||||||
}
|
|
||||||
}, []
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace WorkTime.Api.Controllers;
|
|
||||||
|
|
||||||
[ApiController, Route("auth")]
|
|
||||||
public class AuthController : ControllerBase {
|
|
||||||
|
|
||||||
[HttpGet("register")]
|
|
||||||
public ActionResult<Guid> Register() {
|
|
||||||
return Ok(Guid.NewGuid().ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using WorkTime.Api.Logic;
|
|
||||||
using WorkTime.Shared.Models;
|
|
||||||
|
|
||||||
namespace WorkTime.Api.Controllers;
|
|
||||||
|
|
||||||
[ApiController, Route("entries"), Authorize]
|
|
||||||
public class EntryController(EntryLogic logic) : ControllerBase {
|
|
||||||
|
|
||||||
[HttpGet("{id:guid}")]
|
|
||||||
public async Task<IResult> GetAllEntries(Guid id) {
|
|
||||||
var result = await logic.GetAllEntries(id);
|
|
||||||
return result.MapResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id:guid}/{day:datetime}")]
|
|
||||||
public async Task<IResult> GetEntries(Guid id, DateTime day) {
|
|
||||||
var result = await logic.GetEntries(id, DateOnly.FromDateTime(day));
|
|
||||||
return result.MapResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<IResult> AddEntry(TimeEntry entry) {
|
|
||||||
var result = await logic.AddEntry(entry);
|
|
||||||
return result.MapResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{id:int}")]
|
|
||||||
public async Task<IResult> DeleteEntry(int id) {
|
|
||||||
var result = await logic.DeleteEntry(id);
|
|
||||||
return result.MapResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using WorkTime.Shared.Models;
|
|
||||||
|
|
||||||
namespace WorkTime.Api;
|
|
||||||
|
|
||||||
public class DatabaseContext(DbContextOptions<DatabaseContext> options) : DbContext(options) {
|
|
||||||
|
|
||||||
public DbSet<TimeEntry> Entries { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
|
||||||
USER $APP_UID
|
|
||||||
WORKDIR /app
|
|
||||||
EXPOSE 8080
|
|
||||||
EXPOSE 8081
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
|
||||||
ARG BUILD_CONFIGURATION=Release
|
|
||||||
WORKDIR /src
|
|
||||||
COPY ["src/WorkTime.Api/WorkTime.Api.csproj", "src/WorkTime.Api/"]
|
|
||||||
RUN dotnet restore "src/WorkTime.Api/WorkTime.Api.csproj"
|
|
||||||
COPY . .
|
|
||||||
WORKDIR "/src/src/WorkTime.Api"
|
|
||||||
RUN dotnet build "WorkTime.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
|
||||||
|
|
||||||
FROM build AS publish
|
|
||||||
ARG BUILD_CONFIGURATION=Release
|
|
||||||
RUN dotnet publish "WorkTime.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
|
||||||
|
|
||||||
FROM base AS final
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=publish /app/publish .
|
|
||||||
ENTRYPOINT ["dotnet", "WorkTime.Api.dll"]
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Http.HttpResults;
|
|
||||||
using WorkTime.ServiceDefaults.Results;
|
|
||||||
using WorkTime.Shared.Models;
|
|
||||||
using WorkTime.Shared.Repositories;
|
|
||||||
using WorkTime.Shared.Services;
|
|
||||||
|
|
||||||
namespace WorkTime.Api.Logic;
|
|
||||||
|
|
||||||
public class EntryLogic(IEntryRepository entryRepository, IAuthService authService) {
|
|
||||||
|
|
||||||
public async Task<LogicResult<TimeEntry[]>> GetAllEntries(Guid owner) {
|
|
||||||
if (!await authService.IsAuthenticated())
|
|
||||||
return new(Results.Unauthorized());
|
|
||||||
|
|
||||||
if (await authService.GetCurrentUserId() != owner)
|
|
||||||
return new(Results.Unauthorized());
|
|
||||||
|
|
||||||
return await entryRepository.GetAllEntries(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<LogicResult<TimeEntry[]>> GetEntries(Guid owner, DateOnly date) {
|
|
||||||
if (!await authService.IsAuthenticated())
|
|
||||||
return new(Results.Unauthorized());
|
|
||||||
|
|
||||||
if (await authService.GetCurrentUserId() != owner)
|
|
||||||
return new(Results.Unauthorized());
|
|
||||||
|
|
||||||
return await entryRepository.GetEntries(owner, date);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<LogicResult> AddEntry(TimeEntry entry) {
|
|
||||||
if (!await authService.IsAuthenticated())
|
|
||||||
return new(Results.Unauthorized());
|
|
||||||
|
|
||||||
if (await authService.GetCurrentUserId() != entry.Owner)
|
|
||||||
return new(Results.Unauthorized());
|
|
||||||
|
|
||||||
await entryRepository.AddEntry(entry);
|
|
||||||
return new();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<LogicResult> DeleteEntry(int id) {
|
|
||||||
if (!await authService.IsAuthenticated())
|
|
||||||
return new(Results.Unauthorized());
|
|
||||||
|
|
||||||
var entry = await entryRepository.GetEntry(id);
|
|
||||||
if (entry is null)
|
|
||||||
return new(Results.NotFound());
|
|
||||||
|
|
||||||
if (await authService.GetCurrentUserId() != entry.Owner)
|
|
||||||
return new(Results.Unauthorized());
|
|
||||||
|
|
||||||
await entryRepository.DeleteEntry(entry);
|
|
||||||
return new();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
using MartinCostello.OpenApi;
|
|
||||||
using Microsoft.AspNetCore.Authentication;
|
|
||||||
using WorkTime.Api;
|
|
||||||
using WorkTime.Api.Logic;
|
|
||||||
using WorkTime.Api.Repositories;
|
|
||||||
using WorkTime.Api.Services;
|
|
||||||
using WorkTime.Shared.Repositories;
|
|
||||||
using WorkTime.Shared.Services;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
|
||||||
|
|
||||||
// Add services to the container.
|
|
||||||
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
|
||||||
builder.Services.AddOpenApi(options => {
|
|
||||||
options.AddDocumentTransformer(AuthHandler.ConfigureOpenApi);
|
|
||||||
});
|
|
||||||
builder.Services.AddOpenApiExtensions(options => {
|
|
||||||
options.AddServerUrls = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.AddServiceDefaults();
|
|
||||||
builder.Services.AddControllers();
|
|
||||||
builder.Services.AddProblemDetails();
|
|
||||||
builder.Services.AddHttpContextAccessor();
|
|
||||||
|
|
||||||
builder.Services.AddNpgsql<DatabaseContext>(builder.Configuration.GetConnectionString("data"));
|
|
||||||
builder.Services.AddScoped<IEntryRepository, EntryRepository>();
|
|
||||||
builder.Services.AddScoped<IAuthService, AuthService>();
|
|
||||||
|
|
||||||
builder.Services.AddScoped<EntryLogic>();
|
|
||||||
|
|
||||||
builder.Services.AddAuthentication(nameof(AuthHandler))
|
|
||||||
.AddScheme<AuthenticationSchemeOptions, AuthHandler>(nameof(AuthHandler), _ => { });
|
|
||||||
builder.Services.AddAuthorization();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
|
||||||
if (app.Environment.IsDevelopment()) {
|
|
||||||
app.MapOpenApi();
|
|
||||||
app.UseSwaggerUI(options => {
|
|
||||||
options.SwaggerEndpoint("/openapi/v1.json", "WorkTime.Api");
|
|
||||||
});
|
|
||||||
|
|
||||||
await using var scope = app.Services.CreateAsyncScope();
|
|
||||||
var db = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
|
|
||||||
db.Database.EnsureCreated();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
|
||||||
app.UseAuthentication();
|
|
||||||
app.UseAuthorization();
|
|
||||||
|
|
||||||
app.MapControllers();
|
|
||||||
|
|
||||||
app.Run();
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
|
||||||
"profiles": {
|
|
||||||
"http": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"dotnetRunMessages": true,
|
|
||||||
"launchBrowser": false,
|
|
||||||
"applicationUrl": "http://localhost:5212",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"https": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"dotnetRunMessages": true,
|
|
||||||
"launchBrowser": false,
|
|
||||||
"applicationUrl": "https://localhost:7091;http://localhost:5212",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using WorkTime.Shared.Models;
|
|
||||||
using WorkTime.Shared.Repositories;
|
|
||||||
|
|
||||||
namespace WorkTime.Api.Repositories;
|
|
||||||
|
|
||||||
internal class EntryRepository(DatabaseContext context) : IEntryRepository {
|
|
||||||
|
|
||||||
public async Task<TimeEntry[]> GetAllEntries(Guid owner) {
|
|
||||||
return await context.Entries
|
|
||||||
.Where(entry => entry.Owner == owner)
|
|
||||||
.OrderBy(entry => entry.Timestamp)
|
|
||||||
.ToArrayAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<TimeEntry[]> GetEntries(Guid owner, DateOnly date) {
|
|
||||||
return await context.Entries
|
|
||||||
.Where(entry => entry.Owner == owner)
|
|
||||||
.Where(entry => DateOnly.FromDateTime(entry.Timestamp) == date)
|
|
||||||
.OrderBy(entry => entry.Timestamp)
|
|
||||||
.ToArrayAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<TimeEntry?> GetEntry(int id) {
|
|
||||||
return await context.Entries
|
|
||||||
.FindAsync(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task AddEntry(TimeEntry entry) {
|
|
||||||
await context.Entries.AddAsync(entry);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteEntry(TimeEntry entry) {
|
|
||||||
context.Entries.Remove(entry);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using WorkTime.Shared.Services;
|
|
||||||
|
|
||||||
namespace WorkTime.Api.Services;
|
|
||||||
|
|
||||||
internal class AuthService(IHttpContextAccessor accessor) : IAuthService {
|
|
||||||
|
|
||||||
public Task<bool> IsAuthenticated() {
|
|
||||||
var header = accessor.HttpContext?.Request.Headers[IAuthService.HeaderName];
|
|
||||||
if (header is not { Count: 1 })
|
|
||||||
return Task.FromResult(false);
|
|
||||||
|
|
||||||
var value = header.Value[0]!.Replace("Bearer ", "");
|
|
||||||
if (Guid.TryParse(value, out var guid))
|
|
||||||
return Task.FromResult(false);
|
|
||||||
|
|
||||||
return Task.FromResult(guid != Guid.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Guid> GetCurrentUserId() {
|
|
||||||
if (!await IsAuthenticated())
|
|
||||||
return Guid.Empty;
|
|
||||||
|
|
||||||
var header = accessor.HttpContext?.Request.Headers[IAuthService.HeaderName]!;
|
|
||||||
var value = header.Value[0]!.Replace("Bearer ", "");
|
|
||||||
|
|
||||||
return Guid.Parse(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.1.0" />
|
|
||||||
<PackageReference Include="MartinCostello.OpenApi.Extensions" Version="1.0.0" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0"/>
|
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="7.3.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="..\..\.dockerignore">
|
|
||||||
<Link>.dockerignore</Link>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\WorkTime.ServiceDefaults\WorkTime.ServiceDefaults.csproj" />
|
|
||||||
<ProjectReference Include="..\WorkTime.Shared\WorkTime.Shared.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowedHosts": "*"
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
var builder = DistributedApplication.CreateBuilder(args);
|
|
||||||
|
|
||||||
var db = builder.AddPostgres("db")
|
|
||||||
.WithDataVolume();
|
|
||||||
|
|
||||||
builder.AddProject<Projects.WorkTime_Api>("api")
|
|
||||||
.WithReference(db.AddDatabase("data"))
|
|
||||||
.WaitFor(db);
|
|
||||||
|
|
||||||
builder.Build().Run();
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
|
||||||
"profiles": {
|
|
||||||
"https": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"dotnetRunMessages": true,
|
|
||||||
"launchBrowser": false,
|
|
||||||
"applicationUrl": "https://localhost:17121;http://localhost:15199",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
|
||||||
"DOTNET_ENVIRONMENT": "Development",
|
|
||||||
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21125",
|
|
||||||
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22099"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"http": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"dotnetRunMessages": true,
|
|
||||||
"launchBrowser": false,
|
|
||||||
"applicationUrl": "http://localhost:15199",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
|
||||||
"DOTNET_ENVIRONMENT": "Development",
|
|
||||||
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19218",
|
|
||||||
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20104"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0"/>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<IsAspireHost>true</IsAspireHost>
|
|
||||||
<UserSecretsId>ba72af6f-0952-417d-bef6-ab77ed6fa624</UserSecretsId>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.1.0" />
|
|
||||||
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.1.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\WorkTime.Api\WorkTime.Api.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning",
|
|
||||||
"Aspire.Hosting.Dcp": "Warning"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<?xml version = "1.0" encoding = "UTF-8" ?>
|
|
||||||
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
xmlns:local="clr-namespace:WorkTime.Mobile"
|
|
||||||
x:Class="WorkTime.Mobile.App">
|
|
||||||
<Application.Resources>
|
|
||||||
<ResourceDictionary>
|
|
||||||
<ResourceDictionary.MergedDictionaries>
|
|
||||||
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
|
|
||||||
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
|
|
||||||
</ResourceDictionary.MergedDictionaries>
|
|
||||||
</ResourceDictionary>
|
|
||||||
</Application.Resources>
|
|
||||||
</Application>
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using MauiIcons.Core;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
public partial class App : Application {
|
|
||||||
public App() {
|
|
||||||
InitializeComponent();
|
|
||||||
_ = new MauiIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Window CreateWindow(IActivationState? activationState) {
|
|
||||||
return new Window(new AppShell());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<Shell
|
|
||||||
x:Class="WorkTime.Mobile.AppShell"
|
|
||||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
xmlns:pages="clr-namespace:WorkTime.Mobile.Views.Pages"
|
|
||||||
xmlns:icons="http://www.aathifmahir.com/dotnet/2022/maui/icons"
|
|
||||||
FlyoutBehavior="Disabled"
|
|
||||||
Title="Zeiterfassung">
|
|
||||||
|
|
||||||
<Shell.Resources>
|
|
||||||
<ResourceDictionary>
|
|
||||||
<FontImageSource x:Key="CaptureIcon" Glyph="{icons:Material Schedule}" />
|
|
||||||
</ResourceDictionary>
|
|
||||||
</Shell.Resources>
|
|
||||||
|
|
||||||
<TabBar>
|
|
||||||
|
|
||||||
<ShellContent
|
|
||||||
Title="Erfassen"
|
|
||||||
Icon="{StaticResource CaptureIcon}"
|
|
||||||
ContentTemplate="{DataTemplate pages:CapturePage}"/>
|
|
||||||
|
|
||||||
</TabBar>
|
|
||||||
|
|
||||||
</Shell>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
public partial class AppShell : Shell {
|
|
||||||
public AppShell() {
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using WorkTime.Shared.Models;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
public class DatabaseContext(DbContextOptions<DatabaseContext> options) : DbContext(options) {
|
|
||||||
|
|
||||||
public DbSet<TimeEntry> Entries { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using WorkTime.Shared.Models;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
public static class Extensions {
|
|
||||||
|
|
||||||
public static string GetActionName(this TimeEntryType type) {
|
|
||||||
return type switch {
|
|
||||||
TimeEntryType.Login => "Einstempeln",
|
|
||||||
TimeEntryType.Logout => "Ausstempeln",
|
|
||||||
TimeEntryType.LoginDrive => "Dienstreise starten",
|
|
||||||
TimeEntryType.LogoutDrive => "Dienstreise beenden",
|
|
||||||
_ => string.Empty
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
using MauiIcons.Material;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using WorkTime.Mobile.Repositories;
|
|
||||||
using WorkTime.Mobile.Services;
|
|
||||||
using WorkTime.Mobile.ViewModels;
|
|
||||||
using WorkTime.Shared.Repositories;
|
|
||||||
using WorkTime.Shared.Services;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
public static class MauiProgram {
|
|
||||||
|
|
||||||
private static string BackendUrl { get; set; } = string.Empty; //TODO: Set production endpoint
|
|
||||||
|
|
||||||
public static MauiApp CreateMauiApp() {
|
|
||||||
var builder = MauiApp.CreateBuilder();
|
|
||||||
builder
|
|
||||||
.UseMauiApp<App>()
|
|
||||||
.ConfigureFonts(fonts => {
|
|
||||||
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
|
|
||||||
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
|
|
||||||
})
|
|
||||||
.UseMaterialMauiIcons();
|
|
||||||
|
|
||||||
builder.Services.AddSqlite<DatabaseContext>($"Filename={Path.Combine(FileSystem.AppDataDirectory, "data.db")}");
|
|
||||||
builder.Services.AddSingleton(SecureStorage.Default);
|
|
||||||
builder.Services.AddScoped<HttpClient>(_ => {
|
|
||||||
var client = new HttpClient();
|
|
||||||
client.BaseAddress = new Uri(BackendUrl);
|
|
||||||
return client;
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Services.AddKeyedScoped<IEntryRepository, ServerEntryRepository>("server");
|
|
||||||
builder.Services.AddKeyedScoped<IEntryRepository, ClientEntryRepository>("client");
|
|
||||||
builder.Services.AddKeyedScoped<IHttpService, InsecureHttpService>("insecure");
|
|
||||||
builder.Services.AddScoped<IHttpService, HttpService>();
|
|
||||||
builder.Services.AddScoped<IAuthService, AuthService>();
|
|
||||||
builder.Services.AddScoped<EntryService>();
|
|
||||||
|
|
||||||
builder.Services.AddTransient<CaptureViewModel>();
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
builder.Logging.AddDebug();
|
|
||||||
BackendUrl = "https://localhost:7091/";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var app = builder.Build();
|
|
||||||
|
|
||||||
using var scope = app.Services.CreateScope();
|
|
||||||
var db = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
|
|
||||||
db.Database.EnsureCreated();
|
|
||||||
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
</manifest>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using Android.App;
|
|
||||||
using Android.Content.PM;
|
|
||||||
using Android.OS;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop,
|
|
||||||
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode |
|
|
||||||
ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
|
|
||||||
public class MainActivity : MauiAppCompatActivity { }
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using Android.App;
|
|
||||||
using Android.Runtime;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
[Application]
|
|
||||||
public class MainApplication : MauiApplication {
|
|
||||||
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
|
|
||||||
: base(handle, ownership) { }
|
|
||||||
|
|
||||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<color name="colorPrimary">#512BD4</color>
|
|
||||||
<color name="colorPrimaryDark">#2B0B98</color>
|
|
||||||
<color name="colorAccent">#2B0B98</color>
|
|
||||||
</resources>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using Foundation;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
[Register("AppDelegate")]
|
|
||||||
public class AppDelegate : MauiUIApplicationDelegate {
|
|
||||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<!-- See https://aka.ms/maui-publish-app-store#add-entitlements for more information about adding entitlements.-->
|
|
||||||
<dict>
|
|
||||||
<!-- App Sandbox must be enabled to distribute a MacCatalyst app through the Mac App Store. -->
|
|
||||||
<key>com.apple.security.app-sandbox</key>
|
|
||||||
<true/>
|
|
||||||
<!-- When App Sandbox is enabled, this value is required to open outgoing network connections. -->
|
|
||||||
<key>com.apple.security.network.client</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<!-- The Mac App Store requires you specify if the app uses encryption. -->
|
|
||||||
<!-- Please consult https://developer.apple.com/documentation/bundleresources/information_property_list/itsappusesnonexemptencryption -->
|
|
||||||
<!-- <key>ITSAppUsesNonExemptEncryption</key> -->
|
|
||||||
<!-- Please indicate <true/> or <false/> here. -->
|
|
||||||
|
|
||||||
<!-- Specify the category for your app here. -->
|
|
||||||
<!-- Please consult https://developer.apple.com/documentation/bundleresources/information_property_list/lsapplicationcategorytype -->
|
|
||||||
<!-- <key>LSApplicationCategoryType</key> -->
|
|
||||||
<!-- <string>public.app-category.YOUR-CATEGORY-HERE</string> -->
|
|
||||||
<key>UIDeviceFamily</key>
|
|
||||||
<array>
|
|
||||||
<integer>2</integer>
|
|
||||||
</array>
|
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
|
||||||
<array>
|
|
||||||
<string>arm64</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>XSAppIconAssets</key>
|
|
||||||
<string>Assets.xcassets/appicon.appiconset</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using ObjCRuntime;
|
|
||||||
using UIKit;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
public class Program {
|
|
||||||
// This is the main entry point of the application.
|
|
||||||
static void Main(string[] args) {
|
|
||||||
// if you want to use a different Application Delegate class from "AppDelegate"
|
|
||||||
// you can specify it here.
|
|
||||||
UIApplication.Main(args, null, typeof(AppDelegate));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Microsoft.Maui;
|
|
||||||
using Microsoft.Maui.Hosting;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
class Program : MauiApplication {
|
|
||||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
|
||||||
|
|
||||||
static void Main(string[] args) {
|
|
||||||
var app = new Program();
|
|
||||||
app.Run(args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest package="maui-application-id-placeholder" version="0.0.0" api-version="9" xmlns="http://tizen.org/ns/packages">
|
|
||||||
<profile name="common" />
|
|
||||||
<ui-application appid="maui-application-id-placeholder" exec="WorkTime.Mobile.dll" multiple="false" nodisplay="false" taskmanage="true" type="dotnet" launch_mode="single">
|
|
||||||
<label>maui-application-title-placeholder</label>
|
|
||||||
<icon>maui-appicon-placeholder</icon>
|
|
||||||
<metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
|
|
||||||
</ui-application>
|
|
||||||
<shortcut-list />
|
|
||||||
<privileges>
|
|
||||||
<privilege>http://tizen.org/privilege/internet</privilege>
|
|
||||||
</privileges>
|
|
||||||
<dependencies />
|
|
||||||
<provides-appdefined-privileges />
|
|
||||||
</manifest>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<maui:MauiWinUIApplication
|
|
||||||
x:Class="WorkTime.Mobile.WinUI.App"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:maui="using:Microsoft.Maui"
|
|
||||||
xmlns:local="using:WorkTime.Mobile.WinUI">
|
|
||||||
|
|
||||||
</maui:MauiWinUIApplication>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using Microsoft.UI.Xaml;
|
|
||||||
|
|
||||||
// To learn more about WinUI, the WinUI project structure,
|
|
||||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile.WinUI;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides application-specific behavior to supplement the default Application class.
|
|
||||||
/// </summary>
|
|
||||||
public partial class App : MauiWinUIApplication {
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the singleton application object. This is the first line of authored code
|
|
||||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
|
||||||
/// </summary>
|
|
||||||
public App() {
|
|
||||||
this.InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Package
|
|
||||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
|
||||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
|
||||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
|
||||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
|
||||||
IgnorableNamespaces="uap rescap">
|
|
||||||
|
|
||||||
<Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" />
|
|
||||||
|
|
||||||
<mp:PhoneIdentity PhoneProductId="1D7A4BF8-7BA9-4017-B89B-DBC4682E080F" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
|
||||||
|
|
||||||
<Properties>
|
|
||||||
<DisplayName>$placeholder$</DisplayName>
|
|
||||||
<PublisherDisplayName>User Name</PublisherDisplayName>
|
|
||||||
<Logo>$placeholder$.png</Logo>
|
|
||||||
</Properties>
|
|
||||||
|
|
||||||
<Dependencies>
|
|
||||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
|
||||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
|
||||||
</Dependencies>
|
|
||||||
|
|
||||||
<Resources>
|
|
||||||
<Resource Language="x-generate" />
|
|
||||||
</Resources>
|
|
||||||
|
|
||||||
<Applications>
|
|
||||||
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$">
|
|
||||||
<uap:VisualElements
|
|
||||||
DisplayName="$placeholder$"
|
|
||||||
Description="$placeholder$"
|
|
||||||
Square150x150Logo="$placeholder$.png"
|
|
||||||
Square44x44Logo="$placeholder$.png"
|
|
||||||
BackgroundColor="transparent">
|
|
||||||
<uap:DefaultTile Square71x71Logo="$placeholder$.png" Wide310x150Logo="$placeholder$.png" Square310x310Logo="$placeholder$.png" />
|
|
||||||
<uap:SplashScreen Image="$placeholder$.png" />
|
|
||||||
</uap:VisualElements>
|
|
||||||
</Application>
|
|
||||||
</Applications>
|
|
||||||
|
|
||||||
<Capabilities>
|
|
||||||
<rescap:Capability Name="runFullTrust" />
|
|
||||||
</Capabilities>
|
|
||||||
|
|
||||||
</Package>
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<assemblyIdentity version="1.0.0.0" name="WorkTime.Mobile.WinUI.app"/>
|
|
||||||
|
|
||||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
|
||||||
<windowsSettings>
|
|
||||||
<!-- The combination of below two tags have the following effect:
|
|
||||||
1) Per-Monitor for >= Windows 10 Anniversary Update
|
|
||||||
2) System < Windows 10 Anniversary Update
|
|
||||||
-->
|
|
||||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
|
|
||||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
|
|
||||||
</windowsSettings>
|
|
||||||
</application>
|
|
||||||
</assembly>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using Foundation;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
[Register("AppDelegate")]
|
|
||||||
public class AppDelegate : MauiUIApplicationDelegate {
|
|
||||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>LSRequiresIPhoneOS</key>
|
|
||||||
<true/>
|
|
||||||
<key>UIDeviceFamily</key>
|
|
||||||
<array>
|
|
||||||
<integer>1</integer>
|
|
||||||
<integer>2</integer>
|
|
||||||
</array>
|
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
|
||||||
<array>
|
|
||||||
<string>arm64</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>XSAppIconAssets</key>
|
|
||||||
<string>Assets.xcassets/appicon.appiconset</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using ObjCRuntime;
|
|
||||||
using UIKit;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile;
|
|
||||||
|
|
||||||
public class Program {
|
|
||||||
// This is the main entry point of the application.
|
|
||||||
static void Main(string[] args) {
|
|
||||||
// if you want to use a different Application Delegate class from "AppDelegate"
|
|
||||||
// you can specify it here.
|
|
||||||
UIApplication.Main(args, null, typeof(AppDelegate));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
This is the minimum required version of the Apple Privacy Manifest for .NET MAUI apps.
|
|
||||||
The contents below are needed because of APIs that are used in the .NET framework and .NET MAUI SDK.
|
|
||||||
|
|
||||||
You are responsible for adding extra entries as needed for your application.
|
|
||||||
|
|
||||||
More information: https://aka.ms/maui-privacy-manifest
|
|
||||||
-->
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyAccessedAPITypes</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyAccessedAPIType</key>
|
|
||||||
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
|
|
||||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
|
||||||
<array>
|
|
||||||
<string>C617.1</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyAccessedAPIType</key>
|
|
||||||
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
|
|
||||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
|
||||||
<array>
|
|
||||||
<string>35F9.1</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyAccessedAPIType</key>
|
|
||||||
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
|
|
||||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
|
||||||
<array>
|
|
||||||
<string>E174.1</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
<!--
|
|
||||||
The entry below is only needed when you're using the Preferences API in your app.
|
|
||||||
<dict>
|
|
||||||
<key>NSPrivacyAccessedAPIType</key>
|
|
||||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
|
||||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
|
||||||
<array>
|
|
||||||
<string>CA92.1</string>
|
|
||||||
</array>
|
|
||||||
</dict> -->
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"profiles": {
|
|
||||||
"Windows Machine": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"nativeDebugging": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using WorkTime.Shared.Models;
|
|
||||||
using WorkTime.Shared.Repositories;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile.Repositories;
|
|
||||||
|
|
||||||
public class ClientEntryRepository(DatabaseContext context) : IEntryRepository {
|
|
||||||
|
|
||||||
public async Task<TimeEntry[]> GetAllEntries(Guid owner) {
|
|
||||||
return await context.Entries
|
|
||||||
.Where(entry => entry.Owner == owner)
|
|
||||||
.OrderBy(entry => entry.Timestamp)
|
|
||||||
.ToArrayAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<TimeEntry[]> GetEntries(Guid owner, DateOnly date) {
|
|
||||||
return await context.Entries
|
|
||||||
.Where(entry => entry.Owner == owner)
|
|
||||||
.Where(entry => DateOnly.FromDateTime(entry.Timestamp) == date)
|
|
||||||
.OrderBy(entry => entry.Timestamp)
|
|
||||||
.ToArrayAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<TimeEntry?> GetEntry(int id) {
|
|
||||||
return await context.Entries
|
|
||||||
.FindAsync(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task AddEntry(TimeEntry entry) {
|
|
||||||
await context.Entries.AddAsync(entry);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteEntry(TimeEntry entry) {
|
|
||||||
context.Entries.Remove(entry);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ReplaceEntries(IEnumerable<TimeEntry> entries, DateOnly date) {
|
|
||||||
var oldEntries = await context.Entries
|
|
||||||
.Where(entry => DateOnly.FromDateTime(entry.Timestamp) == date)
|
|
||||||
.ToArrayAsync();
|
|
||||||
|
|
||||||
context.Entries.RemoveRange(oldEntries);
|
|
||||||
await context.Entries.AddRangeAsync(entries);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using WorkTime.Mobile.Services;
|
|
||||||
using WorkTime.Shared.Models;
|
|
||||||
using WorkTime.Shared.Repositories;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile.Repositories;
|
|
||||||
|
|
||||||
public class ServerEntryRepository(IHttpService client) : IEntryRepository {
|
|
||||||
|
|
||||||
public async Task<TimeEntry[]> GetAllEntries(Guid owner) {
|
|
||||||
var response = await client.SendRequest<TimeEntry[]>(HttpMethod.Get, $"entries/{owner}");
|
|
||||||
return response.Result ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<TimeEntry[]> GetEntries(Guid owner, DateOnly date) {
|
|
||||||
var response = await client.SendRequest<TimeEntry[]>(HttpMethod.Get, $"entries/{owner}/{date.ToDateTime(TimeOnly.MinValue)}");
|
|
||||||
return response.Result ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<TimeEntry?> GetEntry(int id) => Task.FromResult<TimeEntry?>(null);
|
|
||||||
|
|
||||||
public async Task AddEntry(TimeEntry entry) {
|
|
||||||
await client.SendRequest(HttpMethod.Post, "entries", entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteEntry(TimeEntry entry) {
|
|
||||||
await client.SendRequest(HttpMethod.Delete, $"entries/{entry.Id}");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<rect x="0" y="0" width="456" height="456" fill="#512BD4" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 228 B |
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
|
||||||
<path d="m 105.50037,281.60863 c -2.70293,0 -5.00091,-0.90042 -6.893127,-2.70209 -1.892214,-1.84778 -2.837901,-4.04181 -2.837901,-6.58209 0,-2.58722 0.945687,-4.80389 2.837901,-6.65167 1.892217,-1.84778 4.190197,-2.77167 6.893127,-2.77167 2.74819,0 5.06798,0.92389 6.96019,2.77167 1.93749,1.84778 2.90581,4.06445 2.90581,6.65167 0,2.54028 -0.96832,4.73431 -2.90581,6.58209 -1.89221,1.80167 -4.212,2.70209 -6.96019,2.70209 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
|
||||||
<path d="M 213.56111,280.08446 H 195.99044 L 149.69953,207.0544 c -1.17121,-1.84778 -2.14037,-3.76515 -2.90581,-5.75126 h -0.40578 c 0.36051,2.12528 0.54076,6.67515 0.54076,13.6496 v 65.13172 h -15.54349 v -99.36009 h 18.71925 l 44.7374,71.29798 c 1.89222,2.95695 3.1087,4.98917 3.64945,6.09751 h 0.26996 c -0.45021,-2.6325 -0.67573,-7.09015 -0.67573,-13.37293 v -64.02256 h 15.47557 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
|
||||||
<path d="m 289.25134,280.08446 h -54.40052 v -99.36009 h 52.23835 v 13.99669 h -36.15411 v 28.13085 h 33.31621 v 13.9271 h -33.31621 v 29.37835 h 38.31628 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
|
||||||
<path d="M 366.56466,194.72106 H 338.7222 v 85.3634 h -16.08423 v -85.3634 h -27.77455 v -13.99669 h 71.70124 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.8 KiB |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 91 KiB |
@@ -1,15 +0,0 @@
|
|||||||
Any raw assets you want to be deployed with your application can be placed in
|
|
||||||
this directory (and child directories). Deployment of the asset to your application
|
|
||||||
is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
|
|
||||||
|
|
||||||
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
|
|
||||||
|
|
||||||
These files will be deployed with your package and will be accessible using Essentials:
|
|
||||||
|
|
||||||
async Task LoadMauiAsset()
|
|
||||||
{
|
|
||||||
using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
|
|
||||||
using var reader = new StreamReader(stream);
|
|
||||||
|
|
||||||
var contents = reader.ReadToEnd();
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
|
||||||
<path d="m 105.50037,281.60863 c -2.70293,0 -5.00091,-0.90042 -6.893127,-2.70209 -1.892214,-1.84778 -2.837901,-4.04181 -2.837901,-6.58209 0,-2.58722 0.945687,-4.80389 2.837901,-6.65167 1.892217,-1.84778 4.190197,-2.77167 6.893127,-2.77167 2.74819,0 5.06798,0.92389 6.96019,2.77167 1.93749,1.84778 2.90581,4.06445 2.90581,6.65167 0,2.54028 -0.96832,4.73431 -2.90581,6.58209 -1.89221,1.80167 -4.212,2.70209 -6.96019,2.70209 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
|
||||||
<path d="M 213.56111,280.08446 H 195.99044 L 149.69953,207.0544 c -1.17121,-1.84778 -2.14037,-3.76515 -2.90581,-5.75126 h -0.40578 c 0.36051,2.12528 0.54076,6.67515 0.54076,13.6496 v 65.13172 h -15.54349 v -99.36009 h 18.71925 l 44.7374,71.29798 c 1.89222,2.95695 3.1087,4.98917 3.64945,6.09751 h 0.26996 c -0.45021,-2.6325 -0.67573,-7.09015 -0.67573,-13.37293 v -64.02256 h 15.47557 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
|
||||||
<path d="m 289.25134,280.08446 h -54.40052 v -99.36009 h 52.23835 v 13.99669 h -36.15411 v 28.13085 h 33.31621 v 13.9271 h -33.31621 v 29.37835 h 38.31628 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
|
||||||
<path d="M 366.56466,194.72106 H 338.7222 v 85.3634 h -16.08423 v -85.3634 h -27.77455 v -13.99669 h 71.70124 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,45 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<?xaml-comp compile="true" ?>
|
|
||||||
<ResourceDictionary
|
|
||||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
|
|
||||||
|
|
||||||
<!-- Note: For Android please see also Platforms\Android\Resources\values\colors.xml -->
|
|
||||||
|
|
||||||
<Color x:Key="Primary">#512BD4</Color>
|
|
||||||
<Color x:Key="PrimaryDark">#ac99ea</Color>
|
|
||||||
<Color x:Key="PrimaryDarkText">#242424</Color>
|
|
||||||
<Color x:Key="Secondary">#DFD8F7</Color>
|
|
||||||
<Color x:Key="SecondaryDarkText">#9880e5</Color>
|
|
||||||
<Color x:Key="Tertiary">#2B0B98</Color>
|
|
||||||
|
|
||||||
<Color x:Key="White">White</Color>
|
|
||||||
<Color x:Key="Black">Black</Color>
|
|
||||||
<Color x:Key="Magenta">#D600AA</Color>
|
|
||||||
<Color x:Key="MidnightBlue">#190649</Color>
|
|
||||||
<Color x:Key="OffBlack">#1f1f1f</Color>
|
|
||||||
|
|
||||||
<Color x:Key="Gray100">#E1E1E1</Color>
|
|
||||||
<Color x:Key="Gray200">#C8C8C8</Color>
|
|
||||||
<Color x:Key="Gray300">#ACACAC</Color>
|
|
||||||
<Color x:Key="Gray400">#919191</Color>
|
|
||||||
<Color x:Key="Gray500">#6E6E6E</Color>
|
|
||||||
<Color x:Key="Gray600">#404040</Color>
|
|
||||||
<Color x:Key="Gray900">#212121</Color>
|
|
||||||
<Color x:Key="Gray950">#141414</Color>
|
|
||||||
|
|
||||||
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}"/>
|
|
||||||
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}"/>
|
|
||||||
<SolidColorBrush x:Key="TertiaryBrush" Color="{StaticResource Tertiary}"/>
|
|
||||||
<SolidColorBrush x:Key="WhiteBrush" Color="{StaticResource White}"/>
|
|
||||||
<SolidColorBrush x:Key="BlackBrush" Color="{StaticResource Black}"/>
|
|
||||||
|
|
||||||
<SolidColorBrush x:Key="Gray100Brush" Color="{StaticResource Gray100}"/>
|
|
||||||
<SolidColorBrush x:Key="Gray200Brush" Color="{StaticResource Gray200}"/>
|
|
||||||
<SolidColorBrush x:Key="Gray300Brush" Color="{StaticResource Gray300}"/>
|
|
||||||
<SolidColorBrush x:Key="Gray400Brush" Color="{StaticResource Gray400}"/>
|
|
||||||
<SolidColorBrush x:Key="Gray500Brush" Color="{StaticResource Gray500}"/>
|
|
||||||
<SolidColorBrush x:Key="Gray600Brush" Color="{StaticResource Gray600}"/>
|
|
||||||
<SolidColorBrush x:Key="Gray900Brush" Color="{StaticResource Gray900}"/>
|
|
||||||
<SolidColorBrush x:Key="Gray950Brush" Color="{StaticResource Gray950}"/>
|
|
||||||
</ResourceDictionary>
|
|
||||||
@@ -1,451 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<?xaml-comp compile="true" ?>
|
|
||||||
<ResourceDictionary
|
|
||||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
|
|
||||||
|
|
||||||
<Style TargetType="ActivityIndicator">
|
|
||||||
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="IndicatorView">
|
|
||||||
<Setter Property="IndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}"/>
|
|
||||||
<Setter Property="SelectedIndicatorColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray100}}"/>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Border">
|
|
||||||
<Setter Property="Stroke" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
|
||||||
<Setter Property="StrokeShape" Value="Rectangle"/>
|
|
||||||
<Setter Property="StrokeThickness" Value="1"/>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="BoxView">
|
|
||||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Button">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource PrimaryDarkText}}" />
|
|
||||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource PrimaryDark}}" />
|
|
||||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
|
||||||
<Setter Property="FontSize" Value="14"/>
|
|
||||||
<Setter Property="BorderWidth" Value="0"/>
|
|
||||||
<Setter Property="CornerRadius" Value="8"/>
|
|
||||||
<Setter Property="Padding" Value="14,10"/>
|
|
||||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
|
||||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
|
|
||||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="PointerOver" />
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="CheckBox">
|
|
||||||
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
|
||||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="Color" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="DatePicker">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
|
||||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
|
||||||
<Setter Property="FontSize" Value="14"/>
|
|
||||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
|
||||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Editor">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
|
||||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
|
||||||
<Setter Property="FontSize" Value="14" />
|
|
||||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
|
||||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
|
||||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Entry">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
|
||||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
|
||||||
<Setter Property="FontSize" Value="14" />
|
|
||||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
|
||||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
|
||||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Frame">
|
|
||||||
<Setter Property="HasShadow" Value="False" />
|
|
||||||
<Setter Property="BorderColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
|
|
||||||
<Setter Property="CornerRadius" Value="8" />
|
|
||||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="ImageButton">
|
|
||||||
<Setter Property="Opacity" Value="1" />
|
|
||||||
<Setter Property="BorderColor" Value="Transparent"/>
|
|
||||||
<Setter Property="BorderWidth" Value="0"/>
|
|
||||||
<Setter Property="CornerRadius" Value="0"/>
|
|
||||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
|
||||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="Opacity" Value="0.5" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="PointerOver" />
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Label">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
|
||||||
<Setter Property="FontFamily" Value="OpenSansRegular" />
|
|
||||||
<Setter Property="FontSize" Value="14" />
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Span">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Label" x:Key="Headline">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource MidnightBlue}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="FontSize" Value="32" />
|
|
||||||
<Setter Property="HorizontalOptions" Value="Center" />
|
|
||||||
<Setter Property="HorizontalTextAlignment" Value="Center" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Label" x:Key="SubHeadline">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource MidnightBlue}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="FontSize" Value="24" />
|
|
||||||
<Setter Property="HorizontalOptions" Value="Center" />
|
|
||||||
<Setter Property="HorizontalTextAlignment" Value="Center" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="ListView">
|
|
||||||
<Setter Property="SeparatorColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray500}}" />
|
|
||||||
<Setter Property="RefreshControlColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Picker">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
|
|
||||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
|
||||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
|
||||||
<Setter Property="FontSize" Value="14" />
|
|
||||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
|
||||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
<Setter Property="TitleColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="ProgressBar">
|
|
||||||
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="ProgressColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="RadioButton">
|
|
||||||
<Setter Property="BackgroundColor" Value="Transparent"/>
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
|
||||||
<Setter Property="FontSize" Value="14"/>
|
|
||||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
|
||||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="RefreshView">
|
|
||||||
<Setter Property="RefreshColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="SearchBar">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
|
|
||||||
<Setter Property="CancelButtonColor" Value="{StaticResource Gray500}" />
|
|
||||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
|
||||||
<Setter Property="FontFamily" Value="OpenSansRegular" />
|
|
||||||
<Setter Property="FontSize" Value="14" />
|
|
||||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
|
||||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="SearchHandler">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="PlaceholderColor" Value="{StaticResource Gray500}" />
|
|
||||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
|
||||||
<Setter Property="FontFamily" Value="OpenSansRegular" />
|
|
||||||
<Setter Property="FontSize" Value="14" />
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
<Setter Property="PlaceholderColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Shadow">
|
|
||||||
<Setter Property="Radius" Value="15" />
|
|
||||||
<Setter Property="Opacity" Value="0.5" />
|
|
||||||
<Setter Property="Brush" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="Offset" Value="10,10" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Slider">
|
|
||||||
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
|
|
||||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="MinimumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
|
|
||||||
<Setter Property="MaximumTrackColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
|
|
||||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}"/>
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="SwipeItem">
|
|
||||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Switch">
|
|
||||||
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="ThumbColor" Value="{StaticResource White}" />
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="On">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="OnColor" Value="{AppThemeBinding Light={StaticResource Secondary}, Dark={StaticResource Gray200}}" />
|
|
||||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="Off">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="ThumbColor" Value="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="TimePicker">
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="BackgroundColor" Value="Transparent"/>
|
|
||||||
<Setter Property="FontFamily" Value="OpenSansRegular"/>
|
|
||||||
<Setter Property="FontSize" Value="14"/>
|
|
||||||
<Setter Property="MinimumHeightRequest" Value="44"/>
|
|
||||||
<Setter Property="MinimumWidthRequest" Value="44"/>
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Normal" />
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray300}, Dark={StaticResource Gray600}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<Style TargetType="TitleBar">
|
|
||||||
<Setter Property="MinimumHeightRequest" Value="32"/>
|
|
||||||
<Setter Property="VisualStateManager.VisualStateGroups">
|
|
||||||
<VisualStateGroupList>
|
|
||||||
<VisualStateGroup x:Name="TitleActiveStates">
|
|
||||||
<VisualState x:Name="TitleBarTitleActive">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
|
||||||
<Setter Property="ForegroundColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource White}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
<VisualState x:Name="TitleBarTitleInactive">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
|
|
||||||
<Setter Property="ForegroundColor" Value="{AppThemeBinding Light={StaticResource Gray400}, Dark={StaticResource Gray500}}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateGroupList>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<Style TargetType="Page" ApplyToDerivedTypes="True">
|
|
||||||
<Setter Property="Padding" Value="0"/>
|
|
||||||
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="Shell" ApplyToDerivedTypes="True">
|
|
||||||
<Setter Property="Shell.BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
|
|
||||||
<Setter Property="Shell.ForegroundColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
|
|
||||||
<Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
|
|
||||||
<Setter Property="Shell.DisabledColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
|
|
||||||
<Setter Property="Shell.UnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray200}}" />
|
|
||||||
<Setter Property="Shell.NavBarHasShadow" Value="False" />
|
|
||||||
<Setter Property="Shell.TabBarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
|
|
||||||
<Setter Property="Shell.TabBarForegroundColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="Shell.TabBarTitleColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="Shell.TabBarUnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="NavigationPage">
|
|
||||||
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
|
|
||||||
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="IconColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource White}}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="TabbedPage">
|
|
||||||
<Setter Property="BarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray950}}" />
|
|
||||||
<Setter Property="BarTextColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
|
|
||||||
<Setter Property="UnselectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
|
|
||||||
<Setter Property="SelectedTabColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
</ResourceDictionary>
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using WorkTime.Shared.Services;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile.Services;
|
|
||||||
|
|
||||||
public class AuthService(ISecureStorage storage, [FromKeyedServices("insecure")] IHttpService httpService) : IAuthService {
|
|
||||||
|
|
||||||
public async Task<bool> IsAuthenticated() {
|
|
||||||
var value = await storage.GetAsync(IAuthService.HeaderName);
|
|
||||||
return !string.IsNullOrWhiteSpace(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Guid> GetCurrentUserId() {
|
|
||||||
var value = await storage.GetAsync(IAuthService.HeaderName);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(value)) {
|
|
||||||
var response = await httpService.SendRequest<string>(HttpMethod.Get, "auth/register");
|
|
||||||
value = response.Result ?? Guid.NewGuid().ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Guid.Parse(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
using WorkTime.Mobile.Repositories;
|
|
||||||
using WorkTime.Shared.Models;
|
|
||||||
using WorkTime.Shared.Repositories;
|
|
||||||
using WorkTime.Shared.Services;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile.Services;
|
|
||||||
|
|
||||||
public class EntryService(
|
|
||||||
[FromKeyedServices("server")] IEntryRepository serverRepository,
|
|
||||||
[FromKeyedServices("client")] IEntryRepository clientRepository,
|
|
||||||
IAuthService authService) {
|
|
||||||
|
|
||||||
public async IAsyncEnumerable<UpdatingEntriesResponse> GetEntries(DateOnly date) {
|
|
||||||
var userId = await authService.GetCurrentUserId();
|
|
||||||
var clientEntries = await clientRepository.GetEntries(userId, date);
|
|
||||||
yield return new() {
|
|
||||||
NewBatch = true
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var entry in clientEntries) {
|
|
||||||
yield return new() {
|
|
||||||
Entry = entry
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var serverEntries = await serverRepository.GetEntries(userId, date);
|
|
||||||
if (serverEntries.Length == 0) yield break;
|
|
||||||
|
|
||||||
yield return new() {
|
|
||||||
NewBatch = true
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var entry in serverEntries) {
|
|
||||||
yield return new() {
|
|
||||||
Entry = entry
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
await ((ClientEntryRepository)clientRepository).ReplaceEntries(serverEntries, date);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task AddEntry(TimeEntry entry) {
|
|
||||||
var userId = await authService.GetCurrentUserId();
|
|
||||||
entry.Owner = userId;
|
|
||||||
|
|
||||||
await Task.WhenAll(
|
|
||||||
clientRepository.AddEntry(entry),
|
|
||||||
serverRepository.AddEntry(entry)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteEntry(TimeEntry entry) {
|
|
||||||
await Task.WhenAll(
|
|
||||||
clientRepository.DeleteEntry(entry),
|
|
||||||
serverRepository.DeleteEntry(entry)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct UpdatingEntriesResponse {
|
|
||||||
|
|
||||||
public bool NewBatch { get; init; }
|
|
||||||
|
|
||||||
public TimeEntry? Entry { get; init; }
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Net;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using WorkTime.Shared.Services;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile.Services;
|
|
||||||
|
|
||||||
public interface IHttpService {
|
|
||||||
Task<HttpResponse<TResult>> SendRequest<TResult>(HttpMethod method, [StringSyntax(StringSyntaxAttribute.Uri)] string uri, object? body = null);
|
|
||||||
|
|
||||||
Task<HttpResponse> SendRequest(HttpMethod method, [StringSyntax(StringSyntaxAttribute.Uri)] string uri, object? body = null);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class HttpService(HttpClient client, IAuthService authService) : IHttpService {
|
|
||||||
|
|
||||||
private InsecureHttpService? _service;
|
|
||||||
|
|
||||||
public async Task<HttpResponse<TResult>> SendRequest<TResult>(HttpMethod method, string uri, object? body = null) {
|
|
||||||
var service = await GetInternalService();
|
|
||||||
return await service.SendRequest<TResult>(method, uri, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<HttpResponse> SendRequest(HttpMethod method, string uri, object? body = null) {
|
|
||||||
var service = await GetInternalService();
|
|
||||||
return await service.SendRequest(method, uri, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<IHttpService> GetInternalService() {
|
|
||||||
if (_service is null) {
|
|
||||||
var id = await authService.GetCurrentUserId();
|
|
||||||
client.DefaultRequestHeaders.Add(IAuthService.HeaderName, id.ToString());
|
|
||||||
_service = new InsecureHttpService(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _service;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class InsecureHttpService(HttpClient client) : IHttpService {
|
|
||||||
|
|
||||||
public async Task<HttpResponse<TResult>> SendRequest<TResult>(HttpMethod method, string uri, object? body = null) {
|
|
||||||
try {
|
|
||||||
var request = new HttpRequestMessage(method, uri);
|
|
||||||
if (body is not null)
|
|
||||||
request.Content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
|
|
||||||
|
|
||||||
var response = await client.SendAsync(request);
|
|
||||||
var responseContent = await response.Content.ReadAsStringAsync();
|
|
||||||
|
|
||||||
return new HttpResponse<TResult> {
|
|
||||||
Result = typeof(TResult) == typeof(string) ? (TResult)(object)responseContent : JsonSerializer.Deserialize<TResult>(responseContent),
|
|
||||||
ResponseCode = response.StatusCode,
|
|
||||||
IsSuccessful = response.IsSuccessStatusCode
|
|
||||||
};
|
|
||||||
}
|
|
||||||
catch (Exception) {
|
|
||||||
return new() {
|
|
||||||
IsSuccessful = false,
|
|
||||||
ResponseCode = HttpStatusCode.InternalServerError
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<HttpResponse> SendRequest(HttpMethod method, string uri, object? body = null) {
|
|
||||||
try {
|
|
||||||
var request = new HttpRequestMessage(method, uri);
|
|
||||||
if (body is not null)
|
|
||||||
request.Content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
|
|
||||||
|
|
||||||
var response = await client.SendAsync(request);
|
|
||||||
|
|
||||||
return new HttpResponse {
|
|
||||||
ResponseCode = response.StatusCode,
|
|
||||||
IsSuccessful = response.IsSuccessStatusCode
|
|
||||||
};
|
|
||||||
}
|
|
||||||
catch (Exception) {
|
|
||||||
return new() {
|
|
||||||
IsSuccessful = false,
|
|
||||||
ResponseCode = HttpStatusCode.InternalServerError
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct HttpResponse<TResult> {
|
|
||||||
public TResult? Result { get; init; }
|
|
||||||
public HttpStatusCode ResponseCode { get; init; }
|
|
||||||
public bool IsSuccessful { get; init; }
|
|
||||||
|
|
||||||
public static implicit operator TResult?(HttpResponse<TResult> response) {
|
|
||||||
return response.Result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct HttpResponse {
|
|
||||||
public HttpStatusCode ResponseCode { get; init; }
|
|
||||||
public bool IsSuccessful { get; init; }
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
using System.Collections.ObjectModel;
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
|
||||||
using CommunityToolkit.Mvvm.Input;
|
|
||||||
using WorkTime.Mobile.Services;
|
|
||||||
using WorkTime.Shared.Models;
|
|
||||||
using WorkTime.Shared.Services;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile.ViewModels;
|
|
||||||
|
|
||||||
public partial class CaptureViewModel(EntryService entryService, IAuthService authService) : ObservableObject {
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public partial ObservableCollection<TimeEntry> Entries { get; set; } = new();
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public partial TimeEntryType CurrentAction { get; set; } = TimeEntryType.Login;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public partial bool CurrentlyMoba { get; set; }
|
|
||||||
|
|
||||||
public string CurrentActionName => CurrentAction.GetActionName();
|
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private async Task OnDateSelected(DateOnly date) {
|
|
||||||
await foreach (var entryResponse in entryService.GetEntries(date)) {
|
|
||||||
if (entryResponse.NewBatch)
|
|
||||||
Entries.Clear();
|
|
||||||
|
|
||||||
if (entryResponse.Entry is not null)
|
|
||||||
Entries.Add(entryResponse.Entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateCurrentAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private async Task RegisterEntry(TimeEntry? entry = null) {
|
|
||||||
entry ??= new TimeEntry {
|
|
||||||
Type = CurrentAction,
|
|
||||||
IsMoba = CurrentlyMoba,
|
|
||||||
Owner = await authService.GetCurrentUserId()
|
|
||||||
};
|
|
||||||
|
|
||||||
var insertIndex = Entries.Index()
|
|
||||||
.LastOrDefault(e => e.Item.Timestamp < entry.Timestamp)
|
|
||||||
.Index;
|
|
||||||
|
|
||||||
if (Entries.Count == insertIndex + 1 || Entries.Count == 0)
|
|
||||||
Entries.Add(entry);
|
|
||||||
else Entries.Insert(insertIndex + 1, entry);
|
|
||||||
|
|
||||||
await entryService.AddEntry(entry);
|
|
||||||
UpdateCurrentAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateCurrentAction() {
|
|
||||||
if (Entries.Count == 0) {
|
|
||||||
CurrentAction = TimeEntryType.Login;
|
|
||||||
CurrentlyMoba = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastEntry = Entries[^1];
|
|
||||||
CurrentAction = lastEntry.Type switch {
|
|
||||||
TimeEntryType.Login => TimeEntryType.Logout,
|
|
||||||
TimeEntryType.Logout => TimeEntryType.Login,
|
|
||||||
TimeEntryType.LoginDrive => TimeEntryType.LogoutDrive,
|
|
||||||
TimeEntryType.LogoutDrive => TimeEntryType.Login,
|
|
||||||
_ => TimeEntryType.Login
|
|
||||||
};
|
|
||||||
CurrentlyMoba = lastEntry is { Type: TimeEntryType.Login, IsMoba: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
partial void OnCurrentActionChanged(TimeEntryType value) {
|
|
||||||
OnPropertyChanged(nameof(CurrentActionName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
xmlns:components="clr-namespace:WorkTime.Mobile.Views.Components"
|
|
||||||
x:Class="WorkTime.Mobile.Views.Components.DateSelector"
|
|
||||||
x:DataType="components:DateSelector"
|
|
||||||
x:Name="Component">
|
|
||||||
|
|
||||||
<Grid ColumnDefinitions="*,Auto">
|
|
||||||
|
|
||||||
<Label
|
|
||||||
Grid.Column="0"
|
|
||||||
Text="Tag"
|
|
||||||
VerticalOptions="Center"/>
|
|
||||||
|
|
||||||
<DatePicker
|
|
||||||
Grid.Column="1"
|
|
||||||
Date="{Binding CurrentDate, Source={x:Reference Component}}"
|
|
||||||
MaximumDate="{Binding MaxDate, Source={x:Reference Component}}"
|
|
||||||
DateSelected="OnDateSelected"/>
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
</ContentView>
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
using CommunityToolkit.Mvvm.Input;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile.Views.Components;
|
|
||||||
|
|
||||||
public partial class DateSelector : ContentView {
|
|
||||||
|
|
||||||
public static readonly BindableProperty CurrentDateProperty = BindableProperty.Create(
|
|
||||||
nameof(CurrentDate),
|
|
||||||
typeof(DateTime),
|
|
||||||
typeof(DateSelector),
|
|
||||||
DateTime.Now);
|
|
||||||
|
|
||||||
public static readonly BindableProperty MaxDateProperty = BindableProperty.Create(
|
|
||||||
nameof(MaxDate),
|
|
||||||
typeof(DateTime),
|
|
||||||
typeof(DateSelector),
|
|
||||||
DateTime.Now);
|
|
||||||
|
|
||||||
public static readonly BindableProperty CommandProperty = BindableProperty.Create(
|
|
||||||
nameof(Command),
|
|
||||||
typeof(IRelayCommand<DateOnly>),
|
|
||||||
typeof(DateSelector));
|
|
||||||
|
|
||||||
public DateTime CurrentDate {
|
|
||||||
get => (DateTime)GetValue(CurrentDateProperty);
|
|
||||||
set => SetValue(CurrentDateProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTime MaxDate {
|
|
||||||
get => (DateTime)GetValue(MaxDateProperty);
|
|
||||||
set => SetValue(MaxDateProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IRelayCommand<DateOnly>? Command {
|
|
||||||
get => (IRelayCommand<DateOnly>)GetValue(CommandProperty);
|
|
||||||
set => SetValue(CommandProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateSelector() {
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDateSelected(object? sender, DateChangedEventArgs e) {
|
|
||||||
var date = DateOnly.FromDateTime(CurrentDate);
|
|
||||||
Command?.Execute(date);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
xmlns:components="clr-namespace:WorkTime.Mobile.Views.Components"
|
|
||||||
xmlns:viewModels="clr-namespace:WorkTime.Mobile.ViewModels"
|
|
||||||
xmlns:models="clr-namespace:WorkTime.Shared.Models;assembly=WorkTime.Shared"
|
|
||||||
x:Class="WorkTime.Mobile.Views.Pages.CapturePage"
|
|
||||||
x:DataType="viewModels:CaptureViewModel"
|
|
||||||
Padding="24, 0, 24, 24">
|
|
||||||
|
|
||||||
<Grid RowDefinitions="Auto,*,Auto">
|
|
||||||
|
|
||||||
<components:DateSelector
|
|
||||||
Grid.Row="0"
|
|
||||||
Command="{Binding DateSelectedCommand}"/>
|
|
||||||
|
|
||||||
<CollectionView
|
|
||||||
Grid.Row="1"
|
|
||||||
ItemsSource="{Binding Entries}">
|
|
||||||
<CollectionView.ItemTemplate>
|
|
||||||
<DataTemplate
|
|
||||||
x:DataType="models:TimeEntry">
|
|
||||||
<HorizontalStackLayout Spacing="5">
|
|
||||||
<Label Text="{Binding Timestamp}" />
|
|
||||||
<Label Text="{Binding Type}" />
|
|
||||||
</HorizontalStackLayout>
|
|
||||||
</DataTemplate>
|
|
||||||
</CollectionView.ItemTemplate>
|
|
||||||
</CollectionView>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
Grid.Row="2"
|
|
||||||
Text="{Binding CurrentActionName}"
|
|
||||||
Command="{Binding RegisterEntryCommand}"/>
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
</ContentPage>
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using WorkTime.Mobile.ViewModels;
|
|
||||||
|
|
||||||
namespace WorkTime.Mobile.Views.Pages;
|
|
||||||
|
|
||||||
public partial class CapturePage : ContentPage {
|
|
||||||
public CapturePage(CaptureViewModel model) {
|
|
||||||
InitializeComponent();
|
|
||||||
BindingContext = model;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks>
|
|
||||||
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net9.0-windows10.0.19041.0</TargetFrameworks>
|
|
||||||
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
|
|
||||||
<!-- <TargetFrameworks>$(TargetFrameworks);net9.0-tizen</TargetFrameworks> -->
|
|
||||||
|
|
||||||
<!-- Note for MacCatalyst:
|
|
||||||
The default runtime is maccatalyst-x64, except in Release config, in which case the default is maccatalyst-x64;maccatalyst-arm64.
|
|
||||||
When specifying both architectures, use the plural <RuntimeIdentifiers> instead of the singular <RuntimeIdentifier>.
|
|
||||||
The Mac App Store will NOT accept apps with ONLY maccatalyst-arm64 indicated;
|
|
||||||
either BOTH runtimes must be indicated or ONLY macatalyst-x64. -->
|
|
||||||
<!-- For example: <RuntimeIdentifiers>maccatalyst-x64;maccatalyst-arm64</RuntimeIdentifiers> -->
|
|
||||||
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<RootNamespace>WorkTime.Mobile</RootNamespace>
|
|
||||||
<UseMaui>true</UseMaui>
|
|
||||||
<SingleProject>true</SingleProject>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<LangVersion>preview</LangVersion>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
|
|
||||||
<!-- Display name -->
|
|
||||||
<ApplicationTitle>Zeiterfassung</ApplicationTitle>
|
|
||||||
|
|
||||||
<!-- App Identifier -->
|
|
||||||
<ApplicationId>de.leon-hoppe.worktime.mobile</ApplicationId>
|
|
||||||
|
|
||||||
<!-- Versions -->
|
|
||||||
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
|
|
||||||
<ApplicationVersion>1</ApplicationVersion>
|
|
||||||
|
|
||||||
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
|
|
||||||
<WindowsPackageType>None</WindowsPackageType>
|
|
||||||
|
|
||||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
|
|
||||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
|
|
||||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
|
|
||||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
|
|
||||||
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
|
|
||||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<!-- App Icon -->
|
|
||||||
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4"/>
|
|
||||||
|
|
||||||
<!-- Splash Screen -->
|
|
||||||
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128"/>
|
|
||||||
|
|
||||||
<!-- Images -->
|
|
||||||
<MauiImage Include="Resources\Images\*"/>
|
|
||||||
<MauiImage Update="Resources\Images\dotnet_bot.png" Resize="True" BaseSize="300,185"/>
|
|
||||||
|
|
||||||
<!-- Custom Fonts -->
|
|
||||||
<MauiFont Include="Resources\Fonts\*"/>
|
|
||||||
|
|
||||||
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
|
|
||||||
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="AathifMahir.Maui.MauiIcons.Material" Version="4.0.0" />
|
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.2" />
|
|
||||||
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)"/>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.0"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\WorkTime.Shared\WorkTime.Shared.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.ServiceDiscovery;
|
|
||||||
using OpenTelemetry;
|
|
||||||
using OpenTelemetry.Metrics;
|
|
||||||
using OpenTelemetry.Trace;
|
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Hosting;
|
|
||||||
|
|
||||||
// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
|
|
||||||
// This project should be referenced by each service project in your solution.
|
|
||||||
// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
|
|
||||||
public static class Extensions {
|
|
||||||
public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder)
|
|
||||||
where TBuilder : IHostApplicationBuilder {
|
|
||||||
builder.ConfigureOpenTelemetry();
|
|
||||||
|
|
||||||
builder.AddDefaultHealthChecks();
|
|
||||||
|
|
||||||
builder.Services.AddServiceDiscovery();
|
|
||||||
|
|
||||||
builder.Services.ConfigureHttpClientDefaults(http => {
|
|
||||||
// Turn on resilience by default
|
|
||||||
http.AddStandardResilienceHandler();
|
|
||||||
|
|
||||||
// Turn on service discovery by default
|
|
||||||
http.AddServiceDiscovery();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Uncomment the following to restrict the allowed schemes for service discovery.
|
|
||||||
// builder.Services.Configure<ServiceDiscoveryOptions>(options =>
|
|
||||||
// {
|
|
||||||
// options.AllowedSchemes = ["https"];
|
|
||||||
// });
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder builder)
|
|
||||||
where TBuilder : IHostApplicationBuilder {
|
|
||||||
builder.Logging.AddOpenTelemetry(logging => {
|
|
||||||
logging.IncludeFormattedMessage = true;
|
|
||||||
logging.IncludeScopes = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Services.AddOpenTelemetry()
|
|
||||||
.WithMetrics(metrics => {
|
|
||||||
metrics.AddAspNetCoreInstrumentation()
|
|
||||||
.AddHttpClientInstrumentation()
|
|
||||||
.AddRuntimeInstrumentation();
|
|
||||||
})
|
|
||||||
.WithTracing(tracing => {
|
|
||||||
tracing.AddSource(builder.Environment.ApplicationName)
|
|
||||||
.AddAspNetCoreInstrumentation()
|
|
||||||
// Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
|
|
||||||
//.AddGrpcClientInstrumentation()
|
|
||||||
.AddHttpClientInstrumentation();
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.AddOpenTelemetryExporters();
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuilder builder)
|
|
||||||
where TBuilder : IHostApplicationBuilder {
|
|
||||||
var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
|
|
||||||
|
|
||||||
if (useOtlpExporter) {
|
|
||||||
builder.Services.AddOpenTelemetry().UseOtlpExporter();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
|
|
||||||
//if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
|
|
||||||
//{
|
|
||||||
// builder.Services.AddOpenTelemetry()
|
|
||||||
// .UseAzureMonitor();
|
|
||||||
//}
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder builder)
|
|
||||||
where TBuilder : IHostApplicationBuilder {
|
|
||||||
builder.Services.AddHealthChecks()
|
|
||||||
// Add a default liveness check to ensure app is responsive
|
|
||||||
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static WebApplication MapDefaultEndpoints(this WebApplication app) {
|
|
||||||
// Adding health checks endpoints to applications in non-development environments has security implications.
|
|
||||||
// See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
|
|
||||||
if (app.Environment.IsDevelopment()) {
|
|
||||||
// All health checks must pass for app to be considered ready to accept traffic after starting
|
|
||||||
app.MapHealthChecks("/health");
|
|
||||||
|
|
||||||
// Only health checks tagged with the "live" tag must pass for app to be considered alive
|
|
||||||
app.MapHealthChecks("/alive", new HealthCheckOptions {
|
|
||||||
Predicate = r => r.Tags.Contains("live")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
|
|
||||||
namespace WorkTime.ServiceDefaults.Results;
|
|
||||||
|
|
||||||
public interface ILogicResult<TResult, TError> {
|
|
||||||
|
|
||||||
public TResult? Result { get; init; }
|
|
||||||
|
|
||||||
public TError? Error { get; init; }
|
|
||||||
|
|
||||||
public bool IsSuccessful => Result is not null && Error is null;
|
|
||||||
|
|
||||||
IResult MapResult();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ILogicResult<TResult> : ILogicResult<TResult, IResult>;
|
|
||||||
|
|
||||||
public interface ILogicResult : ILogicResult<object>;
|
|
||||||
|
|
||||||
public readonly struct LogicResult<TResult, TError> : ILogicResult<TResult, TError> {
|
|
||||||
|
|
||||||
public TResult? Result { get; init; }
|
|
||||||
public TError? Error { get; init; }
|
|
||||||
|
|
||||||
public bool IsSuccessful => Result is not null && Error is null;
|
|
||||||
|
|
||||||
public static implicit operator LogicResult<TResult, TError>(TResult result) {
|
|
||||||
return new LogicResult<TResult, TError> {
|
|
||||||
Result = result
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator LogicResult<TResult, TError>(TError error) {
|
|
||||||
return new LogicResult<TResult, TError> {
|
|
||||||
Error = error
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public IResult MapResult() {
|
|
||||||
if (!IsSuccessful)
|
|
||||||
return Microsoft.AspNetCore.Http.Results.Problem();
|
|
||||||
|
|
||||||
return Microsoft.AspNetCore.Http.Results.Ok(Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct LogicResult<TResult> : ILogicResult<TResult> {
|
|
||||||
|
|
||||||
public TResult? Result { get; init; }
|
|
||||||
public IResult? Error { get; init; }
|
|
||||||
|
|
||||||
public bool IsSuccessful => Error is null;
|
|
||||||
|
|
||||||
public static implicit operator LogicResult<TResult>(TResult result) {
|
|
||||||
return new LogicResult<TResult> {
|
|
||||||
Result = result
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogicResult() { }
|
|
||||||
|
|
||||||
public LogicResult(IResult error) {
|
|
||||||
Error = error;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IResult MapResult() {
|
|
||||||
if (!IsSuccessful) {
|
|
||||||
return Error!;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Microsoft.AspNetCore.Http.Results.Ok(Result);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct LogicResult : ILogicResult {
|
|
||||||
|
|
||||||
public object? Result { get; init; }
|
|
||||||
public IResult? Error { get; init; }
|
|
||||||
|
|
||||||
public bool IsSuccessful => Error is null;
|
|
||||||
|
|
||||||
public LogicResult() { }
|
|
||||||
|
|
||||||
public LogicResult(IResult error) {
|
|
||||||
Error = error;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IResult MapResult() {
|
|
||||||
if (!IsSuccessful) {
|
|
||||||
return Error!;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Microsoft.AspNetCore.Http.Results.Ok(Result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<IsAspireSharedProject>true</IsAspireSharedProject>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
|
|
||||||
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.0.0"/>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="9.0.0"/>
|
|
||||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0"/>
|
|
||||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0"/>
|
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0"/>
|
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0"/>
|
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace WorkTime.Shared.Models;
|
|
||||||
|
|
||||||
public class TimeEntry {
|
|
||||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
|
||||||
public int Id { get; set; }
|
|
||||||
|
|
||||||
public required Guid Owner { get; set; }
|
|
||||||
|
|
||||||
public required TimeEntryType Type { get; set; }
|
|
||||||
|
|
||||||
public DateTime Timestamp { get; set; } = DateTime.Now;
|
|
||||||
|
|
||||||
public bool IsMoba { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TimeEntryType {
|
|
||||||
Login,
|
|
||||||
Logout,
|
|
||||||
LoginDrive,
|
|
||||||
LogoutDrive
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using WorkTime.Shared.Models;
|
|
||||||
|
|
||||||
namespace WorkTime.Shared.Repositories;
|
|
||||||
|
|
||||||
public interface IEntryRepository {
|
|
||||||
|
|
||||||
Task<TimeEntry[]> GetAllEntries(Guid owner);
|
|
||||||
|
|
||||||
Task<TimeEntry[]> GetEntries(Guid owner, DateOnly date);
|
|
||||||
|
|
||||||
Task<TimeEntry?> GetEntry(int id);
|
|
||||||
|
|
||||||
Task AddEntry(TimeEntry entry);
|
|
||||||
|
|
||||||
Task DeleteEntry(TimeEntry entry);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
namespace WorkTime.Shared.Services;
|
|
||||||
|
|
||||||
public interface IAuthService {
|
|
||||||
|
|
||||||
public const string HeaderName = "Authentication";
|
|
||||||
|
|
||||||
public Task<bool> IsAuthenticated();
|
|
||||||
|
|
||||||
public Task<Guid> GetCurrentUserId();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.2" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user