diff --git a/.editorconfig b/.editorconfig
index d3ccf41..573bedd 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,107 +1,107 @@
-# Suppress: EC112
-# top-most EditorConfig file
-root = true
-
-# Don't use tabs for indentation.
-[*]
-indent_style = space
-# (Please don't specify an indent_size here; that has too many unintended consequences.)
-
-# Code files
-[*.{cs,csx,vb,vbx}]
-indent_size = 4
-
-# Xml project files
-[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
-indent_size = 2
-
-# Xml config files
-[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
-indent_size = 2
-
-# JSON files
-[*.json]
-indent_size = 2
-
-# Dotnet code style settings:
-[*.{cs,vb}]
-# Sort using and Import directives with System.* appearing first
-dotnet_sort_system_directives_first = false
-# Avoid "this." and "Me." if not necessary
-dotnet_style_qualification_for_field = false:suggestion
-dotnet_style_qualification_for_property = false:suggestion
-dotnet_style_qualification_for_method = false:suggestion
-dotnet_style_qualification_for_event = false:suggestion
-
-# Use language keywords instead of framework type names for type references
-dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
-dotnet_style_predefined_type_for_member_access = true:suggestion
-
-# Suggest more modern language features when available
-dotnet_style_object_initializer = true:suggestion
-dotnet_style_collection_initializer = true:suggestion
-dotnet_style_coalesce_expression = true:suggestion
-dotnet_style_null_propagation = true:suggestion
-dotnet_style_explicit_tuple_names = true:suggestion
-
-# Naming Conventions:
-# Pascal Casing
-dotnet_naming_symbols.method_and_property_symbols.applicable_kinds = method,property,enum
-dotnet_naming_symbols.method_and_property_symbols.applicable_accessibilities = *
-dotnet_naming_style.pascal_case_style.capitalization = pascal_case
-
-dotnet_naming_rule.methods_and_properties_must_be_pascal_case.severity = warning
-dotnet_naming_rule.methods_and_properties_must_be_pascal_case.symbols = method_and_property_symbols
-dotnet_naming_rule.methods_and_properties_must_be_pascal_case.style = pascal_case_style
-
-# Non-public members must be lower-case
-#dotnet_naming_symbols.non_public_symbols.applicable_kinds = property,event,delegate
-#dotnet_naming_symbols.non_public_symbols.applicable_accessibilities = private
-#dotnet_naming_style.all_lower_case_style.capitalization = camel_case
-
-#dotnet_naming_rule.non_public_members_must_be_lower_case.severity = warning
-#dotnet_naming_rule.non_public_members_must_be_lower_case.symbols = non_public_symbols
-#dotnet_naming_rule.non_public_members_must_be_lower_case.style = all_lower_case_style
-
-# Private fields must start with an underscore
-dotnet_naming_symbols.private_fields.applicable_kinds = field
-dotnet_naming_symbols.private_fields.applicable_accessibilities = private
-dotnet_naming_style.prefix_underscore.capitalization = camel_case
-dotnet_naming_style.prefix_underscore.required_prefix = _
-
-dotnet_naming_rule.private_members_with_underscore.severity = warning
-dotnet_naming_rule.private_members_with_underscore.symbols = private_fields
-dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
-
-# CSharp code style settings:
-[*.cs]
-# Do not prefer "var" everywhere
-csharp_style_var_for_built_in_types = true:suggestion
-csharp_style_var_when_type_is_apparent = true:suggestion
-csharp_style_var_elsewhere = true:suggestion
-
-# Prefer method-like constructs to have a block body
-csharp_style_expression_bodied_methods = true:suggestion
-csharp_style_expression_bodied_constructors = true:none
-csharp_style_expression_bodied_operators = true:none
-
-# Prefer property-like constructs to have an expression-body
-csharp_style_expression_bodied_properties = true:suggestion
-csharp_style_expression_bodied_indexers = true:none
-csharp_style_expression_bodied_accessors = true:none
-
-# Suggest more modern language features when available
-csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
-csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
-csharp_style_inlined_variable_declaration = true:suggestion
-csharp_style_throw_expression = true:suggestion
-csharp_style_conditional_delegate_call = true:suggestion
-
-# Newline settings
-csharp_new_line_before_open_brace = all
-csharp_new_line_before_else = true
-csharp_new_line_before_catch = true
-csharp_new_line_before_finally = true
-csharp_new_line_before_members_in_object_initializers = true
-csharp_new_line_before_members_in_anonymous_types = true
-
+# Suppress: EC112
+# top-most EditorConfig file
+root = true
+
+# Don't use tabs for indentation.
+[*]
+indent_style = space
+# (Please don't specify an indent_size here; that has too many unintended consequences.)
+
+# Code files
+[*.{cs,csx,vb,vbx}]
+indent_size = 4
+
+# Xml project files
+[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
+indent_size = 2
+
+# Xml config files
+[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
+indent_size = 2
+
+# JSON files
+[*.json]
+indent_size = 2
+
+# Dotnet code style settings:
+[*.{cs,vb}]
+# Sort using and Import directives with System.* appearing first
+dotnet_sort_system_directives_first = false
+# Avoid "this." and "Me." if not necessary
+dotnet_style_qualification_for_field = false:suggestion
+dotnet_style_qualification_for_property = false:suggestion
+dotnet_style_qualification_for_method = false:suggestion
+dotnet_style_qualification_for_event = false:suggestion
+
+# Use language keywords instead of framework type names for type references
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+# Suggest more modern language features when available
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+
+# Naming Conventions:
+# Pascal Casing
+dotnet_naming_symbols.method_and_property_symbols.applicable_kinds = method,property,enum
+dotnet_naming_symbols.method_and_property_symbols.applicable_accessibilities = *
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+
+dotnet_naming_rule.methods_and_properties_must_be_pascal_case.severity = warning
+dotnet_naming_rule.methods_and_properties_must_be_pascal_case.symbols = method_and_property_symbols
+dotnet_naming_rule.methods_and_properties_must_be_pascal_case.style = pascal_case_style
+
+# Non-public members must be lower-case
+#dotnet_naming_symbols.non_public_symbols.applicable_kinds = property,event,delegate
+#dotnet_naming_symbols.non_public_symbols.applicable_accessibilities = private
+#dotnet_naming_style.all_lower_case_style.capitalization = camel_case
+
+#dotnet_naming_rule.non_public_members_must_be_lower_case.severity = warning
+#dotnet_naming_rule.non_public_members_must_be_lower_case.symbols = non_public_symbols
+#dotnet_naming_rule.non_public_members_must_be_lower_case.style = all_lower_case_style
+
+# Private fields must start with an underscore
+dotnet_naming_symbols.private_fields.applicable_kinds = field
+dotnet_naming_symbols.private_fields.applicable_accessibilities = private
+dotnet_naming_style.prefix_underscore.capitalization = camel_case
+dotnet_naming_style.prefix_underscore.required_prefix = _
+
+dotnet_naming_rule.private_members_with_underscore.severity = warning
+dotnet_naming_rule.private_members_with_underscore.symbols = private_fields
+dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
+
+# CSharp code style settings:
+[*.cs]
+# Do not prefer "var" everywhere
+csharp_style_var_for_built_in_types = true:suggestion
+csharp_style_var_when_type_is_apparent = true:suggestion
+csharp_style_var_elsewhere = true:suggestion
+
+# Prefer method-like constructs to have a block body
+csharp_style_expression_bodied_methods = true:suggestion
+csharp_style_expression_bodied_constructors = true:none
+csharp_style_expression_bodied_operators = true:none
+
+# Prefer property-like constructs to have an expression-body
+csharp_style_expression_bodied_properties = true:suggestion
+csharp_style_expression_bodied_indexers = true:none
+csharp_style_expression_bodied_accessors = true:none
+
+# Suggest more modern language features when available
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Newline settings
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+
diff --git a/.gitignore b/.gitignore
index 44a55de..d1cd191 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,346 +1,346 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-##
-## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
-
-# User-specific files
-*.rsuser
-*.suo
-*.user
-*.userosscache
-*.sln.docstates
-
-# User-specific files (MonoDevelop/Xamarin Studio)
-*.userprefs
-
-# Build results
-[Dd]ebug/
-[Dd]ebugPublic/
-[Rr]elease/
-[Rr]eleases/
-x64/
-x86/
-[Aa][Rr][Mm]/
-[Aa][Rr][Mm]64/
-bld/
-[Bb]in/
-[Oo]bj/
-[Ll]og/
-
-# Visual Studio 2015/2017 cache/options directory
-.vs/
-# Uncomment if you have tasks that create the project's static files in wwwroot
-#wwwroot/
-
-# Visual Studio 2017 auto generated files
-Generated\ Files/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-# NUNIT
-*.VisualState.xml
-TestResult.xml
-
-# Build Results of an ATL Project
-[Dd]ebugPS/
-[Rr]eleasePS/
-dlldata.c
-
-# Benchmark Results
-BenchmarkDotNet.Artifacts/
-
-# .NET Core
-project.lock.json
-project.fragment.lock.json
-artifacts/
-
-# StyleCop
-StyleCopReport.xml
-
-# Files built by Visual Studio
-*_i.c
-*_p.c
-*_h.h
-*.ilk
-*.meta
-*.obj
-*.iobj
-*.pch
-*.pdb
-*.ipdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
-*_wpftmp.csproj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.svclog
-*.scc
-
-# Chutzpah Test files
-_Chutzpah*
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opendb
-*.opensdf
-*.sdf
-*.cachefile
-*.VC.db
-*.VC.VC.opendb
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-*.sap
-
-# Visual Studio Trace Files
-*.e2e
-
-# TFS 2012 Local Workspace
-$tf/
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-*.DotSettings.user
-
-# JustCode is a .NET coding add-in
-.JustCode
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# AxoCover is a Code Coverage Tool
-.axoCover/*
-!.axoCover/settings.json
-
-# Visual Studio code coverage results
-*.coverage
-*.coveragexml
-
-# NCrunch
-_NCrunch_*
-.*crunch*.local.xml
-nCrunchTemp_*
-
-# MightyMoose
-*.mm.*
-AutoTest.Net/
-
-# Web workbench (sass)
-.sass-cache/
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.[Pp]ublish.xml
-*.azurePubxml
-# Note: Comment the next line if you want to checkin your web deploy settings,
-# but database connection strings (with potential passwords) will be unencrypted
-*.pubxml
-*.publishproj
-
-# Microsoft Azure Web App publish settings. Comment the next line if you want to
-# checkin your Azure Web App publish settings, but sensitive information contained
-# in these scripts will be unencrypted
-PublishScripts/
-
-# NuGet Packages
-*.nupkg
-# The packages folder can be ignored because of Package Restore
-**/[Pp]ackages/*
-# except build/, which is used as an MSBuild target.
-!**/[Pp]ackages/build/
-# Uncomment if necessary however generally it will be regenerated when needed
-#!**/[Pp]ackages/repositories.config
-# NuGet v3's project.json files produces more ignorable files
-*.nuget.props
-*.nuget.targets
-
-# Microsoft Azure Build Output
-csx/
-*.build.csdef
-
-# Microsoft Azure Emulator
-ecf/
-rcf/
-
-# Windows Store app package directories and files
-AppPackages/
-BundleArtifacts/
-Package.StoreAssociation.xml
-_pkginfo.txt
-*.appx
-
-# Visual Studio cache files
-# files ending in .cache can be ignored
-*.[Cc]ache
-# but keep track of directories ending in .cache
-!?*.[Cc]ache/
-
-# Others
-ClientBin/
-~$*
-*~
-*.dbmdl
-*.dbproj.schemaview
-*.jfm
-*.pfx
-*.publishsettings
-orleans.codegen.cs
-
-# Including strong name files can present a security risk
-# (https://github.com/github/gitignore/pull/2483#issue-259490424)
-#*.snk
-
-# Since there are multiple workflows, uncomment next line to ignore bower_components
-# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
-#bower_components/
-# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
-**/wwwroot/lib/
-
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file
-# to a newer Visual Studio version. Backup files are not needed,
-# because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-ServiceFabricBackup/
-*.rptproj.bak
-
-# SQL Server files
-*.mdf
-*.ldf
-*.ndf
-
-# Business Intelligence projects
-*.rdl.data
-*.bim.layout
-*.bim_*.settings
-*.rptproj.rsuser
-
-# Microsoft Fakes
-FakesAssemblies/
-
-# GhostDoc plugin setting file
-*.GhostDoc.xml
-
-# Node.js Tools for Visual Studio
-.ntvs_analysis.dat
-node_modules/
-
-# Visual Studio 6 build log
-*.plg
-
-# Visual Studio 6 workspace options file
-*.opt
-
-# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
-*.vbw
-
-# Visual Studio LightSwitch build output
-**/*.HTMLClient/GeneratedArtifacts
-**/*.DesktopClient/GeneratedArtifacts
-**/*.DesktopClient/ModelManifest.xml
-**/*.Server/GeneratedArtifacts
-**/*.Server/ModelManifest.xml
-_Pvt_Extensions
-
-# Paket dependency manager
-.paket/paket.exe
-paket-files/
-
-# FAKE - F# Make
-.fake/
-
-# JetBrains Rider
-.idea/
-*.sln.iml
-
-# CodeRush personal settings
-.cr/personal
-
-# Python Tools for Visual Studio (PTVS)
-__pycache__/
-*.pyc
-
-# Cake - Uncomment if you are using it
-# tools/**
-# !tools/packages.config
-
-# Tabs Studio
-*.tss
-
-# Telerik's JustMock configuration file
-*.jmconfig
-
-# BizTalk build output
-*.btp.cs
-*.btm.cs
-*.odx.cs
-*.xsd.cs
-
-# OpenCover UI analysis results
-OpenCover/
-
-# Azure Stream Analytics local run output
-ASALocalRun/
-
-# MSBuild Binary and Structured Log
-*.binlog
-
-# NVidia Nsight GPU debugger configuration file
-*.nvuser
-
-# MFractors (Xamarin productivity tool) working folder
-.mfractor/
-
-# Local History for Visual Studio
-.localhistory/
-
-# BeatPulse healthcheck temp database
-healthchecksdb
-/src/WorkFlowCheck.API/Images
-*.pdf
-/src/WorkFlowCheck.API/Pdf/c86f3a6a-c646-4627-823c-7e24134b7725.docx
-/src/WorkFlowCheck.API/Downloads/APK/com.nuvolar.wfcapp-Signed.apk
-/src/WorkFlowCheck.API/Pdf/3b9fd83a-dce8-4427-813b-9475726700be.docx
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
+**/wwwroot/lib/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+/src/WorkFlowCheck.API/Images
+*.pdf
+/src/WorkFlowCheck.API/Pdf/c86f3a6a-c646-4627-823c-7e24134b7725.docx
+/src/WorkFlowCheck.API/Downloads/APK/com.nuvolar.wfcapp-Signed.apk
+/src/WorkFlowCheck.API/Pdf/3b9fd83a-dce8-4427-813b-9475726700be.docx
diff --git a/README.md b/README.md
index 014e816..d1ca251 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,20 @@
-#Introduction
-TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project.
-
-#Getting Started
-TODO: Guide users through getting your code up and running on their own system. In this section you can talk about:
-1. Installation process
-2. Software dependencies
-3. Latest releases
-4. API references
-
-#Build and Test
-TODO: Describe and show how to build your code and run the tests.
-
-#Contribute
-TODO: Explain how other users and developers can contribute to make your code better.
-
-If you want to learn more about creating good readme files then refer the following [guidelines](https://www.visualstudio.com/en-us/docs/git/create-a-readme). You can also seek inspiration from the below readme files:
-- [ASP.NET Core](https://github.com/aspnet/Home)
-- [Visual Studio Code](https://github.com/Microsoft/vscode)
+#Introduction
+TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project.
+
+#Getting Started
+TODO: Guide users through getting your code up and running on their own system. In this section you can talk about:
+1. Installation process
+2. Software dependencies
+3. Latest releases
+4. API references
+
+#Build and Test
+TODO: Describe and show how to build your code and run the tests.
+
+#Contribute
+TODO: Explain how other users and developers can contribute to make your code better.
+
+If you want to learn more about creating good readme files then refer the following [guidelines](https://www.visualstudio.com/en-us/docs/git/create-a-readme). You can also seek inspiration from the below readme files:
+- [ASP.NET Core](https://github.com/aspnet/Home)
+- [Visual Studio Code](https://github.com/Microsoft/vscode)
- [Chakra Core](https://github.com/Microsoft/ChakraCore)
\ No newline at end of file
diff --git a/src/Migration.cmd b/src/Migration.cmd
index fa262a1..cb59da1 100644
--- a/src/Migration.cmd
+++ b/src/Migration.cmd
@@ -1,5 +1,5 @@
-echo off
-echo "dotnet ef migrations add InitialCreate --project WorkFlowCheck.DL --startup-project WorkFlowCheck.API"
-echo "dotnet ef database update --project WorkFlowCheck.DL --startup-project WorkFlowCheck.API"
-echo "dotnet ef migrations remove --project WorkFlowCheck.DL --startup-project WorkFlowCheck.API"
-pause
+echo off
+echo "dotnet ef migrations add InitialCreate --project WorkFlowCheck.DL --startup-project WorkFlowCheck.API"
+echo "dotnet ef database update --project WorkFlowCheck.DL --startup-project WorkFlowCheck.API"
+echo "dotnet ef migrations remove --project WorkFlowCheck.DL --startup-project WorkFlowCheck.API"
+pause
diff --git a/src/Plugin.NFC/Android/CrossNFC.android.cs b/src/Plugin.NFC/Android/CrossNFC.android.cs
index 44a932b..2b61c16 100644
--- a/src/Plugin.NFC/Android/CrossNFC.android.cs
+++ b/src/Plugin.NFC/Android/CrossNFC.android.cs
@@ -1,90 +1,90 @@
-using Android.App;
-using Android.Content;
-using Android.OS;
-using System;
-
-namespace Plugin.NFC
-{
- ///
- /// Cross NFC (Android specific)
- ///
- public static partial class CrossNFC
- {
- internal static ActivityLifecycleContextListener lifecycleListener;
-
- ///
- /// Initialization
- ///
- /// Android
- public static void Init(Application application)
- {
- if (lifecycleListener != null) return;
- lifecycleListener = new ActivityLifecycleContextListener();
- application.RegisterActivityLifecycleCallbacks(lifecycleListener);
- }
-
- ///
- /// Initialization
- ///
- /// Android
- public static void Init(Activity activity)
- {
- Init(activity.Application);
- lifecycleListener.Activity = activity;
- }
-
- ///
- /// Overrides Activity.OnNewIntent()
- ///
- /// Android
- public static void OnNewIntent(Intent intent) => ((NFCImplementation)Current).HandleNewIntent(intent);
-
- ///
- /// Overrides Activity.OnResume()
- ///
- public static void OnResume() => ((NFCImplementation)Current).HandleOnResume();
-
- ///
- /// Returns the current Android
- ///
- internal static Context AppContext => Application.Context;
-
- ///
- /// Returns the current Android
- ///
- ///
- ///
- internal static Activity GetCurrentActivity(bool throwError)
- {
- var activity = lifecycleListener?.Activity;
- if (throwError && activity == null)
- throw new NullReferenceException("The current Activity can not be detected. Ensure that you have called Init in your Activity or Application class.");
- return activity;
- }
- }
-
- ///
- /// James Montemagno's ActivityLifecycleContextListener from CurrentActivityPlugin
- ///
- ///
- class ActivityLifecycleContextListener : Java.Lang.Object, Application.IActivityLifecycleCallbacks
- {
- WeakReference _currentActivity = new WeakReference(null);
-
- internal Context Context => Activity ?? Application.Context;
-
- internal Activity Activity
- {
- get => _currentActivity.TryGetTarget(out var a) ? a : null;
- set => _currentActivity.SetTarget(value);
- }
-
- void Application.IActivityLifecycleCallbacks.OnActivityCreated(Activity activity, Bundle savedInstanceState) => Activity = activity;
- void Application.IActivityLifecycleCallbacks.OnActivityDestroyed(Activity activity) { }
- void Application.IActivityLifecycleCallbacks.OnActivityPaused(Activity activity) => Activity = activity;
- void Application.IActivityLifecycleCallbacks.OnActivityResumed(Activity activity) => Activity = activity;
- void Application.IActivityLifecycleCallbacks.OnActivitySaveInstanceState(Activity activity, Bundle outState) { }
- void Application.IActivityLifecycleCallbacks.OnActivityStarted(Activity activity) { }
- void Application.IActivityLifecycleCallbacks.OnActivityStopped(Activity activity) { }
- }
-}
+using Android.App;
+using Android.Content;
+using Android.OS;
+using System;
+
+namespace Plugin.NFC
+{
+ ///
+ /// Cross NFC (Android specific)
+ ///
+ public static partial class CrossNFC
+ {
+ internal static ActivityLifecycleContextListener lifecycleListener;
+
+ ///
+ /// Initialization
+ ///
+ /// Android
+ public static void Init(Application application)
+ {
+ if (lifecycleListener != null) return;
+ lifecycleListener = new ActivityLifecycleContextListener();
+ application.RegisterActivityLifecycleCallbacks(lifecycleListener);
+ }
+
+ ///
+ /// Initialization
+ ///
+ /// Android
+ public static void Init(Activity activity)
+ {
+ Init(activity.Application);
+ lifecycleListener.Activity = activity;
+ }
+
+ ///
+ /// Overrides Activity.OnNewIntent()
+ ///
+ /// Android
+ public static void OnNewIntent(Intent intent) => ((NFCImplementation)Current).HandleNewIntent(intent);
+
+ ///
+ /// Overrides Activity.OnResume()
+ ///
+ public static void OnResume() => ((NFCImplementation)Current).HandleOnResume();
+
+ ///
+ /// Returns the current Android
+ ///
+ internal static Context AppContext => Application.Context;
+
+ ///
+ /// Returns the current Android
+ ///
+ ///
+ ///
+ internal static Activity GetCurrentActivity(bool throwError)
+ {
+ var activity = lifecycleListener?.Activity;
+ if (throwError && activity == null)
+ throw new NullReferenceException("The current Activity can not be detected. Ensure that you have called Init in your Activity or Application class.");
+ return activity;
+ }
+ }
+
+ ///
+ /// James Montemagno's ActivityLifecycleContextListener from CurrentActivityPlugin
+ ///
+ ///
+ class ActivityLifecycleContextListener : Java.Lang.Object, Application.IActivityLifecycleCallbacks
+ {
+ WeakReference _currentActivity = new WeakReference(null);
+
+ internal Context Context => Activity ?? Application.Context;
+
+ internal Activity Activity
+ {
+ get => _currentActivity.TryGetTarget(out var a) ? a : null;
+ set => _currentActivity.SetTarget(value);
+ }
+
+ void Application.IActivityLifecycleCallbacks.OnActivityCreated(Activity activity, Bundle savedInstanceState) => Activity = activity;
+ void Application.IActivityLifecycleCallbacks.OnActivityDestroyed(Activity activity) { }
+ void Application.IActivityLifecycleCallbacks.OnActivityPaused(Activity activity) => Activity = activity;
+ void Application.IActivityLifecycleCallbacks.OnActivityResumed(Activity activity) => Activity = activity;
+ void Application.IActivityLifecycleCallbacks.OnActivitySaveInstanceState(Activity activity, Bundle outState) { }
+ void Application.IActivityLifecycleCallbacks.OnActivityStarted(Activity activity) { }
+ void Application.IActivityLifecycleCallbacks.OnActivityStopped(Activity activity) { }
+ }
+}
diff --git a/src/Plugin.NFC/Android/NFC.android.cs b/src/Plugin.NFC/Android/NFC.android.cs
index da90162..466d091 100644
--- a/src/Plugin.NFC/Android/NFC.android.cs
+++ b/src/Plugin.NFC/Android/NFC.android.cs
@@ -1,570 +1,570 @@
-using Android;
-using Android.App;
-using Android.Content;
-using Android.Nfc;
-using Android.Nfc.Tech;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Plugin.NFC
-{
- ///
- /// Android implementation of
- ///
- public class NFCImplementation : INFC
- {
- public event EventHandler OnTagConnected;
- public event EventHandler OnTagDisconnected;
- public event NdefMessageReceivedEventHandler OnMessageReceived;
- public event NdefMessagePublishedEventHandler OnMessagePublished;
- public event TagDiscoveredEventHandler OnTagDiscovered;
- public event EventHandler OniOSReadingSessionCancelled;
- public event TagListeningStatusChangedEventHandler OnTagListeningStatusChanged;
-
- readonly NfcAdapter _nfcAdapter;
-
- bool _isListening;
- bool _isWriting;
- bool _isFormatting;
- Tag _currentTag;
-
- ///
- /// Current Android
- ///
- Context CurrentContext => CrossNFC.AppContext;
-
- ///
- /// Current Android
- ///
- Activity CurrentActivity => CrossNFC.GetCurrentActivity(true);
-
- ///
- /// Checks if NFC Feature is available
- ///
- public bool IsAvailable
- {
- get
- {
- if (CurrentContext.CheckCallingOrSelfPermission(Manifest.Permission.Nfc) != Android.Content.PM.Permission.Granted)
- return false;
- return _nfcAdapter != null;
- }
- }
-
- ///
- /// Checks if NFC Feature is enabled
- ///
- public bool IsEnabled => IsAvailable && _nfcAdapter.IsEnabled;
-
- ///
- /// Checks if writing mode is supported
- ///
- public bool IsWritingTagSupported => NFCUtils.IsWritingSupported();
-
- ///
- /// NFC configuration
- ///
- public NfcConfiguration Configuration { get; private set; }
-
- ///
- /// Default constructor
- ///
- public NFCImplementation()
- {
- _nfcAdapter = NfcAdapter.GetDefaultAdapter(CurrentContext);
- Configuration = NfcConfiguration.GetDefaultConfiguration();
- }
-
- ///
- /// Update NFC configuration
- ///
- ///
- public void SetConfiguration(NfcConfiguration configuration) => Configuration.Update(configuration);
-
- ///
- /// Starts tags detection
- ///
- public void StartListening()
- {
- if (_nfcAdapter == null)
- return;
-
- var intent = new Intent(CurrentActivity, CurrentActivity.GetType()).AddFlags(ActivityFlags.SingleTop);
-
- // We don't use MonoAndroid12.0 as targetframework for easier backward compatibility:
- // MonoAndroid12.0 needs JDK 11.
- PendingIntentFlags pendingIntentFlags = 0;
-
-#if NET6_0_OR_GREATER
- if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.S)
- pendingIntentFlags = PendingIntentFlags.Mutable;
-#else
- if ((int)Android.OS.Build.VERSION.SdkInt >= 31) //Android.OS.BuildVersionCodes.S
- pendingIntentFlags = (PendingIntentFlags)33554432; //PendingIntentFlags.Mutable
-#endif
-
- var pendingIntent = PendingIntent.GetActivity(CurrentActivity, 0, intent, pendingIntentFlags);
-
- var ndefFilter = new IntentFilter(NfcAdapter.ActionNdefDiscovered);
- ndefFilter.AddDataType("*/*");
-
- var tagFilter = new IntentFilter(NfcAdapter.ActionTagDiscovered);
- tagFilter.AddCategory(Intent.CategoryDefault);
-
- var filters = new IntentFilter[] { ndefFilter, tagFilter };
-
- _nfcAdapter.EnableForegroundDispatch(CurrentActivity, pendingIntent, filters, null);
-
- _isListening = true;
- OnTagListeningStatusChanged?.Invoke(_isListening);
- }
-
- ///
- /// Stops tags detection
- ///
- public void StopListening()
- {
- DisablePublishing();
- if (_nfcAdapter != null)
- _nfcAdapter.DisableForegroundDispatch(CurrentActivity);
-
- _isListening = false;
- OnTagListeningStatusChanged?.Invoke(_isListening);
- }
-
- ///
- /// Starts tag publishing (writing or formatting)
- ///
- /// Format tag
- public void StartPublishing(bool clearMessage = false)
- {
- if (!IsWritingTagSupported)
- return;
-
- _isWriting = true;
- _isFormatting = clearMessage;
- }
-
- ///
- /// Stops tag publishing
- ///
- public void StopPublishing() => DisablePublishing();
-
- ///
- /// Publish or write a message on a tag
- ///
- /// see
- /// make tag read-only
- public void PublishMessage(ITagInfo tagInfo, bool makeReadOnly = false) => WriteOrClearMessage(tagInfo, false, makeReadOnly);
-
- ///
- /// Format tag
- ///
- /// see
- public void ClearMessage(ITagInfo tagInfo) => WriteOrClearMessage(tagInfo, true);
-
- ///
- /// Write or Clear a NDEF message
- ///
- ///
- /// Clear Message
- /// Make tag read-only
- internal void WriteOrClearMessage(ITagInfo tagInfo, bool clearMessage = false, bool makeReadOnly = false)
- {
- try
- {
- if (_currentTag == null)
- throw new Exception(Configuration.Messages.NFCErrorMissingTag);
-
- if (tagInfo == null)
- throw new Exception(Configuration.Messages.NFCErrorMissingTagInfo);
-
- var ndef = Ndef.Get(_currentTag);
- if (ndef != null)
- {
- try
- {
- if (!ndef.IsWritable)
- throw new Exception(Configuration.Messages.NFCErrorReadOnlyTag);
-
- if (ndef.MaxSize < NFCUtils.GetSize(tagInfo.Records))
- throw new Exception(Configuration.Messages.NFCErrorCapacityTag);
-
- ndef.Connect();
- OnTagConnected?.Invoke(null, EventArgs.Empty);
-
- NdefMessage message = null;
- if (clearMessage)
- {
- message = GetEmptyNdefMessage();
- }
- else
- {
- var records = new List();
- for (var i = 0; i < tagInfo.Records.Length; i++)
- {
- var record = tagInfo.Records[i];
- if (GetAndroidNdefRecord(record) is NdefRecord ndefRecord)
- records.Add(ndefRecord);
- }
-
- if (records.Any())
- message = new NdefMessage(records.ToArray());
- }
-
- if (message != null)
- {
- ndef.WriteNdefMessage(message);
-
- if (!clearMessage && makeReadOnly)
- {
- if (!MakeReadOnly(ndef))
- Console.WriteLine("Cannot lock tag");
- }
-
- var nTag = GetTagInfo(_currentTag, ndef.NdefMessage);
- OnMessagePublished?.Invoke(nTag);
- }
- else
- throw new Exception(Configuration.Messages.NFCErrorWrite);
- }
- catch (Android.Nfc.TagLostException tlex)
- {
- throw new Exception("Tag Lost Error: " + tlex.Message);
- }
- catch (Java.IO.IOException ioex)
- {
- throw new Exception("Tag IO Error: " + ioex.Message);
- }
- catch (Android.Nfc.FormatException fe)
- {
- throw new Exception("Tag Format Error: " + fe.Message);
- }
- catch (Exception ex)
- {
- throw new Exception("Tag Error:" + ex.Message);
- }
- finally
- {
- if (ndef.IsConnected)
- ndef.Close();
-
- _currentTag = null;
- OnTagDisconnected?.Invoke(null, EventArgs.Empty);
- }
- }
- else
- throw new Exception(Configuration.Messages.NFCErrorNotCompliantTag);
- }
- catch (Exception ex)
- {
- StopPublishingAndThrowError(ex.Message);
- }
- }
-
- ///
- /// Handle Android OnNewIntent
- ///
- /// Android
- internal void HandleNewIntent(Intent intent)
- {
- if (intent == null)
- return;
-
- if (intent.Action == NfcAdapter.ActionTagDiscovered || intent.Action == NfcAdapter.ActionNdefDiscovered)
- {
- _currentTag = intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;
- if (_currentTag != null)
- {
- var nTag = GetTagInfo(_currentTag);
- if (_isWriting)
- {
- // Write mode
- OnTagDiscovered?.Invoke(nTag, _isFormatting);
- }
- else
- {
- // Read mode
- OnMessageReceived?.Invoke(nTag);
- }
- }
- }
- }
-
- ///
- /// Handle Android OnResume
- ///
- internal void HandleOnResume()
- {
- // Android 10 fix:
- // If listening mode is already enable, we restart listening when activity is resumed
- if (_isListening)
- StartListening();
- }
-
- #region Private
-
- ///
- /// Stops publishing and throws error
- ///
- /// message
- void StopPublishingAndThrowError(string message)
- {
- StopPublishing();
- throw new Exception(message);
- }
-
- ///
- /// Deactivate publishing
- ///
- void DisablePublishing()
- {
- _isWriting = false;
- _isFormatting = false;
- }
-
- ///
- /// Transforms an array of into an array of
- ///
- /// Array of
- /// Array of
- NFCNdefRecord[] GetRecords(NdefRecord[] records)
- {
- var results = new NFCNdefRecord[records.Length];
- for (var i = 0; i < records.Length; i++)
- {
- var ndefRecord = new NFCNdefRecord
- {
- TypeFormat = (NFCNdefTypeFormat)records[i].Tnf,
- Uri = records[i].ToUri()?.ToString(),
- MimeType = records[i].ToMimeType(),
- Payload = records[i].GetPayload()
- };
- results.SetValue(ndefRecord, i);
- }
- return results;
- }
-
- ///
- /// Returns informations contains in NFC Tag
- ///
- /// Android
- /// Android
- ///
- ITagInfo GetTagInfo(Tag tag, NdefMessage ndefMessage = null)
- {
- if (tag == null)
- return null;
-
- var ndef = Ndef.Get(tag);
- var nTag = new TagInfo(tag.GetId(), ndef != null);
-
- if (ndef != null)
- {
- nTag.Capacity = ndef.MaxSize;
- nTag.IsWritable = ndef.IsWritable;
-
- if (ndefMessage == null)
- ndefMessage = ndef.CachedNdefMessage;
-
- if (ndefMessage != null)
- {
- var records = ndefMessage.GetRecords();
- nTag.Records = GetRecords(records);
- }
- }
-
- return nTag;
- }
-
- ///
- /// Transforms a into an Android
- ///
- /// Object
- /// Android
- NdefRecord GetAndroidNdefRecord(NFCNdefRecord record)
- {
- if (record == null)
- return null;
-
- NdefRecord ndefRecord = null;
- switch (record.TypeFormat)
- {
- case NFCNdefTypeFormat.WellKnown:
- var languageCode = record.LanguageCode;
- if (string.IsNullOrWhiteSpace(languageCode)) languageCode = Configuration.DefaultLanguageCode;
- ndefRecord = NdefRecord.CreateTextRecord(languageCode.Substring(0, 2), Encoding.UTF8.GetString(record.Payload));
- break;
- case NFCNdefTypeFormat.Mime:
- ndefRecord = NdefRecord.CreateMime(record.MimeType, record.Payload);
- break;
- case NFCNdefTypeFormat.Uri:
- ndefRecord = NdefRecord.CreateUri(Encoding.UTF8.GetString(record.Payload));
- break;
- case NFCNdefTypeFormat.External:
- ndefRecord = NdefRecord.CreateExternal(record.ExternalDomain, record.ExternalType, record.Payload);
- break;
- case NFCNdefTypeFormat.Empty:
- ndefRecord = GetEmptyNdefRecord();
- break;
- case NFCNdefTypeFormat.Unknown:
- case NFCNdefTypeFormat.Unchanged:
- case NFCNdefTypeFormat.Reserved:
- default:
- break;
-
- }
- return ndefRecord;
- }
-
- ///
- /// Returns an empty Android
- ///
- /// Android
- NdefRecord GetEmptyNdefRecord()
- {
- var empty = Array.Empty();
- return new NdefRecord(NdefRecord.TnfEmpty, empty, empty, empty);
- }
-
- ///
- /// Returns an empty Android
- ///
- /// Android
- NdefMessage GetEmptyNdefMessage()
- {
- var records = new NdefRecord[1];
- records[0] = GetEmptyNdefRecord();
- return new NdefMessage(records);
- }
-
- ///
- /// Make a tag read-only
- /// WARNING: This operation is permanent
- ///
- ///
- /// boolean
- bool MakeReadOnly(Ndef ndef)
- {
- if (ndef == null)
- return false;
-
- var result = false;
- var newConnection = false;
-
- if (!ndef.IsConnected)
- {
- newConnection = true;
- ndef.Connect();
- }
-
- if (ndef.CanMakeReadOnly())
- result = ndef.MakeReadOnly();
-
- if (newConnection && ndef.IsConnected)
- ndef.Close();
-
- return result;
- }
-
- #endregion
-
- #region NFC Status Event Listener
-
- NfcBroadcastReceiver _nfcBroadcastReceiver;
-
- event OnNfcStatusChangedEventHandler _onNfcStatusChangedInternal;
-
- public event OnNfcStatusChangedEventHandler OnNfcStatusChanged
- {
- add
- {
- var wasRunning = _onNfcStatusChangedInternal != null;
- _onNfcStatusChangedInternal += value;
- if (!wasRunning && _onNfcStatusChangedInternal != null)
- {
- RegisterListener();
- }
- }
- remove
- {
- var wasRunning = _onNfcStatusChangedInternal != null;
- _onNfcStatusChangedInternal -= value;
- if (wasRunning && _onNfcStatusChangedInternal == null)
- {
- UnRegisterListener();
- }
- }
- }
-
- ///
- /// Register NFC Broadcast Receiver
- ///
- void RegisterListener()
- {
- _nfcBroadcastReceiver = new NfcBroadcastReceiver(OnNfcStatusChange);
- CurrentContext?.RegisterReceiver(_nfcBroadcastReceiver, new IntentFilter(NfcAdapter.ActionAdapterStateChanged));
- }
-
- ///
- /// Unregister NFC Broadcast Receiver
- ///
- void UnRegisterListener()
- {
- if (_nfcBroadcastReceiver == null)
- return;
-
- try
- {
- CurrentContext?.UnregisterReceiver(_nfcBroadcastReceiver);
- }
- catch (Java.Lang.IllegalArgumentException ex)
- {
- throw new Exception("NFC Broadcast Receiver Error: " + ex.Message);
- }
-
- _nfcBroadcastReceiver.Dispose();
- _nfcBroadcastReceiver = null;
- }
-
- ///
- /// Called when NFC status has changed
- ///
- void OnNfcStatusChange() => _onNfcStatusChangedInternal?.Invoke(IsEnabled);
-
- ///
- /// Broadcast Receiver to check NFC feature availability
- ///
- [BroadcastReceiver(Enabled = true, Exported = false, Label = "NFC Status Broadcast Receiver")]
- class NfcBroadcastReceiver : BroadcastReceiver
- {
- Action _onChanged;
-
- public NfcBroadcastReceiver() { }
- public NfcBroadcastReceiver(Action onChanged)
- {
- _onChanged = onChanged;
- }
-
- public override async void OnReceive(Context context, Intent intent)
- {
- if (intent.Action == NfcAdapter.ActionAdapterStateChanged)
- {
- var state = intent.GetIntExtra(NfcAdapter.ExtraAdapterState, default);
- if (state == NfcAdapter.StateOff || state == NfcAdapter.StateOn)
- {
- // await 1500ms to ensure that the status updates
- await Task.Delay(1500);
- _onChanged?.Invoke();
- }
- }
- }
- }
-
- #endregion
-
- }
-}
+using Android;
+using Android.App;
+using Android.Content;
+using Android.Nfc;
+using Android.Nfc.Tech;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Plugin.NFC
+{
+ ///
+ /// Android implementation of
+ ///
+ public class NFCImplementation : INFC
+ {
+ public event EventHandler OnTagConnected;
+ public event EventHandler OnTagDisconnected;
+ public event NdefMessageReceivedEventHandler OnMessageReceived;
+ public event NdefMessagePublishedEventHandler OnMessagePublished;
+ public event TagDiscoveredEventHandler OnTagDiscovered;
+ public event EventHandler OniOSReadingSessionCancelled;
+ public event TagListeningStatusChangedEventHandler OnTagListeningStatusChanged;
+
+ readonly NfcAdapter _nfcAdapter;
+
+ bool _isListening;
+ bool _isWriting;
+ bool _isFormatting;
+ Tag _currentTag;
+
+ ///
+ /// Current Android
+ ///
+ Context CurrentContext => CrossNFC.AppContext;
+
+ ///
+ /// Current Android
+ ///
+ Activity CurrentActivity => CrossNFC.GetCurrentActivity(true);
+
+ ///
+ /// Checks if NFC Feature is available
+ ///
+ public bool IsAvailable
+ {
+ get
+ {
+ if (CurrentContext.CheckCallingOrSelfPermission(Manifest.Permission.Nfc) != Android.Content.PM.Permission.Granted)
+ return false;
+ return _nfcAdapter != null;
+ }
+ }
+
+ ///
+ /// Checks if NFC Feature is enabled
+ ///
+ public bool IsEnabled => IsAvailable && _nfcAdapter.IsEnabled;
+
+ ///
+ /// Checks if writing mode is supported
+ ///
+ public bool IsWritingTagSupported => NFCUtils.IsWritingSupported();
+
+ ///
+ /// NFC configuration
+ ///
+ public NfcConfiguration Configuration { get; private set; }
+
+ ///
+ /// Default constructor
+ ///
+ public NFCImplementation()
+ {
+ _nfcAdapter = NfcAdapter.GetDefaultAdapter(CurrentContext);
+ Configuration = NfcConfiguration.GetDefaultConfiguration();
+ }
+
+ ///
+ /// Update NFC configuration
+ ///
+ ///
+ public void SetConfiguration(NfcConfiguration configuration) => Configuration.Update(configuration);
+
+ ///
+ /// Starts tags detection
+ ///
+ public void StartListening()
+ {
+ if (_nfcAdapter == null)
+ return;
+
+ var intent = new Intent(CurrentActivity, CurrentActivity.GetType()).AddFlags(ActivityFlags.SingleTop);
+
+ // We don't use MonoAndroid12.0 as targetframework for easier backward compatibility:
+ // MonoAndroid12.0 needs JDK 11.
+ PendingIntentFlags pendingIntentFlags = 0;
+
+#if NET6_0_OR_GREATER
+ if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.S)
+ pendingIntentFlags = PendingIntentFlags.Mutable;
+#else
+ if ((int)Android.OS.Build.VERSION.SdkInt >= 31) //Android.OS.BuildVersionCodes.S
+ pendingIntentFlags = (PendingIntentFlags)33554432; //PendingIntentFlags.Mutable
+#endif
+
+ var pendingIntent = PendingIntent.GetActivity(CurrentActivity, 0, intent, pendingIntentFlags);
+
+ var ndefFilter = new IntentFilter(NfcAdapter.ActionNdefDiscovered);
+ ndefFilter.AddDataType("*/*");
+
+ var tagFilter = new IntentFilter(NfcAdapter.ActionTagDiscovered);
+ tagFilter.AddCategory(Intent.CategoryDefault);
+
+ var filters = new IntentFilter[] { ndefFilter, tagFilter };
+
+ _nfcAdapter.EnableForegroundDispatch(CurrentActivity, pendingIntent, filters, null);
+
+ _isListening = true;
+ OnTagListeningStatusChanged?.Invoke(_isListening);
+ }
+
+ ///
+ /// Stops tags detection
+ ///
+ public void StopListening()
+ {
+ DisablePublishing();
+ if (_nfcAdapter != null)
+ _nfcAdapter.DisableForegroundDispatch(CurrentActivity);
+
+ _isListening = false;
+ OnTagListeningStatusChanged?.Invoke(_isListening);
+ }
+
+ ///
+ /// Starts tag publishing (writing or formatting)
+ ///
+ /// Format tag
+ public void StartPublishing(bool clearMessage = false)
+ {
+ if (!IsWritingTagSupported)
+ return;
+
+ _isWriting = true;
+ _isFormatting = clearMessage;
+ }
+
+ ///
+ /// Stops tag publishing
+ ///
+ public void StopPublishing() => DisablePublishing();
+
+ ///
+ /// Publish or write a message on a tag
+ ///
+ /// see
+ /// make tag read-only
+ public void PublishMessage(ITagInfo tagInfo, bool makeReadOnly = false) => WriteOrClearMessage(tagInfo, false, makeReadOnly);
+
+ ///
+ /// Format tag
+ ///
+ /// see
+ public void ClearMessage(ITagInfo tagInfo) => WriteOrClearMessage(tagInfo, true);
+
+ ///
+ /// Write or Clear a NDEF message
+ ///
+ ///
+ /// Clear Message
+ /// Make tag read-only
+ internal void WriteOrClearMessage(ITagInfo tagInfo, bool clearMessage = false, bool makeReadOnly = false)
+ {
+ try
+ {
+ if (_currentTag == null)
+ throw new Exception(Configuration.Messages.NFCErrorMissingTag);
+
+ if (tagInfo == null)
+ throw new Exception(Configuration.Messages.NFCErrorMissingTagInfo);
+
+ var ndef = Ndef.Get(_currentTag);
+ if (ndef != null)
+ {
+ try
+ {
+ if (!ndef.IsWritable)
+ throw new Exception(Configuration.Messages.NFCErrorReadOnlyTag);
+
+ if (ndef.MaxSize < NFCUtils.GetSize(tagInfo.Records))
+ throw new Exception(Configuration.Messages.NFCErrorCapacityTag);
+
+ ndef.Connect();
+ OnTagConnected?.Invoke(null, EventArgs.Empty);
+
+ NdefMessage message = null;
+ if (clearMessage)
+ {
+ message = GetEmptyNdefMessage();
+ }
+ else
+ {
+ var records = new List();
+ for (var i = 0; i < tagInfo.Records.Length; i++)
+ {
+ var record = tagInfo.Records[i];
+ if (GetAndroidNdefRecord(record) is NdefRecord ndefRecord)
+ records.Add(ndefRecord);
+ }
+
+ if (records.Any())
+ message = new NdefMessage(records.ToArray());
+ }
+
+ if (message != null)
+ {
+ ndef.WriteNdefMessage(message);
+
+ if (!clearMessage && makeReadOnly)
+ {
+ if (!MakeReadOnly(ndef))
+ Console.WriteLine("Cannot lock tag");
+ }
+
+ var nTag = GetTagInfo(_currentTag, ndef.NdefMessage);
+ OnMessagePublished?.Invoke(nTag);
+ }
+ else
+ throw new Exception(Configuration.Messages.NFCErrorWrite);
+ }
+ catch (Android.Nfc.TagLostException tlex)
+ {
+ throw new Exception("Tag Lost Error: " + tlex.Message);
+ }
+ catch (Java.IO.IOException ioex)
+ {
+ throw new Exception("Tag IO Error: " + ioex.Message);
+ }
+ catch (Android.Nfc.FormatException fe)
+ {
+ throw new Exception("Tag Format Error: " + fe.Message);
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Tag Error:" + ex.Message);
+ }
+ finally
+ {
+ if (ndef.IsConnected)
+ ndef.Close();
+
+ _currentTag = null;
+ OnTagDisconnected?.Invoke(null, EventArgs.Empty);
+ }
+ }
+ else
+ throw new Exception(Configuration.Messages.NFCErrorNotCompliantTag);
+ }
+ catch (Exception ex)
+ {
+ StopPublishingAndThrowError(ex.Message);
+ }
+ }
+
+ ///
+ /// Handle Android OnNewIntent
+ ///
+ /// Android
+ internal void HandleNewIntent(Intent intent)
+ {
+ if (intent == null)
+ return;
+
+ if (intent.Action == NfcAdapter.ActionTagDiscovered || intent.Action == NfcAdapter.ActionNdefDiscovered)
+ {
+ _currentTag = intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;
+ if (_currentTag != null)
+ {
+ var nTag = GetTagInfo(_currentTag);
+ if (_isWriting)
+ {
+ // Write mode
+ OnTagDiscovered?.Invoke(nTag, _isFormatting);
+ }
+ else
+ {
+ // Read mode
+ OnMessageReceived?.Invoke(nTag);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Handle Android OnResume
+ ///
+ internal void HandleOnResume()
+ {
+ // Android 10 fix:
+ // If listening mode is already enable, we restart listening when activity is resumed
+ if (_isListening)
+ StartListening();
+ }
+
+ #region Private
+
+ ///
+ /// Stops publishing and throws error
+ ///
+ /// message
+ void StopPublishingAndThrowError(string message)
+ {
+ StopPublishing();
+ throw new Exception(message);
+ }
+
+ ///
+ /// Deactivate publishing
+ ///
+ void DisablePublishing()
+ {
+ _isWriting = false;
+ _isFormatting = false;
+ }
+
+ ///
+ /// Transforms an array of into an array of
+ ///
+ /// Array of
+ /// Array of
+ NFCNdefRecord[] GetRecords(NdefRecord[] records)
+ {
+ var results = new NFCNdefRecord[records.Length];
+ for (var i = 0; i < records.Length; i++)
+ {
+ var ndefRecord = new NFCNdefRecord
+ {
+ TypeFormat = (NFCNdefTypeFormat)records[i].Tnf,
+ Uri = records[i].ToUri()?.ToString(),
+ MimeType = records[i].ToMimeType(),
+ Payload = records[i].GetPayload()
+ };
+ results.SetValue(ndefRecord, i);
+ }
+ return results;
+ }
+
+ ///
+ /// Returns informations contains in NFC Tag
+ ///
+ /// Android
+ /// Android
+ ///
+ ITagInfo GetTagInfo(Tag tag, NdefMessage ndefMessage = null)
+ {
+ if (tag == null)
+ return null;
+
+ var ndef = Ndef.Get(tag);
+ var nTag = new TagInfo(tag.GetId(), ndef != null);
+
+ if (ndef != null)
+ {
+ nTag.Capacity = ndef.MaxSize;
+ nTag.IsWritable = ndef.IsWritable;
+
+ if (ndefMessage == null)
+ ndefMessage = ndef.CachedNdefMessage;
+
+ if (ndefMessage != null)
+ {
+ var records = ndefMessage.GetRecords();
+ nTag.Records = GetRecords(records);
+ }
+ }
+
+ return nTag;
+ }
+
+ ///
+ /// Transforms a into an Android
+ ///
+ /// Object
+ /// Android
+ NdefRecord GetAndroidNdefRecord(NFCNdefRecord record)
+ {
+ if (record == null)
+ return null;
+
+ NdefRecord ndefRecord = null;
+ switch (record.TypeFormat)
+ {
+ case NFCNdefTypeFormat.WellKnown:
+ var languageCode = record.LanguageCode;
+ if (string.IsNullOrWhiteSpace(languageCode)) languageCode = Configuration.DefaultLanguageCode;
+ ndefRecord = NdefRecord.CreateTextRecord(languageCode.Substring(0, 2), Encoding.UTF8.GetString(record.Payload));
+ break;
+ case NFCNdefTypeFormat.Mime:
+ ndefRecord = NdefRecord.CreateMime(record.MimeType, record.Payload);
+ break;
+ case NFCNdefTypeFormat.Uri:
+ ndefRecord = NdefRecord.CreateUri(Encoding.UTF8.GetString(record.Payload));
+ break;
+ case NFCNdefTypeFormat.External:
+ ndefRecord = NdefRecord.CreateExternal(record.ExternalDomain, record.ExternalType, record.Payload);
+ break;
+ case NFCNdefTypeFormat.Empty:
+ ndefRecord = GetEmptyNdefRecord();
+ break;
+ case NFCNdefTypeFormat.Unknown:
+ case NFCNdefTypeFormat.Unchanged:
+ case NFCNdefTypeFormat.Reserved:
+ default:
+ break;
+
+ }
+ return ndefRecord;
+ }
+
+ ///
+ /// Returns an empty Android
+ ///
+ /// Android
+ NdefRecord GetEmptyNdefRecord()
+ {
+ var empty = Array.Empty();
+ return new NdefRecord(NdefRecord.TnfEmpty, empty, empty, empty);
+ }
+
+ ///
+ /// Returns an empty Android
+ ///
+ /// Android
+ NdefMessage GetEmptyNdefMessage()
+ {
+ var records = new NdefRecord[1];
+ records[0] = GetEmptyNdefRecord();
+ return new NdefMessage(records);
+ }
+
+ ///
+ /// Make a tag read-only
+ /// WARNING: This operation is permanent
+ ///
+ ///
+ /// boolean
+ bool MakeReadOnly(Ndef ndef)
+ {
+ if (ndef == null)
+ return false;
+
+ var result = false;
+ var newConnection = false;
+
+ if (!ndef.IsConnected)
+ {
+ newConnection = true;
+ ndef.Connect();
+ }
+
+ if (ndef.CanMakeReadOnly())
+ result = ndef.MakeReadOnly();
+
+ if (newConnection && ndef.IsConnected)
+ ndef.Close();
+
+ return result;
+ }
+
+ #endregion
+
+ #region NFC Status Event Listener
+
+ NfcBroadcastReceiver _nfcBroadcastReceiver;
+
+ event OnNfcStatusChangedEventHandler _onNfcStatusChangedInternal;
+
+ public event OnNfcStatusChangedEventHandler OnNfcStatusChanged
+ {
+ add
+ {
+ var wasRunning = _onNfcStatusChangedInternal != null;
+ _onNfcStatusChangedInternal += value;
+ if (!wasRunning && _onNfcStatusChangedInternal != null)
+ {
+ RegisterListener();
+ }
+ }
+ remove
+ {
+ var wasRunning = _onNfcStatusChangedInternal != null;
+ _onNfcStatusChangedInternal -= value;
+ if (wasRunning && _onNfcStatusChangedInternal == null)
+ {
+ UnRegisterListener();
+ }
+ }
+ }
+
+ ///
+ /// Register NFC Broadcast Receiver
+ ///
+ void RegisterListener()
+ {
+ _nfcBroadcastReceiver = new NfcBroadcastReceiver(OnNfcStatusChange);
+ CurrentContext?.RegisterReceiver(_nfcBroadcastReceiver, new IntentFilter(NfcAdapter.ActionAdapterStateChanged));
+ }
+
+ ///
+ /// Unregister NFC Broadcast Receiver
+ ///
+ void UnRegisterListener()
+ {
+ if (_nfcBroadcastReceiver == null)
+ return;
+
+ try
+ {
+ CurrentContext?.UnregisterReceiver(_nfcBroadcastReceiver);
+ }
+ catch (Java.Lang.IllegalArgumentException ex)
+ {
+ throw new Exception("NFC Broadcast Receiver Error: " + ex.Message);
+ }
+
+ _nfcBroadcastReceiver.Dispose();
+ _nfcBroadcastReceiver = null;
+ }
+
+ ///
+ /// Called when NFC status has changed
+ ///
+ void OnNfcStatusChange() => _onNfcStatusChangedInternal?.Invoke(IsEnabled);
+
+ ///
+ /// Broadcast Receiver to check NFC feature availability
+ ///
+ [BroadcastReceiver(Enabled = true, Exported = false, Label = "NFC Status Broadcast Receiver")]
+ class NfcBroadcastReceiver : BroadcastReceiver
+ {
+ Action _onChanged;
+
+ public NfcBroadcastReceiver() { }
+ public NfcBroadcastReceiver(Action onChanged)
+ {
+ _onChanged = onChanged;
+ }
+
+ public override async void OnReceive(Context context, Intent intent)
+ {
+ if (intent.Action == NfcAdapter.ActionAdapterStateChanged)
+ {
+ var state = intent.GetIntExtra(NfcAdapter.ExtraAdapterState, default);
+ if (state == NfcAdapter.StateOff || state == NfcAdapter.StateOn)
+ {
+ // await 1500ms to ensure that the status updates
+ await Task.Delay(1500);
+ _onChanged?.Invoke();
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/Plugin.NFC/Plugin.NFC.csproj b/src/Plugin.NFC/Plugin.NFC.csproj
index 0c629fe..7c1ece4 100644
--- a/src/Plugin.NFC/Plugin.NFC.csproj
+++ b/src/Plugin.NFC/Plugin.NFC.csproj
@@ -1,108 +1,108 @@
-
-
-
-
-
- net8.0;net8.0-android;net8.0-ios
-
- Plugin.NFC
- Plugin.NFC
- Plugin.NFC
-
- $(AssemblyName) ($(TargetFramework))
- 1.0.0.0
- 1.0.0.0
- 1.0.0.0
- 1.0.0.0
- true
- en
- $(DefineConstants);
- CS0067
-
- false
- false
- latest
- portable
-
- MIT
- https://github.com/franckbour/Plugin.NFC
- https://github.com/franckbour/Plugin.NFC
- git
- https://github.com/franckbour/Plugin.NFC/blob/master/CHANGELOG.md
- https://github.com/franckbour/Plugin.NFC/raw/master/art/nfc128.png
- icon.png
- maui, xamarin, ios, android, xamarin.forms, plugin, NFC
-
- NFC Plugin for Xamarin
- A Cross-Platform plugin to easily read and write NFC tags.
- Cross-Platform NFC (Near Field Communication) plugin to easily read and write NFC tags in your application.
-
- Franck Bour
- Franck Bour
- Copyright 2022
-
-
- false
-
-
-
-
- true
- false
-
-
-
- true
- true
-
-
- true
-
- true
-
- $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
-
-
-
-
- <_NET8 Condition=" $(TargetFramework.Contains('net8')) ">true
- <_DROID Condition=" $(TargetFramework.ToLowerInvariant().Contains('droid')) ">true
- <_IOS Condition=" $(TargetFramework.ToLowerInvariant().Contains('ios')) ">true
- <_MOBILE Condition=" '$(_DROID)' == 'true' OR '$(_IOS)' == 'true' ">true
-
- $(DefineConstants);__ANDROID__;__MOBILE__;
- $(DefineConstants);__IOS__;__MOBILE__;
- $(DefineConstants);__NET8__;
-
-
-
- 11.0
- 21.0
-
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ net8.0;net8.0-android;net8.0-ios
+
+ Plugin.NFC
+ Plugin.NFC
+ Plugin.NFC
+
+ $(AssemblyName) ($(TargetFramework))
+ 1.0.0.0
+ 1.0.0.0
+ 1.0.0.0
+ 1.0.0.0
+ true
+ en
+ $(DefineConstants);
+ CS0067
+
+ false
+ false
+ latest
+ portable
+
+ MIT
+ https://github.com/franckbour/Plugin.NFC
+ https://github.com/franckbour/Plugin.NFC
+ git
+ https://github.com/franckbour/Plugin.NFC/blob/master/CHANGELOG.md
+ https://github.com/franckbour/Plugin.NFC/raw/master/art/nfc128.png
+ icon.png
+ maui, xamarin, ios, android, xamarin.forms, plugin, NFC
+
+ NFC Plugin for Xamarin
+ A Cross-Platform plugin to easily read and write NFC tags.
+ Cross-Platform NFC (Near Field Communication) plugin to easily read and write NFC tags in your application.
+
+ Franck Bour
+ Franck Bour
+ Copyright 2022
+
+
+ false
+
+
+
+
+ true
+ false
+
+
+
+ true
+ true
+
+
+ true
+
+ true
+
+ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
+
+
+
+
+ <_NET8 Condition=" $(TargetFramework.Contains('net8')) ">true
+ <_DROID Condition=" $(TargetFramework.ToLowerInvariant().Contains('droid')) ">true
+ <_IOS Condition=" $(TargetFramework.ToLowerInvariant().Contains('ios')) ">true
+ <_MOBILE Condition=" '$(_DROID)' == 'true' OR '$(_IOS)' == 'true' ">true
+
+ $(DefineConstants);__ANDROID__;__MOBILE__;
+ $(DefineConstants);__IOS__;__MOBILE__;
+ $(DefineConstants);__NET8__;
+
+
+
+ 11.0
+ 21.0
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Plugin.NFC/Shared/CrossNFC.shared.cs b/src/Plugin.NFC/Shared/CrossNFC.shared.cs
index 056e369..96a94bb 100644
--- a/src/Plugin.NFC/Shared/CrossNFC.shared.cs
+++ b/src/Plugin.NFC/Shared/CrossNFC.shared.cs
@@ -1,73 +1,73 @@
-using System;
-
-namespace Plugin.NFC
-{
- ///
- /// Cross NFC
- ///
- public static partial class CrossNFC
- {
- static Lazy _implementation = new Lazy(() => CreateNFC(), System.Threading.LazyThreadSafetyMode.PublicationOnly);
-
- ///
- /// Gets if the plugin is supported on the current platform.
- ///
- public static bool IsSupported => _implementation.Value != null;
-
- ///
- /// Legacy Mode (Supporting Mifare Classic on iOS)
- ///
- static bool _legacy = false;
-
- public static bool Legacy
- {
- get
- {
- return _legacy;
- }
-
- set
- {
- _legacy = value;
-
- _implementation = new Lazy(() => CreateNFC(), System.Threading.LazyThreadSafetyMode.PublicationOnly);
- }
- }
-
- ///
- /// Current plugin implementation to use
- ///
- public static INFC Current
- {
- get
- {
- INFC ret = _implementation.Value;
- if (ret == null)
- {
- throw NotImplementedInReferenceAssembly();
- }
- return ret;
- }
- }
-
- static INFC CreateNFC()
- {
-#if NETSTANDARD || !__MOBILE__
- return null;
-#elif __IOS__
- ObjCRuntime.Class.ThrowOnInitFailure = false;
- if (NFCUtils.IsWritingSupported() && !Legacy)
- return new NFCImplementation();
- return new NFCImplementation_Before_iOS13();
-#else
-#pragma warning disable IDE0022 // Use expression body for methods
- return new NFCImplementation();
-#pragma warning restore IDE0022 // Use expression body for methods
-#endif
- }
-
- internal static Exception NotImplementedInReferenceAssembly() =>
- new NotImplementedException("This functionality is not implemented in the portable version of this assembly. You should reference the NuGet package from your main application project in order to reference the platform-specific implementation.");
-
- }
-}
+using System;
+
+namespace Plugin.NFC
+{
+ ///
+ /// Cross NFC
+ ///
+ public static partial class CrossNFC
+ {
+ static Lazy _implementation = new Lazy(() => CreateNFC(), System.Threading.LazyThreadSafetyMode.PublicationOnly);
+
+ ///
+ /// Gets if the plugin is supported on the current platform.
+ ///
+ public static bool IsSupported => _implementation.Value != null;
+
+ ///
+ /// Legacy Mode (Supporting Mifare Classic on iOS)
+ ///
+ static bool _legacy = false;
+
+ public static bool Legacy
+ {
+ get
+ {
+ return _legacy;
+ }
+
+ set
+ {
+ _legacy = value;
+
+ _implementation = new Lazy(() => CreateNFC(), System.Threading.LazyThreadSafetyMode.PublicationOnly);
+ }
+ }
+
+ ///
+ /// Current plugin implementation to use
+ ///
+ public static INFC Current
+ {
+ get
+ {
+ INFC ret = _implementation.Value;
+ if (ret == null)
+ {
+ throw NotImplementedInReferenceAssembly();
+ }
+ return ret;
+ }
+ }
+
+ static INFC CreateNFC()
+ {
+#if NETSTANDARD || !__MOBILE__
+ return null;
+#elif __IOS__
+ ObjCRuntime.Class.ThrowOnInitFailure = false;
+ if (NFCUtils.IsWritingSupported() && !Legacy)
+ return new NFCImplementation();
+ return new NFCImplementation_Before_iOS13();
+#else
+#pragma warning disable IDE0022 // Use expression body for methods
+ return new NFCImplementation();
+#pragma warning restore IDE0022 // Use expression body for methods
+#endif
+ }
+
+ internal static Exception NotImplementedInReferenceAssembly() =>
+ new NotImplementedException("This functionality is not implemented in the portable version of this assembly. You should reference the NuGet package from your main application project in order to reference the platform-specific implementation.");
+
+ }
+}
diff --git a/src/Plugin.NFC/Shared/INFC.shared.cs b/src/Plugin.NFC/Shared/INFC.shared.cs
index ace1e12..aa6b17c 100644
--- a/src/Plugin.NFC/Shared/INFC.shared.cs
+++ b/src/Plugin.NFC/Shared/INFC.shared.cs
@@ -1,118 +1,118 @@
-using System;
-
-namespace Plugin.NFC
-{
- #region Event delegates
- public delegate void NdefMessageReceivedEventHandler(ITagInfo tagInfo);
- public delegate void NdefMessagePublishedEventHandler(ITagInfo tagInfo);
- public delegate void TagDiscoveredEventHandler(ITagInfo tagInfo, bool format);
- public delegate void OnNfcStatusChangedEventHandler(bool isEnabled);
- public delegate void TagListeningStatusChangedEventHandler(bool isListening);
- #endregion
-
- ///
- /// Main interface for NFC
- ///
- public interface INFC
- {
- ///
- /// Checks if NFC Feature is available
- ///
- bool IsAvailable { get; }
-
- ///
- /// Checks if NFC Feature is enabled
- ///
- bool IsEnabled { get; }
-
- ///
- /// Checks if writing mode is supported
- ///
- bool IsWritingTagSupported { get; }
-
- ///
- /// NFC Configuration
- ///
- NfcConfiguration Configuration { get; }
-
- ///
- /// Set Nfc configuration
- ///
- ///
- void SetConfiguration(NfcConfiguration configuration);
-
- ///
- /// Starts tags detection
- ///
- void StartListening();
-
- ///
- /// Stops tags detection
- ///
- void StopListening();
-
- ///
- /// Starts tag publishing (writing or formatting)
- ///
- /// Format tag
- void StartPublishing(bool clearMessage = false);
-
- ///
- /// Stops tag publishing
- ///
- void StopPublishing();
-
- ///
- /// Publish or write a message on a tag
- ///
- /// see
- /// make tag read-only
- void PublishMessage(ITagInfo tagInfo, bool makeReadOnly = false);
-
- ///
- /// Format tag
- ///
- /// see
- void ClearMessage(ITagInfo tagInfo);
-
- ///
- /// Event raised when tag is connected
- ///
- event EventHandler OnTagConnected;
-
- ///
- /// Event raised when tag is disconnected
- ///
- event EventHandler OnTagDisconnected;
-
- ///
- /// Event raised when ndef message is received
- ///
- event NdefMessageReceivedEventHandler OnMessageReceived;
-
- ///
- /// Event raised when a tag is discovered (Editing)
- ///
- event TagDiscoveredEventHandler OnTagDiscovered;
-
- ///
- /// Event raised when ndef message has been published
- ///
- event NdefMessagePublishedEventHandler OnMessagePublished;
-
- ///
- /// Event raised when iOS NFC reading session is cancelled
- ///
- event EventHandler OniOSReadingSessionCancelled;
-
- ///
- /// Event raised when NFC status changes
- ///
- event OnNfcStatusChangedEventHandler OnNfcStatusChanged;
-
- ///
- /// Event raised when NFC listener status changes
- ///
- event TagListeningStatusChangedEventHandler OnTagListeningStatusChanged;
- }
-}
+using System;
+
+namespace Plugin.NFC
+{
+ #region Event delegates
+ public delegate void NdefMessageReceivedEventHandler(ITagInfo tagInfo);
+ public delegate void NdefMessagePublishedEventHandler(ITagInfo tagInfo);
+ public delegate void TagDiscoveredEventHandler(ITagInfo tagInfo, bool format);
+ public delegate void OnNfcStatusChangedEventHandler(bool isEnabled);
+ public delegate void TagListeningStatusChangedEventHandler(bool isListening);
+ #endregion
+
+ ///
+ /// Main interface for NFC
+ ///
+ public interface INFC
+ {
+ ///
+ /// Checks if NFC Feature is available
+ ///
+ bool IsAvailable { get; }
+
+ ///
+ /// Checks if NFC Feature is enabled
+ ///
+ bool IsEnabled { get; }
+
+ ///
+ /// Checks if writing mode is supported
+ ///
+ bool IsWritingTagSupported { get; }
+
+ ///
+ /// NFC Configuration
+ ///
+ NfcConfiguration Configuration { get; }
+
+ ///
+ /// Set Nfc configuration
+ ///
+ ///
+ void SetConfiguration(NfcConfiguration configuration);
+
+ ///
+ /// Starts tags detection
+ ///
+ void StartListening();
+
+ ///
+ /// Stops tags detection
+ ///
+ void StopListening();
+
+ ///
+ /// Starts tag publishing (writing or formatting)
+ ///
+ /// Format tag
+ void StartPublishing(bool clearMessage = false);
+
+ ///
+ /// Stops tag publishing
+ ///
+ void StopPublishing();
+
+ ///
+ /// Publish or write a message on a tag
+ ///
+ /// see
+ /// make tag read-only
+ void PublishMessage(ITagInfo tagInfo, bool makeReadOnly = false);
+
+ ///
+ /// Format tag
+ ///
+ /// see
+ void ClearMessage(ITagInfo tagInfo);
+
+ ///
+ /// Event raised when tag is connected
+ ///
+ event EventHandler OnTagConnected;
+
+ ///
+ /// Event raised when tag is disconnected
+ ///
+ event EventHandler OnTagDisconnected;
+
+ ///
+ /// Event raised when ndef message is received
+ ///
+ event NdefMessageReceivedEventHandler OnMessageReceived;
+
+ ///
+ /// Event raised when a tag is discovered (Editing)
+ ///
+ event TagDiscoveredEventHandler OnTagDiscovered;
+
+ ///
+ /// Event raised when ndef message has been published
+ ///
+ event NdefMessagePublishedEventHandler OnMessagePublished;
+
+ ///
+ /// Event raised when iOS NFC reading session is cancelled
+ ///
+ event EventHandler OniOSReadingSessionCancelled;
+
+ ///
+ /// Event raised when NFC status changes
+ ///
+ event OnNfcStatusChangedEventHandler OnNfcStatusChanged;
+
+ ///
+ /// Event raised when NFC listener status changes
+ ///
+ event TagListeningStatusChangedEventHandler OnTagListeningStatusChanged;
+ }
+}
diff --git a/src/Plugin.NFC/Shared/ITagInfo.shared.cs b/src/Plugin.NFC/Shared/ITagInfo.shared.cs
index ba4e226..d10ef39 100644
--- a/src/Plugin.NFC/Shared/ITagInfo.shared.cs
+++ b/src/Plugin.NFC/Shared/ITagInfo.shared.cs
@@ -1,104 +1,104 @@
-namespace Plugin.NFC
-{
- ///
- /// Interface for ITagInfo
- ///
- public interface ITagInfo
- {
- ///
- /// Tag Raw Identifier
- ///
- byte[] Identifier { get; }
-
- ///
- /// Tag Serial Number
- ///
- string SerialNumber { get; }
-
- ///
- /// Writable tag
- ///
- bool IsWritable { get; set; }
-
- ///
- /// Empty tag
- ///
- bool IsEmpty { get; }
-
- ///
- /// Supported tag
- ///
- bool IsSupported { get; }
-
- ///
- /// Capacity of tag in bytes
- ///
- int Capacity { get; set; }
-
- ///
- /// Array of of tag
- ///
- NFCNdefRecord[] Records { get; set; }
- }
-
- ///
- /// Class describing the information containing within a NFC tag
- ///
- public class NFCNdefRecord
- {
- ///
- /// NDEF Type
- ///
- public NFCNdefTypeFormat TypeFormat { get; set; }
-
- ///
- /// MimeType used for type
- ///
- public string MimeType { get; set; } = "text/plain";
-
- ///
- /// External domain used for type
- ///
- public string ExternalDomain { get; set; }
-
- ///
- /// External type used for type
- ///
- public string ExternalType { get; set; }
-
- ///
- /// Payload
- ///
- public byte[] Payload { get; set; }
-
- ///
- /// Uri
- ///
- public string Uri { get; set; }
-
- ///
- /// String formatted payload
- ///
- public string Message => NFCUtils.GetMessage(TypeFormat, Payload, Uri);
-
- ///
- /// Two letters ISO 639-1 Language Code (ex: en, fr, de...)
- ///
- public string LanguageCode { get; set; }
- }
-
- ///
- /// Enumeration of NDEF type
- ///
- public enum NFCNdefTypeFormat
- {
- Empty = 0x00,
- WellKnown = 0x01,
- Mime = 0x02,
- Uri = 0x03,
- External = 0x04,
- Unknown = 0x05,
- Unchanged = 0x06,
- Reserved = 0x07
- }
-}
+namespace Plugin.NFC
+{
+ ///
+ /// Interface for ITagInfo
+ ///
+ public interface ITagInfo
+ {
+ ///
+ /// Tag Raw Identifier
+ ///
+ byte[] Identifier { get; }
+
+ ///
+ /// Tag Serial Number
+ ///
+ string SerialNumber { get; }
+
+ ///
+ /// Writable tag
+ ///
+ bool IsWritable { get; set; }
+
+ ///
+ /// Empty tag
+ ///
+ bool IsEmpty { get; }
+
+ ///
+ /// Supported tag
+ ///
+ bool IsSupported { get; }
+
+ ///
+ /// Capacity of tag in bytes
+ ///
+ int Capacity { get; set; }
+
+ ///
+ /// Array of of tag
+ ///
+ NFCNdefRecord[] Records { get; set; }
+ }
+
+ ///
+ /// Class describing the information containing within a NFC tag
+ ///
+ public class NFCNdefRecord
+ {
+ ///
+ /// NDEF Type
+ ///
+ public NFCNdefTypeFormat TypeFormat { get; set; }
+
+ ///
+ /// MimeType used for type
+ ///
+ public string MimeType { get; set; } = "text/plain";
+
+ ///
+ /// External domain used for type
+ ///
+ public string ExternalDomain { get; set; }
+
+ ///
+ /// External type used for type
+ ///
+ public string ExternalType { get; set; }
+
+ ///
+ /// Payload
+ ///
+ public byte[] Payload { get; set; }
+
+ ///
+ /// Uri
+ ///
+ public string Uri { get; set; }
+
+ ///
+ /// String formatted payload
+ ///
+ public string Message => NFCUtils.GetMessage(TypeFormat, Payload, Uri);
+
+ ///
+ /// Two letters ISO 639-1 Language Code (ex: en, fr, de...)
+ ///
+ public string LanguageCode { get; set; }
+ }
+
+ ///
+ /// Enumeration of NDEF type
+ ///
+ public enum NFCNdefTypeFormat
+ {
+ Empty = 0x00,
+ WellKnown = 0x01,
+ Mime = 0x02,
+ Uri = 0x03,
+ External = 0x04,
+ Unknown = 0x05,
+ Unchanged = 0x06,
+ Reserved = 0x07
+ }
+}
diff --git a/src/Plugin.NFC/Shared/NFCUtils.shared.cs b/src/Plugin.NFC/Shared/NFCUtils.shared.cs
index cb0720c..f88fe12 100644
--- a/src/Plugin.NFC/Shared/NFCUtils.shared.cs
+++ b/src/Plugin.NFC/Shared/NFCUtils.shared.cs
@@ -1,113 +1,113 @@
-using System.Linq;
-using System.Text;
-#if __IOS__
-using UIKit;
-#endif
-
-namespace Plugin.NFC
-{
- ///
- /// NFC tools
- ///
- public static class NFCUtils
- {
- ///
- /// Returns the content size of an array of
- ///
- /// array of
- /// Content size
- internal static int GetSize(NFCNdefRecord[] records)
- {
- var size = 0;
- if (records != null && records.Length > 0)
- {
- for (var i = 0; i < records.Length; i++)
- {
- if (records[i] != null)
- size += records[i].Payload.Length;
- }
- }
- return size;
- }
-
- ///
- /// Returns the string formatted payload
- ///
- /// type of
- /// record payload
- /// record uri
- /// String formatted payload
- internal static string GetMessage(NFCNdefTypeFormat type, byte[] payload, string uri)
- {
- string message;
- if (!string.IsNullOrWhiteSpace(uri))
- message = uri;
- else
- {
- if (type == NFCNdefTypeFormat.WellKnown)
- {
- // NDEF_WELLKNOWN Text record
- var status = payload[0];
- var enc = status & 0x80;
- var languageCodeLength = status & 0x3F;
- if (enc == 0)
- message = Encoding.UTF8.GetString(payload, languageCodeLength + 1, payload.Length - languageCodeLength - 1);
- else
- message = Encoding.Unicode.GetString(payload, languageCodeLength + 1, payload.Length - languageCodeLength - 1);
- }
- else
- {
- // Other NDEF types
- message = Encoding.UTF8.GetString(payload, 0, payload.Length);
- }
- }
- return message;
- }
-
- ///
- /// Transforms a string message into an array of bytes
- ///
- /// text message
- /// Array of bytes
- public static byte[] EncodeToByteArray(string text) => Encoding.UTF8.GetBytes(text);
-
- ///
- /// Returns the string formatted payload
- ///
- /// Object
- /// String formatted payload
- public static string GetMessage(NFCNdefRecord record)
- {
- if (record == null)
- return string.Empty;
- return GetMessage(record.TypeFormat, record.Payload, record.Uri);
- }
-
- ///
- /// Convert bytes array into hexadecimal string
- ///
- /// Bytes Array
- /// Separator
- /// Hexadecimal string
- public static string ByteArrayToHexString(byte[] bytes, string separator = null)
- {
- return bytes == null ? string.Empty : string.Join(separator ?? string.Empty, bytes.Select(b => b.ToString("X2")));
- }
-
- ///
- /// Checks if writing tags is supported
- ///
- /// boolean
- public static bool IsWritingSupported()
- {
-#if __IOS__
- var splitted = UIDevice.CurrentDevice.SystemVersion?.Split('.');
- if (splitted != null && splitted.Length > 0 && int.TryParse(splitted[0], out var majorVersion))
- return majorVersion >= 13;
- return false;
-#else
- return true;
-#endif
- }
- }
-}
+using System.Linq;
+using System.Text;
+#if __IOS__
+using UIKit;
+#endif
+
+namespace Plugin.NFC
+{
+ ///
+ /// NFC tools
+ ///
+ public static class NFCUtils
+ {
+ ///
+ /// Returns the content size of an array of
+ ///
+ /// array of
+ /// Content size
+ internal static int GetSize(NFCNdefRecord[] records)
+ {
+ var size = 0;
+ if (records != null && records.Length > 0)
+ {
+ for (var i = 0; i < records.Length; i++)
+ {
+ if (records[i] != null)
+ size += records[i].Payload.Length;
+ }
+ }
+ return size;
+ }
+
+ ///
+ /// Returns the string formatted payload
+ ///
+ /// type of
+ /// record payload
+ /// record uri
+ /// String formatted payload
+ internal static string GetMessage(NFCNdefTypeFormat type, byte[] payload, string uri)
+ {
+ string message;
+ if (!string.IsNullOrWhiteSpace(uri))
+ message = uri;
+ else
+ {
+ if (type == NFCNdefTypeFormat.WellKnown)
+ {
+ // NDEF_WELLKNOWN Text record
+ var status = payload[0];
+ var enc = status & 0x80;
+ var languageCodeLength = status & 0x3F;
+ if (enc == 0)
+ message = Encoding.UTF8.GetString(payload, languageCodeLength + 1, payload.Length - languageCodeLength - 1);
+ else
+ message = Encoding.Unicode.GetString(payload, languageCodeLength + 1, payload.Length - languageCodeLength - 1);
+ }
+ else
+ {
+ // Other NDEF types
+ message = Encoding.UTF8.GetString(payload, 0, payload.Length);
+ }
+ }
+ return message;
+ }
+
+ ///
+ /// Transforms a string message into an array of bytes
+ ///
+ /// text message
+ /// Array of bytes
+ public static byte[] EncodeToByteArray(string text) => Encoding.UTF8.GetBytes(text);
+
+ ///
+ /// Returns the string formatted payload
+ ///
+ /// Object
+ /// String formatted payload
+ public static string GetMessage(NFCNdefRecord record)
+ {
+ if (record == null)
+ return string.Empty;
+ return GetMessage(record.TypeFormat, record.Payload, record.Uri);
+ }
+
+ ///
+ /// Convert bytes array into hexadecimal string
+ ///
+ /// Bytes Array
+ /// Separator
+ /// Hexadecimal string
+ public static string ByteArrayToHexString(byte[] bytes, string separator = null)
+ {
+ return bytes == null ? string.Empty : string.Join(separator ?? string.Empty, bytes.Select(b => b.ToString("X2")));
+ }
+
+ ///
+ /// Checks if writing tags is supported
+ ///
+ /// boolean
+ public static bool IsWritingSupported()
+ {
+#if __IOS__
+ var splitted = UIDevice.CurrentDevice.SystemVersion?.Split('.');
+ if (splitted != null && splitted.Length > 0 && int.TryParse(splitted[0], out var majorVersion))
+ return majorVersion >= 13;
+ return false;
+#else
+ return true;
+#endif
+ }
+ }
+}
diff --git a/src/Plugin.NFC/Shared/NfcConfiguration.shared.cs b/src/Plugin.NFC/Shared/NfcConfiguration.shared.cs
index e3a356c..d6cc0f5 100644
--- a/src/Plugin.NFC/Shared/NfcConfiguration.shared.cs
+++ b/src/Plugin.NFC/Shared/NfcConfiguration.shared.cs
@@ -1,282 +1,282 @@
-namespace Plugin.NFC
-{
- ///
- /// NFC Configuration class
- ///
- public class NfcConfiguration
- {
- ///
- /// List of user defined messages
- ///
- public UserDefinedMessages Messages { get; set; }
-
- ///
- /// Sets ISO 639-1 Language Code for all ndef records (default is "en")
- ///
- public string DefaultLanguageCode { get; set; }
-
- ///
- /// Update Nfc Configuration with a new configuration object
- ///
- ///
- public void Update(NfcConfiguration newCfg)
- {
- if (newCfg == null || newCfg.Messages == null)
- return;
- Messages = newCfg.Messages;
- DefaultLanguageCode = newCfg.DefaultLanguageCode;
- }
-
- ///
- /// Get the default Nfc configuration
- ///
- /// Default
- public static NfcConfiguration GetDefaultConfiguration()
- => new NfcConfiguration { Messages = new UserDefinedMessages(), DefaultLanguageCode = "en" };
- }
-
- ///
- /// User defined UI messages
- ///
- public class UserDefinedMessages
- {
- string _nfcSessionInvalidated = "Session Invalidated";
- string _nfcSessionInvalidatedButton = "OK";
- string _nfcWritingNotSupported = "Writing NFC Tag is not supported on this device";
- string _nfcDialogAlertMessage = "Please hold your phone near a NFC tag";
- string _nfcErrorRead = "Read error. Please try again";
- string _nfcErrorEmptyTag = "Tag is empty";
- string _nfcErrorReadOnlyTag = "Tag is not writable";
- string _nfcErrorCapacityTag = "Tag's capacity is too low";
- string _nfcErrorMissingTag = "Tag is missing";
- string _nfcErrorMissingTagInfo = "No Tag Informations: nothing to write";
- string _nfcErrorNotSupportedTag = "Tag is not supported";
- string _nfcErrorNotCompliantTag = "Tag is not NDEF compliant";
- string _nfcErrorWrite = "Nothing to write";
- string _nfcSuccessRead = "Read Operation Successful";
- string _nfcSuccessWrite = "Write Operation Successful";
- string _nfcSuccessClear = "Clear Operation Successful";
- string _nfcSessionTimeout = "session timeout";
-
- ///
- /// Session timeout
- ///
- public string NFCSessionTimeout
- {
- get => _nfcSessionTimeout;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcSessionTimeout = value;
- }
- }
-
- ///
- /// Session invalidated
- ///
- public string NFCSessionInvalidatedButton
- {
- get => _nfcSessionInvalidatedButton;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcSessionInvalidatedButton = value;
- }
- }
-
- ///
- /// Session invalidated
- ///
- public string NFCSessionInvalidated
- {
- get => _nfcSessionInvalidated;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcSessionInvalidated = value;
- }
- }
-
- ///
- /// Writing feature not supported
- ///
- public string NFCWritingNotSupported
- {
- get => _nfcWritingNotSupported;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcWritingNotSupported = value;
- }
- }
-
- ///
- /// [iOS] NFC Scan dialog alert message
- ///
- public string NFCDialogAlertMessage
- {
- get => _nfcDialogAlertMessage;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcDialogAlertMessage = value;
- }
- }
-
- ///
- /// Read operation error
- ///
- public string NFCErrorRead
- {
- get => _nfcErrorRead;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcErrorRead = value;
- }
- }
-
- ///
- /// Write operation error
- ///
- public string NFCErrorWrite
- {
- get => _nfcErrorWrite;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcErrorWrite = value;
- }
- }
-
- ///
- /// Empty tag error
- ///
- public string NFCErrorEmptyTag
- {
- get => _nfcErrorEmptyTag;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcErrorEmptyTag = value;
- }
- }
-
- ///
- /// Read-only tag error
- ///
- public string NFCErrorReadOnlyTag
- {
- get => _nfcErrorReadOnlyTag;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcErrorReadOnlyTag = value;
- }
- }
-
- ///
- /// Tag capacity error
- ///
- public string NFCErrorCapacityTag
- {
- get => _nfcErrorCapacityTag;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcErrorCapacityTag = value;
- }
- }
-
- ///
- /// Missing tag error
- ///
- public string NFCErrorMissingTag
- {
- get => _nfcErrorMissingTag;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcErrorMissingTag = value;
- }
- }
-
- ///
- /// Missing tag info error
- ///
- public string NFCErrorMissingTagInfo
- {
- get => _nfcErrorMissingTagInfo;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcErrorMissingTagInfo = value;
- }
- }
-
- ///
- /// Not supported tag error
- ///
- public string NFCErrorNotSupportedTag
- {
- get => _nfcErrorNotSupportedTag;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcErrorNotSupportedTag = value;
- }
- }
-
- ///
- /// Not NDEF compliant tag error
- ///
- public string NFCErrorNotCompliantTag
- {
- get => _nfcErrorNotCompliantTag;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcErrorNotCompliantTag = value;
- }
- }
-
- ///
- /// [iOS] Successful read operation message
- ///
- public string NFCSuccessRead
- {
- get => _nfcSuccessRead;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcSuccessRead = value;
- }
- }
-
- ///
- /// [iOS] Successful write operation message
- ///
- public string NFCSuccessWrite
- {
- get => _nfcSuccessWrite;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcSuccessWrite = value;
- }
- }
-
- ///
- /// [iOS] Successful clear operation message
- ///
- public string NFCSuccessClear
- {
- get => _nfcSuccessClear;
- set
- {
- if (!string.IsNullOrWhiteSpace(value))
- _nfcSuccessClear = value;
- }
- }
- }
-}
+namespace Plugin.NFC
+{
+ ///
+ /// NFC Configuration class
+ ///
+ public class NfcConfiguration
+ {
+ ///
+ /// List of user defined messages
+ ///
+ public UserDefinedMessages Messages { get; set; }
+
+ ///
+ /// Sets ISO 639-1 Language Code for all ndef records (default is "en")
+ ///
+ public string DefaultLanguageCode { get; set; }
+
+ ///
+ /// Update Nfc Configuration with a new configuration object
+ ///
+ ///
+ public void Update(NfcConfiguration newCfg)
+ {
+ if (newCfg == null || newCfg.Messages == null)
+ return;
+ Messages = newCfg.Messages;
+ DefaultLanguageCode = newCfg.DefaultLanguageCode;
+ }
+
+ ///
+ /// Get the default Nfc configuration
+ ///
+ /// Default
+ public static NfcConfiguration GetDefaultConfiguration()
+ => new NfcConfiguration { Messages = new UserDefinedMessages(), DefaultLanguageCode = "en" };
+ }
+
+ ///
+ /// User defined UI messages
+ ///
+ public class UserDefinedMessages
+ {
+ string _nfcSessionInvalidated = "Session Invalidated";
+ string _nfcSessionInvalidatedButton = "OK";
+ string _nfcWritingNotSupported = "Writing NFC Tag is not supported on this device";
+ string _nfcDialogAlertMessage = "Please hold your phone near a NFC tag";
+ string _nfcErrorRead = "Read error. Please try again";
+ string _nfcErrorEmptyTag = "Tag is empty";
+ string _nfcErrorReadOnlyTag = "Tag is not writable";
+ string _nfcErrorCapacityTag = "Tag's capacity is too low";
+ string _nfcErrorMissingTag = "Tag is missing";
+ string _nfcErrorMissingTagInfo = "No Tag Informations: nothing to write";
+ string _nfcErrorNotSupportedTag = "Tag is not supported";
+ string _nfcErrorNotCompliantTag = "Tag is not NDEF compliant";
+ string _nfcErrorWrite = "Nothing to write";
+ string _nfcSuccessRead = "Read Operation Successful";
+ string _nfcSuccessWrite = "Write Operation Successful";
+ string _nfcSuccessClear = "Clear Operation Successful";
+ string _nfcSessionTimeout = "session timeout";
+
+ ///
+ /// Session timeout
+ ///
+ public string NFCSessionTimeout
+ {
+ get => _nfcSessionTimeout;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcSessionTimeout = value;
+ }
+ }
+
+ ///
+ /// Session invalidated
+ ///
+ public string NFCSessionInvalidatedButton
+ {
+ get => _nfcSessionInvalidatedButton;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcSessionInvalidatedButton = value;
+ }
+ }
+
+ ///
+ /// Session invalidated
+ ///
+ public string NFCSessionInvalidated
+ {
+ get => _nfcSessionInvalidated;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcSessionInvalidated = value;
+ }
+ }
+
+ ///
+ /// Writing feature not supported
+ ///
+ public string NFCWritingNotSupported
+ {
+ get => _nfcWritingNotSupported;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcWritingNotSupported = value;
+ }
+ }
+
+ ///
+ /// [iOS] NFC Scan dialog alert message
+ ///
+ public string NFCDialogAlertMessage
+ {
+ get => _nfcDialogAlertMessage;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcDialogAlertMessage = value;
+ }
+ }
+
+ ///
+ /// Read operation error
+ ///
+ public string NFCErrorRead
+ {
+ get => _nfcErrorRead;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcErrorRead = value;
+ }
+ }
+
+ ///
+ /// Write operation error
+ ///
+ public string NFCErrorWrite
+ {
+ get => _nfcErrorWrite;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcErrorWrite = value;
+ }
+ }
+
+ ///
+ /// Empty tag error
+ ///
+ public string NFCErrorEmptyTag
+ {
+ get => _nfcErrorEmptyTag;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcErrorEmptyTag = value;
+ }
+ }
+
+ ///
+ /// Read-only tag error
+ ///
+ public string NFCErrorReadOnlyTag
+ {
+ get => _nfcErrorReadOnlyTag;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcErrorReadOnlyTag = value;
+ }
+ }
+
+ ///
+ /// Tag capacity error
+ ///
+ public string NFCErrorCapacityTag
+ {
+ get => _nfcErrorCapacityTag;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcErrorCapacityTag = value;
+ }
+ }
+
+ ///
+ /// Missing tag error
+ ///
+ public string NFCErrorMissingTag
+ {
+ get => _nfcErrorMissingTag;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcErrorMissingTag = value;
+ }
+ }
+
+ ///
+ /// Missing tag info error
+ ///
+ public string NFCErrorMissingTagInfo
+ {
+ get => _nfcErrorMissingTagInfo;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcErrorMissingTagInfo = value;
+ }
+ }
+
+ ///
+ /// Not supported tag error
+ ///
+ public string NFCErrorNotSupportedTag
+ {
+ get => _nfcErrorNotSupportedTag;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcErrorNotSupportedTag = value;
+ }
+ }
+
+ ///
+ /// Not NDEF compliant tag error
+ ///
+ public string NFCErrorNotCompliantTag
+ {
+ get => _nfcErrorNotCompliantTag;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcErrorNotCompliantTag = value;
+ }
+ }
+
+ ///
+ /// [iOS] Successful read operation message
+ ///
+ public string NFCSuccessRead
+ {
+ get => _nfcSuccessRead;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcSuccessRead = value;
+ }
+ }
+
+ ///
+ /// [iOS] Successful write operation message
+ ///
+ public string NFCSuccessWrite
+ {
+ get => _nfcSuccessWrite;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcSuccessWrite = value;
+ }
+ }
+
+ ///
+ /// [iOS] Successful clear operation message
+ ///
+ public string NFCSuccessClear
+ {
+ get => _nfcSuccessClear;
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ _nfcSuccessClear = value;
+ }
+ }
+ }
+}
diff --git a/src/Plugin.NFC/Shared/TagInfo.shared.cs b/src/Plugin.NFC/Shared/TagInfo.shared.cs
index 73c310d..f2a0da7 100644
--- a/src/Plugin.NFC/Shared/TagInfo.shared.cs
+++ b/src/Plugin.NFC/Shared/TagInfo.shared.cs
@@ -1,62 +1,62 @@
-namespace Plugin.NFC
-{
- ///
- /// Default implementation of
- ///
- public class TagInfo : ITagInfo
- {
- public byte[] Identifier { get; }
-
- ///
- /// Tag Serial Number
- ///
- public string SerialNumber { get; }
-
- ///
- /// Writable tag
- ///
- public bool IsWritable { get; set; }
-
- ///
- /// Capacity of tag in bytes
- ///
- public int Capacity { get; set; }
-
- ///
- /// Array of of tag
- ///
- public NFCNdefRecord[] Records { get; set; }
-
- ///
- /// Empty tag
- ///
- public bool IsEmpty => Records == null || Records.Length == 0 || Records[0] == null ||Records[0].TypeFormat == NFCNdefTypeFormat.Empty;
-
- ///
- ///
- ///
- public bool IsSupported { get; private set; }
-
- ///
- /// Default constructor
- ///
- public TagInfo()
- {
- IsSupported = true;
- }
-
- ///
- /// Custom contructor
- ///
- /// Tag Identifier
- /// Is Ndef tag
- public TagInfo(byte[] identifier, bool isNdef = true)
- {
- Identifier = identifier;
- SerialNumber = NFCUtils.ByteArrayToHexString(identifier);
- IsSupported = isNdef;
- }
-
- public override string ToString() => $"TagInfo: identifier: {Identifier}, SerialNumber:{SerialNumber}, Capacity:{Capacity} bytes, IsSupported:{IsSupported}, IsEmpty:{IsEmpty}, IsWritable:{IsWritable}";
- }
-}
+namespace Plugin.NFC
+{
+ ///
+ /// Default implementation of
+ ///
+ public class TagInfo : ITagInfo
+ {
+ public byte[] Identifier { get; }
+
+ ///
+ /// Tag Serial Number
+ ///
+ public string SerialNumber { get; }
+
+ ///
+ /// Writable tag
+ ///
+ public bool IsWritable { get; set; }
+
+ ///
+ /// Capacity of tag in bytes
+ ///
+ public int Capacity { get; set; }
+
+ ///
+ /// Array of of tag
+ ///
+ public NFCNdefRecord[] Records { get; set; }
+
+ ///
+ /// Empty tag
+ ///
+ public bool IsEmpty => Records == null || Records.Length == 0 || Records[0] == null ||Records[0].TypeFormat == NFCNdefTypeFormat.Empty;
+
+ ///
+ ///
+ ///
+ public bool IsSupported { get; private set; }
+
+ ///
+ /// Default constructor
+ ///
+ public TagInfo()
+ {
+ IsSupported = true;
+ }
+
+ ///
+ /// Custom contructor
+ ///
+ /// Tag Identifier
+ /// Is Ndef tag
+ public TagInfo(byte[] identifier, bool isNdef = true)
+ {
+ Identifier = identifier;
+ SerialNumber = NFCUtils.ByteArrayToHexString(identifier);
+ IsSupported = isNdef;
+ }
+
+ public override string ToString() => $"TagInfo: identifier: {Identifier}, SerialNumber:{SerialNumber}, Capacity:{Capacity} bytes, IsSupported:{IsSupported}, IsEmpty:{IsEmpty}, IsWritable:{IsWritable}";
+ }
+}
diff --git a/src/Plugin.NFC/iOS/NFC.iOS.cs b/src/Plugin.NFC/iOS/NFC.iOS.cs
index 6aebc6d..77e2107 100644
--- a/src/Plugin.NFC/iOS/NFC.iOS.cs
+++ b/src/Plugin.NFC/iOS/NFC.iOS.cs
@@ -1,1303 +1,1303 @@
-using CoreFoundation;
-using CoreNFC;
-using Foundation;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using UIKit;
-
-namespace Plugin.NFC
-{
- ///
- /// iOS 13+ implementation of
- ///
- public class NFCImplementation : NFCTagReaderSessionDelegate, INFC
- {
- public const string SessionTimeoutMessage = "session timeout";
-
- public event EventHandler OnTagConnected;
- public event EventHandler OnTagDisconnected;
- public event NdefMessageReceivedEventHandler OnMessageReceived;
- public event NdefMessagePublishedEventHandler OnMessagePublished;
- public event TagDiscoveredEventHandler OnTagDiscovered;
- public event EventHandler OniOSReadingSessionCancelled;
- public event OnNfcStatusChangedEventHandler OnNfcStatusChanged;
- public event TagListeningStatusChangedEventHandler OnTagListeningStatusChanged;
-
- bool _isWriting;
- bool _isFormatting;
- bool _customInvalidation = false;
-
- INFCTag _tag;
-
- NFCTagReaderSession NfcSession { get; set; }
-
- ///
- /// Checks if NFC Feature is available
- ///
- public bool IsAvailable => NFCReaderSession.ReadingAvailable;
-
- ///
- /// Checks if NFC Feature is enabled
- ///
- public bool IsEnabled => IsAvailable;
-
- ///
- /// Checks if writing mode is supported
- ///
- public bool IsWritingTagSupported => true;
-
- ///
- /// NFC configuration
- ///
- public NfcConfiguration Configuration { get; private set; }
-
- ///
- /// Default constructor
- ///
- public NFCImplementation()
- {
- Configuration = NfcConfiguration.GetDefaultConfiguration();
- }
-
- ///
- /// Update NFC configuration
- ///
- ///
- public void SetConfiguration(NfcConfiguration configuration) => Configuration.Update(configuration);
-
- ///
- /// Starts tags detection
- ///
- public void StartListening()
- {
- _customInvalidation = false;
- _isWriting = false;
- _isFormatting = false;
-
- NfcSession = new NFCTagReaderSession(NFCPollingOption.Iso14443 | NFCPollingOption.Iso15693, this, DispatchQueue.CurrentQueue)
- {
- AlertMessage = Configuration.Messages.NFCDialogAlertMessage
- };
- NfcSession?.BeginSession();
- OnTagListeningStatusChanged?.Invoke(true);
- }
-
- ///
- /// Stops tags detection
- ///
- public void StopListening()
- {
- NfcSession?.InvalidateSession();
- }
-
- ///
- /// Starts tag publishing (writing or formatting)
- ///
- /// Format tag
- public void StartPublishing(bool clearMessage = false)
- {
- if (!IsAvailable)
- throw new InvalidOperationException(Configuration.Messages.NFCWritingNotSupported);
-
- _customInvalidation = false;
- _isWriting = true;
- _isFormatting = clearMessage;
-
- NfcSession = new NFCTagReaderSession(NFCPollingOption.Iso14443 | NFCPollingOption.Iso15693, this, DispatchQueue.CurrentQueue)
- {
- AlertMessage = Configuration.Messages.NFCDialogAlertMessage
- };
- NfcSession?.BeginSession();
- OnTagListeningStatusChanged?.Invoke(true);
- }
-
- ///
- /// Stops tag publishing
- ///
- public void StopPublishing()
- {
- _isWriting = _isFormatting = _customInvalidation = false;
- _tag = null;
- NfcSession?.InvalidateSession();
- }
-
- ///
- /// Publish or write a message on a tag
- ///
- /// see
- /// make tag read-only
- public void PublishMessage(ITagInfo tagInfo, bool makeReadOnly = false) => WriteOrClearMessage(_tag, tagInfo, false, makeReadOnly);
-
- ///
- /// Format tag
- ///
- /// see
- public void ClearMessage(ITagInfo tagInfo) => WriteOrClearMessage(_tag, tagInfo, true);
-
- ///
- /// Event raised when NFC tags are detected
- ///
- /// iOS
- /// Array of iOS
- public override void DidDetectTags(NFCTagReaderSession session, INFCTag[] tags)
- {
- _customInvalidation = false;
- _tag = tags.First();
-
- var connectionError = string.Empty;
- session.ConnectTo(_tag, (error) =>
- {
- if (error != null)
- {
- connectionError = error.LocalizedDescription;
- Invalidate(session, connectionError);
- return;
- }
-
- var ndefTag = NfcNdefTagExtensions.GetNdefTag(_tag);
-
- if (ndefTag == null)
- {
- Invalidate(session, Configuration.Messages.NFCErrorNotCompliantTag);
- return;
- }
-
- ndefTag.QueryNdefStatus((status, capacity, error) =>
- {
- if (error != null)
- {
- Invalidate(session, error.LocalizedDescription);
- return;
- }
-
- var isNdefSupported = status != NFCNdefStatus.NotSupported;
-
- var identifier = NfcNdefTagExtensions.GetTagIdentifier(ndefTag);
- var nTag = new TagInfo(identifier, isNdefSupported)
- {
- IsWritable = status == NFCNdefStatus.ReadWrite,
- Capacity = Convert.ToInt32(capacity)
- };
-
- if (!isNdefSupported)
- {
- session.AlertMessage = Configuration.Messages.NFCErrorNotSupportedTag;
-
- OnMessageReceived?.Invoke(nTag);
- Invalidate(session);
- return;
- }
-
- if (_isWriting)
- {
- // Write mode
- OnTagDiscovered?.Invoke(nTag, _isFormatting);
- }
- else
- {
- // Read mode
- ndefTag.ReadNdef((message, error) =>
- {
- // iOS Error: NFCReaderError.NdefReaderSessionErrorZeroLengthMessage (NDEF tag does not contain any NDEF message)
- // NFCReaderError.NdefReaderSessionErrorZeroLengthMessage constant should be equals to 403 instead of 304
- // see https://developer.apple.com/documentation/corenfc/nfcreadererror/code/ndefreadersessionerrorzerolengthmessage
- if (error != null && error.Code != 403)
- {
- Invalidate(session, Configuration.Messages.NFCErrorRead);
- return;
- }
-
- session.AlertMessage = Configuration.Messages.NFCSuccessRead;
-
- nTag.Records = NFCNdefPayloadExtensions.GetRecords(message?.Records);
- OnMessageReceived?.Invoke(nTag);
- Invalidate(session);
- });
- }
- });
- });
- }
-
- ///
- /// Event raised when an error happened during detection
- ///
- /// iOS
- /// iOS
- public override void DidInvalidate(NFCTagReaderSession session, NSError error)
- {
- OnTagListeningStatusChanged?.Invoke(false);
-
- var readerError = (NFCReaderError)(long)error.Code;
- if (readerError != NFCReaderError.ReaderSessionInvalidationErrorFirstNDEFTagRead && readerError != NFCReaderError.ReaderSessionInvalidationErrorUserCanceled)
- {
- var alertController = UIAlertController.Create(Configuration.Messages.NFCSessionInvalidated, error.LocalizedDescription.ToLower().Equals(SessionTimeoutMessage) ? Configuration.Messages.NFCSessionTimeout : error.LocalizedDescription, UIAlertControllerStyle.Alert);
- alertController.AddAction(UIAlertAction.Create(Configuration.Messages.NFCSessionInvalidatedButton, UIAlertActionStyle.Default, null));
- OniOSReadingSessionCancelled?.Invoke(null, EventArgs.Empty);
- DispatchQueue.MainQueue.DispatchAsync(() =>
- {
- GetCurrentController().PresentViewController(alertController, true, null);
- });
- }
- else if (readerError == NFCReaderError.ReaderSessionInvalidationErrorUserCanceled && !_customInvalidation)
- OniOSReadingSessionCancelled?.Invoke(null, EventArgs.Empty);
- }
-
- ///
- /// Write or Clear a NDEF message
- ///
- ///
- ///
- /// Clear Message
- /// Make a tag read-only
- internal void WriteOrClearMessage(INFCTag tag, ITagInfo tagInfo, bool clearMessage = false, bool makeReadOnly = false)
- {
- if (NfcSession == null)
- return;
-
- if (tag == null)
- {
- Invalidate(NfcSession, Configuration.Messages.NFCErrorMissingTag);
- return;
- }
-
- if (tagInfo == null || (!clearMessage && tagInfo.Records.Any(record => record.Payload == null)))
- {
- Invalidate(NfcSession, Configuration.Messages.NFCErrorMissingTagInfo);
- return;
- }
-
- var ndefTag = NfcNdefTagExtensions.GetNdefTag(tag);
- if (ndefTag == null)
- {
- Invalidate(NfcSession, Configuration.Messages.NFCErrorNotCompliantTag);
- return;
- }
-
- try
- {
- if (!ndefTag.Available)
- {
- NfcSession.ConnectTo(tag, (error) =>
- {
- if (error != null)
- {
- Invalidate(NfcSession, error.LocalizedDescription);
- return;
- }
-
- ExecuteWriteOrClear(NfcSession, ndefTag, tagInfo, clearMessage);
- });
- }
- else
- {
- ExecuteWriteOrClear(NfcSession, ndefTag, tagInfo, clearMessage);
- }
-
- if (!clearMessage && makeReadOnly)
- {
- MakeTagReadOnly(NfcSession, tag, ndefTag);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.StackTrace);
- }
- finally
- {
- OnTagDisconnected?.Invoke(null, EventArgs.Empty);
- }
- }
-
- #region Private
-
- ///
- /// Returns the current iOS controller
- ///
- /// Object
- UIViewController GetCurrentController()
- {
- var window = UIApplication.SharedApplication.KeyWindow;
- var vc = window.RootViewController;
- while (vc.PresentedViewController != null)
- vc = vc.PresentedViewController;
- return vc;
- }
-
- ///
- /// Invalidate the session
- ///
- ///
- /// Message to show
- void Invalidate(NFCTagReaderSession session, string message = null)
- {
- _customInvalidation = true;
- if (string.IsNullOrWhiteSpace(message))
- session.InvalidateSession();
- else
- session.InvalidateSession(message);
- }
-
- ///
- /// Writes or clears a TAG
- ///
- ///
- ///
- ///
- /// Clear message
- void ExecuteWriteOrClear(NFCTagReaderSession session, INFCNdefTag tag, ITagInfo tagInfo, bool clearMessage = false)
- {
- tag.QueryNdefStatus((status, capacity, error) =>
- {
- if (error != null)
- {
- Invalidate(session, error.LocalizedDescription);
- return;
- }
-
- if (status == NFCNdefStatus.ReadOnly)
- {
- Invalidate(session, Configuration.Messages.NFCErrorReadOnlyTag);
- return;
- }
-
- if (Convert.ToInt32(capacity) < NFCUtils.GetSize(tagInfo.Records))
- {
- Invalidate(session, Configuration.Messages.NFCErrorCapacityTag);
- return;
- }
-
- NFCNdefMessage message = null;
- if (!clearMessage)
- {
- session.AlertMessage = Configuration.Messages.NFCSuccessWrite;
-
- var records = new List();
- for (var i = 0; i < tagInfo.Records.Length; i++)
- {
- var record = tagInfo.Records[i];
- if (NFCNdefPayloadExtensions.GetiOSPayload(record, Configuration) is NFCNdefPayload ndefPayload)
- records.Add(ndefPayload);
- }
-
- if (records.Any())
- message = new NFCNdefMessage(records.ToArray());
- }
- else
- {
- session.AlertMessage = Configuration.Messages.NFCSuccessClear;
- message = NFCNdefMessageExtensions.EmptyNdefMessage;
- }
-
- if (message != null)
- {
- tag.WriteNdef(message, (error) =>
- {
- if (error != null)
- {
- Invalidate(session, error.LocalizedDescription);
- return;
- }
-
- tagInfo.Records = NFCNdefPayloadExtensions.GetRecords(message.Records);
- OnMessagePublished?.Invoke(tagInfo);
- Invalidate(NfcSession);
- });
- }
- else
- Invalidate(session, Configuration.Messages.NFCErrorWrite);
- });
- }
-
- ///
- /// Make a tag read-only
- /// WARNING: This operation is permanent
- ///
- ///
- ///
- ///
- void MakeTagReadOnly(NFCTagReaderSession session, INFCTag tag, INFCNdefTag ndefTag)
- {
- session.ConnectTo(tag, (error) =>
- {
- if (error != null)
- {
- Console.WriteLine(error.LocalizedDescription);
- return;
- }
-
- ndefTag.WriteLock((error) =>
- {
- if (error != null)
- Console.WriteLine("Error when locking a tag on iOS: " + error.LocalizedDescription);
- else
- Console.WriteLine("Locking Successful!");
- });
- });
- }
-
- #endregion
- }
-
- ///
- /// Old iOS implementation of (iOS < 13)
- ///
- public class NFCImplementation_Before_iOS13 : NFCNdefReaderSessionDelegate, INFC
- {
- public const string SessionTimeoutMessage = "session timeout";
-
- private bool _isWriting;
- private bool _isFormatting;
- private bool _customInvalidation = false;
- private INFCNdefTag _tag;
-
- public event EventHandler OnTagConnected;
- public event EventHandler OnTagDisconnected;
- public event NdefMessageReceivedEventHandler OnMessageReceived;
- public event NdefMessagePublishedEventHandler OnMessagePublished;
- public event TagDiscoveredEventHandler OnTagDiscovered;
- public event EventHandler OniOSReadingSessionCancelled;
- public event OnNfcStatusChangedEventHandler OnNfcStatusChanged;
- public event TagListeningStatusChangedEventHandler OnTagListeningStatusChanged;
-
- NFCNdefReaderSession NfcSession { get; set; }
-
- ///
- /// Checks if NFC Feature is available
- ///
- public bool IsAvailable => NFCNdefReaderSession.ReadingAvailable;
-
- ///
- /// Checks if NFC Feature is enabled
- ///
- public bool IsEnabled => IsAvailable;
-
- ///
- /// Checks if writing mode is supported
- ///
- public bool IsWritingTagSupported => NFCUtils.IsWritingSupported();
-
- ///
- /// NFC configuration
- ///
- public NfcConfiguration Configuration { get; private set; }
-
- ///
- /// Default constructor
- ///
- public NFCImplementation_Before_iOS13()
- {
- Configuration = NfcConfiguration.GetDefaultConfiguration();
- }
-
- ///
- /// Update NFC configuration
- ///
- ///
- public void SetConfiguration(NfcConfiguration configuration) => Configuration.Update(configuration);
-
- ///
- /// Starts tags detection
- ///
- public void StartListening()
- {
- _customInvalidation = false;
- _isWriting = false;
- _isFormatting = false;
-
- NfcSession = new NFCNdefReaderSession(this, DispatchQueue.CurrentQueue, true)
- {
- AlertMessage = Configuration.Messages.NFCDialogAlertMessage
- };
-
- NfcSession?.BeginSession();
- OnTagListeningStatusChanged?.Invoke(true);
- }
-
- ///
- /// Stops tags detection
- ///
- public void StopListening()
- {
- NfcSession?.InvalidateSession();
- }
-
- ///
- /// Starts tag publishing (writing or formatting)
- ///
- /// Format tag
- public void StartPublishing(bool clearMessage = false)
- {
- if (!IsAvailable)
- {
- throw new InvalidOperationException(Configuration.Messages.NFCWritingNotSupported);
- }
-
- _customInvalidation = false;
- _isWriting = true;
- _isFormatting = clearMessage;
-
- NfcSession = new NFCNdefReaderSession(this, DispatchQueue.CurrentQueue, true)
- {
- AlertMessage = Configuration.Messages.NFCDialogAlertMessage
- };
- NfcSession?.BeginSession();
- OnTagListeningStatusChanged?.Invoke(true);
- }
-
- ///
- /// Stops tag publishing
- ///
- public void StopPublishing()
- {
- _isWriting = _isFormatting = _customInvalidation = false;
- _tag = null;
- NfcSession?.InvalidateSession();
- }
-
- ///
- /// Publish or write a message on a tag
- ///
- /// see
- /// Make a tag read-only
- public void PublishMessage(ITagInfo tagInfo, bool makeReadOnly = false) => WriteOrClearMessage(_tag, tagInfo, false, makeReadOnly);
-
- ///
- /// Format tag
- ///
- /// see
- public void ClearMessage(ITagInfo tagInfo) => WriteOrClearMessage(_tag, tagInfo, true);
-
- ///
- /// Event raised when NDEF messages are detected
- ///
- /// iOS
- /// Array of iOS
- public override void DidDetect(NFCNdefReaderSession session, NFCNdefMessage[] messages)
- {
- OnTagConnected?.Invoke(null, EventArgs.Empty);
-
- if (messages != null && messages.Length > 0)
- {
- var first = messages[0];
- var tagInfo = new TagInfo
- {
- IsWritable = false,
- Records = NFCNdefPayloadExtensions.GetRecords(first.Records)
- };
- OnMessageReceived?.Invoke(tagInfo);
- }
-
- OnTagDisconnected?.Invoke(null, EventArgs.Empty);
- }
-
- ///
- /// Event raised when NFC tag detected
- ///
- /// iOS
- /// Array of iOS
- public override void DidDetectTags(NFCNdefReaderSession session, INFCNdefTag[] tags)
- {
- _customInvalidation = false;
- _tag = tags.First();
-
- session.ConnectToTag(_tag, error =>
- {
- if (error != null)
- {
- Invalidate(session, error.LocalizedDescription);
- return;
- }
-
- if (_tag == null)
- {
- Invalidate(session, Configuration.Messages.NFCErrorNotCompliantTag);
- return;
- }
-
- _tag.QueryNdefStatus((status, capacity, ndefError) =>
- {
- if (ndefError != null)
- {
- Invalidate(session, ndefError.LocalizedDescription);
- return;
- }
-
- var isNdefSupported = status != NFCNdefStatus.NotSupported;
-
- var identifier = NfcNdefTagExtensions.GetTagIdentifier(_tag);
- var nTag = new TagInfo(identifier, isNdefSupported)
- {
- IsWritable = status == NFCNdefStatus.ReadWrite,
- Capacity = Convert.ToInt32(capacity)
- };
-
- if (!isNdefSupported)
- {
- session.AlertMessage = Configuration.Messages.NFCErrorNotSupportedTag;
-
- OnMessageReceived?.Invoke(nTag);
- Invalidate(session);
- return;
- }
-
- if (_isWriting)
- {
- // Write mode
- OnTagDiscovered?.Invoke(nTag, _isFormatting);
- }
- else
- {
- // Read mode
- _tag.ReadNdef((message, readError) =>
- {
- if (readError != null)
- {
- Invalidate(session, readError.Code == (int)NFCReaderError.NdefReaderSessionErrorZeroLengthMessage
- ? Configuration.Messages.NFCErrorEmptyTag
- : Configuration.Messages.NFCErrorRead);
- return;
- }
-
- session.AlertMessage = Configuration.Messages.NFCSuccessRead;
-
- nTag.Records = NFCNdefPayloadExtensions.GetRecords(message?.Records);
- OnMessageReceived?.Invoke(nTag);
- Invalidate(session);
- });
- }
- });
- });
- }
-
- ///
- /// Event raised when an error happened during detection
- ///
- /// iOS
- /// iOS
- public override void DidInvalidate(NFCNdefReaderSession session, NSError error)
- {
- OnTagListeningStatusChanged?.Invoke(false);
-
- var readerError = (NFCReaderError)(long)error.Code;
- if (readerError != NFCReaderError.ReaderSessionInvalidationErrorFirstNDEFTagRead && readerError != NFCReaderError.ReaderSessionInvalidationErrorUserCanceled)
- {
- var alertController = UIAlertController.Create(Configuration.Messages.NFCSessionInvalidated, error.LocalizedDescription.ToLower().Equals(SessionTimeoutMessage) ? Configuration.Messages.NFCSessionTimeout : error.LocalizedDescription, UIAlertControllerStyle.Alert);
- alertController.AddAction(UIAlertAction.Create(Configuration.Messages.NFCSessionInvalidatedButton, UIAlertActionStyle.Default, null));
- OniOSReadingSessionCancelled?.Invoke(null, EventArgs.Empty);
- DispatchQueue.MainQueue.DispatchAsync(() =>
- {
- GetCurrentController().PresentViewController(alertController, true, null);
- });
- }
- else if (readerError == NFCReaderError.ReaderSessionInvalidationErrorUserCanceled && !_customInvalidation)
- {
- OniOSReadingSessionCancelled?.Invoke(null, EventArgs.Empty);
- }
- }
-
- ///
- /// Write or Clear a NDEF message
- ///
- ///
- ///
- /// Clear Message
- /// Make a tag read-only
- internal void WriteOrClearMessage(INFCNdefTag tag, ITagInfo tagInfo, bool clearMessage = false, bool makeReadOnly = false)
- {
- if (NfcSession == null)
- {
- return;
- }
-
- if (tag == null)
- {
- Invalidate(NfcSession, Configuration.Messages.NFCErrorMissingTag);
- return;
- }
-
- if (tagInfo == null || (!clearMessage && tagInfo.Records.Any(record => record.Payload == null)))
- {
- Invalidate(NfcSession, Configuration.Messages.NFCErrorMissingTagInfo);
- return;
- }
-
- if (_tag == null)
- {
- Invalidate(NfcSession, Configuration.Messages.NFCErrorNotCompliantTag);
- return;
- }
-
- try
- {
- if (!_tag.Available)
- {
- NfcSession.ConnectToTag(_tag, (error) =>
- {
- if (error != null)
- {
- Invalidate(NfcSession, error.LocalizedDescription);
- return;
- }
-
- ExecuteWriteOrClear(NfcSession, _tag, tagInfo, clearMessage);
- });
- }
- else
- {
- ExecuteWriteOrClear(NfcSession, _tag, tagInfo, clearMessage);
- }
-
- if (!clearMessage && makeReadOnly)
- {
- MakeTagReadOnly(NfcSession, tag);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.StackTrace);
- }
- finally
- {
- OnTagDisconnected?.Invoke(null, EventArgs.Empty);
- }
- }
-
- #region Private
-
- ///
- /// Returns the current iOS controller
- ///
- /// Object
- UIViewController GetCurrentController()
- {
- var window = UIApplication.SharedApplication.KeyWindow;
- var vc = window.RootViewController;
- while (vc.PresentedViewController != null)
- vc = vc.PresentedViewController;
- return vc;
- }
-
- ///
- /// Writes or clears a TAG
- ///
- ///
- ///
- ///
- /// Clear message
- private void ExecuteWriteOrClear(NFCNdefReaderSession session, INFCNdefTag tag, ITagInfo tagInfo, bool clearMessage = false)
- {
- tag.QueryNdefStatus((status, capacity, error) =>
- {
- if (error != null)
- {
- Invalidate(session, error.LocalizedDescription);
- return;
- }
-
- if (status == NFCNdefStatus.ReadOnly)
- {
- Invalidate(session, Configuration.Messages.NFCErrorReadOnlyTag);
- return;
- }
-
- if (Convert.ToInt32(capacity) < NFCUtils.GetSize(tagInfo.Records))
- {
- Invalidate(session, Configuration.Messages.NFCErrorCapacityTag);
- return;
- }
-
- NFCNdefMessage message = null;
- if (!clearMessage)
- {
- session.AlertMessage = Configuration.Messages.NFCSuccessWrite;
-
- var records = new List();
- for (var i = 0; i < tagInfo.Records.Length; i++)
- {
- var record = tagInfo.Records[i];
- if (NFCNdefPayloadExtensions.GetiOSPayload(record, Configuration) is NFCNdefPayload ndefPayload)
- records.Add(ndefPayload);
- }
-
- if (records.Any())
- message = new NFCNdefMessage(records.ToArray());
- }
- else
- {
- session.AlertMessage = Configuration.Messages.NFCSuccessClear;
- message = NFCNdefMessageExtensions.EmptyNdefMessage;
- }
-
- if (message != null)
- {
- tag.WriteNdef(message, (error) =>
- {
- if (error != null)
- {
- Invalidate(session, error.LocalizedDescription);
- return;
- }
-
- tagInfo.Records = NFCNdefPayloadExtensions.GetRecords(message.Records);
- OnMessagePublished?.Invoke(tagInfo);
- Invalidate(NfcSession);
- });
- }
- else
- Invalidate(session, Configuration.Messages.NFCErrorWrite);
- });
- }
-
- ///
- /// Make a tag read-only
- /// WARNING: This operation is permanent
- ///
- ///
- ///
- ///
- private void MakeTagReadOnly(NFCNdefReaderSession session, INFCNdefTag tag)
- {
- session.ConnectToTag(tag, (error) =>
- {
- if (error != null)
- {
- Console.WriteLine(error.LocalizedDescription);
- return;
- }
-
- tag.WriteLock((error) =>
- {
- if (error != null)
- Console.WriteLine("Error when locking a tag on iOS: " + error.LocalizedDescription);
- else
- Console.WriteLine("Locking Successful!");
- });
- });
- }
-
- ///
- /// Invalidate the session
- ///
- ///
- /// Message to show
- void Invalidate(NFCNdefReaderSession session, string message = null)
- {
- _customInvalidation = true;
- if (string.IsNullOrWhiteSpace(message))
- session.InvalidateSession();
- else
- session.InvalidateSession(message);
- }
-
- #endregion
- }
-
- ///
- /// NFC Ndef Message extensions class
- ///
- internal static class NFCNdefMessageExtensions
- {
- ///
- /// Convert an iOS into an array of bytes
- ///
- /// iOS
- /// Array of bytes
- public static byte[] ToByteArray(this NSData data)
- {
- var bytes = new byte[data.Length];
- if (data.Length > 0) System.Runtime.InteropServices.Marshal.Copy(data.Bytes, bytes, 0, Convert.ToInt32(data.Length));
- return bytes;
- }
-
- ///
- /// Converte an iOS into an array of bytes
- ///
- /// iOS
- /// Array of bytes
- public static byte[] ToByteArray(this NFCNdefMessage message)
- {
- var records = message?.Records;
-
- // Empty message: single empty record
- if (records == null || records.Length == 0)
- {
- records = new NFCNdefPayload[] { null };
- }
-
- var m = new MemoryStream();
- for (var i = 0; i < records.Length; i++)
- {
- var record = records[i];
- var typeNameFormat = record?.TypeNameFormat ?? NFCTypeNameFormat.Empty;
- var payload = record?.Payload;
- var id = record?.Identifier;
- var type = record?.Type;
-
- var flags = (byte)typeNameFormat;
-
- // Message begin / end flags. If there is only one record in the message, both flags are set.
- if (i == 0)
- flags |= 0x80; // MB (message begin = first record in the message)
- if (i == records.Length - 1)
- flags |= 0x40; // ME (message end = last record in the message)
-
- // cf (chunked records) not supported yet
-
- // SR (Short Record)?
- if (payload == null || payload.Length < 255)
- flags |= 0x10;
-
- // ID present?
- if (id != null && id.Length > 0)
- flags |= 0x08;
-
- m.WriteByte(flags);
-
- // Type length
- if (type != null)
- m.WriteByte((byte)type.Length);
- else
- m.WriteByte(0);
-
- // Payload length 1 byte (SR) or 4 bytes
- if (payload == null)
- {
- m.WriteByte(0);
- }
- else
- {
- if ((flags & 0x10) != 0)
- {
- // SR
- m.WriteByte((byte)payload.Length);
- }
- else
- {
- // No SR (Short Record)
- var payloadLength = (uint)payload.Length;
- m.WriteByte((byte)(payloadLength >> 24));
- m.WriteByte((byte)(payloadLength >> 16));
- m.WriteByte((byte)(payloadLength >> 8));
- m.WriteByte((byte)(payloadLength & 0x000000ff));
- }
- }
-
- // ID length
- if (id != null && (flags & 0x08) != 0)
- m.WriteByte((byte)id.Length);
-
- // Type length
- if (type != null && type.Length > 0)
- m.Write(type.ToArray(), 0, (int)type.Length);
-
- // ID data
- if (id != null && id.Length > 0)
- m.Write(id.ToArray(), 0, (int)id.Length);
-
- // Payload data
- if (payload != null && payload.Length > 0)
- m.Write(payload.ToArray(), 0, (int)payload.Length);
- }
-
- return m.ToArray();
- }
-
- ///
- /// Returns an empty iOS
- ///
- /// iOS
- internal static NFCNdefMessage EmptyNdefMessage
- {
- get
- {
- var records = new NFCNdefPayload[1];
- records[0] = NFCNdefPayloadExtensions.EmptyPayload;
- return new NFCNdefMessage(records);
- }
- }
- }
-
- ///
- /// NFC Ndef Payload Extensions Class
- ///
- internal static class NFCNdefPayloadExtensions
- {
- ///
- /// Returns ndef payload into MimeType
- ///
- ///
- /// string
- public static string ToMimeType(this NFCNdefPayload payload)
- {
- switch (payload.TypeNameFormat)
- {
- case NFCTypeNameFormat.NFCWellKnown:
- if (payload.Type.ToString() == "T")
- return "text/plain";
- break;
- case NFCTypeNameFormat.Media:
- return payload.Type.ToString();
- }
- return null;
- }
-
- ///
- /// Returns Ndef payload into URI
- ///
- ///
- ///
- public static Uri ToUri(this NFCNdefPayload payload)
- {
- switch (payload.TypeNameFormat)
- {
- case NFCTypeNameFormat.NFCWellKnown:
- if (payload.Type.ToString() == "U")
- {
- var uri = payload.Payload?.ParseWktUri();
- return uri;
- }
- break;
- case NFCTypeNameFormat.AbsoluteUri:
- case NFCTypeNameFormat.Media:
- var content = Encoding.UTF8.GetString(payload.Payload?.ToByteArray());
- if (Uri.TryCreate(content, UriKind.RelativeOrAbsolute, out var result))
- return result;
-
- break;
- }
- return null;
- }
-
- ///
- /// Returns complete URI of TNF_WELL_KNOWN, RTD_URI records.
- ///
- ///
- private static Uri ParseWktUri(this NSData data)
- {
- var payload = data.ToByteArray();
-
- if (payload.Length < 2)
- return null;
-
- var prefixIndex = payload[0] & 0xFF;
- if (prefixIndex < 0 || prefixIndex >= _uri_Prefixes_Map.Length)
- return null;
-
- var prefix = _uri_Prefixes_Map[prefixIndex];
- var suffix = Encoding.UTF8.GetString(CopyOfRange(payload, 1, payload.Length));
-
- if (Uri.TryCreate(prefix + suffix, UriKind.Absolute, out var result))
- return result;
-
- return null;
- }
-
- ///
- /// Copy a range of an array into another array
- ///
- /// Array of
- /// Start
- /// End
- /// Array of
- private static byte[] CopyOfRange(byte[] src, int start, int end)
- {
- var length = end - start;
- var dest = new byte[length];
- for (var i = 0; i < length; i++)
- dest[i] = src[start + i];
- return dest;
- }
-
- ///
- /// NFC Forum "URI Record Type Definition"
- /// This is a mapping of "URI Identifier Codes" to URI string prefixes,
- /// per section 3.2.2 of the NFC Forum URI Record Type Definition document.
- ///
- private static readonly string[] _uri_Prefixes_Map = new string[] {
- "", // 0x00
- "http://www.", // 0x01
- "https://www.", // 0x02
- "http://", // 0x03
- "https://", // 0x04
- "tel:", // 0x05
- "mailto:", // 0x06
- "ftp://anonymous:anonymous@", // 0x07
- "ftp://ftp.", // 0x08
- "ftps://", // 0x09
- "sftp://", // 0x0A
- "smb://", // 0x0B
- "nfs://", // 0x0C
- "ftp://", // 0x0D
- "dav://", // 0x0E
- "news:", // 0x0F
- "telnet://", // 0x10
- "imap:", // 0x11
- "rtsp://", // 0x12
- "urn:", // 0x13
- "pop:", // 0x14
- "sip:", // 0x15
- "sips:", // 0x16
- "tftp:", // 0x17
- "btspp://", // 0x18
- "btl2cap://", // 0x19
- "btgoep://", // 0x1A
- "tcpobex://", // 0x1B
- "irdaobex://", // 0x1C
- "file://", // 0x1D
- "urn:epc:id:", // 0x1E
- "urn:epc:tag:", // 0x1F
- "urn:epc:pat:", // 0x20
- "urn:epc:raw:", // 0x21
- "urn:epc:", // 0x22
- "urn:nfc:", // 0x23
- };
-
- ///
- /// Returns an empty iOS
- ///
- /// iOS
- internal static NFCNdefPayload EmptyPayload => new(NFCTypeNameFormat.Empty, new NSData(), new NSData(), new NSData());
-
- ///
- /// Transforms an array of into an array of
- ///
- /// Array of
- /// Array of
- internal static NFCNdefRecord[] GetRecords(NFCNdefPayload[] records)
- {
- if (records == null)
- return new NFCNdefRecord[0];
-
- var results = new NFCNdefRecord[records.Length];
- for (var i = 0; i < records.Length; i++)
- {
- var record = records[i];
- var ndefRecord = new NFCNdefRecord
- {
- TypeFormat = (NFCNdefTypeFormat)record.TypeNameFormat,
- Uri = records[i].ToUri()?.ToString(),
- MimeType = records[i].ToMimeType(),
- Payload = record.Payload?.ToByteArray()
- };
- results.SetValue(ndefRecord, i);
- }
- return results;
- }
-
- ///
- /// Returns NDEF payload
- ///
- ///
- ///
- internal static NFCNdefPayload GetiOSPayload(NFCNdefRecord record, NfcConfiguration configuration)
- {
- if (record == null)
- return null;
-
- NFCNdefPayload payload = null;
- switch (record.TypeFormat)
- {
- case NFCNdefTypeFormat.WellKnown:
- var lang = record.LanguageCode;
- if (string.IsNullOrWhiteSpace(lang)) lang = configuration.DefaultLanguageCode;
- var langData = Encoding.ASCII.GetBytes(lang.Substring(0, 2));
- var payloadData = new byte[] { 0x02 }.Concat(langData).Concat(record.Payload).ToArray();
- payload = new NFCNdefPayload(NFCTypeNameFormat.NFCWellKnown, NSData.FromString("T"), new NSData(), NSData.FromString(Encoding.UTF8.GetString(payloadData), NSStringEncoding.UTF8));
- break;
- case NFCNdefTypeFormat.Mime:
- payload = new NFCNdefPayload(NFCTypeNameFormat.Media, record.MimeType, new NSData(), NSData.FromArray(record.Payload));
- break;
- case NFCNdefTypeFormat.Uri:
- payload = NFCNdefPayload.CreateWellKnownTypePayload(NSUrl.FromString(Encoding.UTF8.GetString(record.Payload)));
- break;
- case NFCNdefTypeFormat.External:
- payload = new NFCNdefPayload(NFCTypeNameFormat.NFCExternal, record.ExternalType, new NSData(), NSData.FromString(Encoding.UTF8.GetString(record.Payload), NSStringEncoding.UTF8));
- break;
- case NFCNdefTypeFormat.Empty:
- payload = EmptyPayload;
- break;
- case NFCNdefTypeFormat.Unknown:
- case NFCNdefTypeFormat.Unchanged:
- case NFCNdefTypeFormat.Reserved:
- default:
- break;
- }
- return payload;
- }
- }
-
- ///
- /// NFC Tag Extensions Class
- ///
- internal static class NfcNdefTagExtensions
- {
- ///
- /// Get Ndef tag
- ///
- ///
- ///
- internal static INFCNdefTag GetNdefTag(INFCTag tag)
- {
- if (tag == null || !tag.Available)
- return null;
-
- INFCNdefTag ndef;
-
-#if NET6_0_OR_GREATER
- if (tag.Type == CoreNFC.NFCTagType.MiFare)
- ndef = tag.AsNFCMiFareTag;
- else if (tag.Type == CoreNFC.NFCTagType.Iso7816Compatible)
- ndef = tag.AsNFCIso7816Tag;
- else if (tag.Type == CoreNFC.NFCTagType.Iso15693)
- ndef = tag.AsNFCIso15693Tag;
- else if (tag.Type == CoreNFC.NFCTagType.FeliCa)
- ndef = tag.AsNFCFeliCaTag;
- else
- ndef = null;
-#else
- if (tag.GetNFCMiFareTag() != null)
- ndef = tag.GetNFCMiFareTag();
- else if (tag.GetNFCIso7816Tag() != null)
- ndef = tag.GetNFCIso7816Tag();
- else if (tag.GetNFCIso15693Tag() != null)
- ndef = tag.GetNFCIso15693Tag();
- else if (tag.GetNFCFeliCaTag() != null)
- ndef = tag.GetNFCFeliCaTag();
- else
- ndef = null;
-#endif
-
- return ndef;
- }
-
- ///
- /// Returns NFC Tag identifier
- ///
- ///
- /// Tag identifier
- internal static byte[] GetTagIdentifier(INFCNdefTag tag)
- {
- byte[] identifier = null;
- if (tag is INFCMiFareTag mifareTag)
- {
- identifier = mifareTag.Identifier.ToByteArray();
- }
- else if (tag is INFCFeliCaTag felicaTag)
- {
- identifier = felicaTag.CurrentIdm.ToByteArray();
- }
- else if (tag is INFCIso15693Tag iso15693Tag)
- {
- identifier = iso15693Tag.Identifier.ToByteArray().Reverse().ToArray();
- }
- else if (tag is INFCIso7816Tag iso7816Tag)
- {
- identifier = iso7816Tag.Identifier.ToByteArray();
- }
- return identifier;
- }
- }
-}
+using CoreFoundation;
+using CoreNFC;
+using Foundation;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using UIKit;
+
+namespace Plugin.NFC
+{
+ ///
+ /// iOS 13+ implementation of
+ ///
+ public class NFCImplementation : NFCTagReaderSessionDelegate, INFC
+ {
+ public const string SessionTimeoutMessage = "session timeout";
+
+ public event EventHandler OnTagConnected;
+ public event EventHandler OnTagDisconnected;
+ public event NdefMessageReceivedEventHandler OnMessageReceived;
+ public event NdefMessagePublishedEventHandler OnMessagePublished;
+ public event TagDiscoveredEventHandler OnTagDiscovered;
+ public event EventHandler OniOSReadingSessionCancelled;
+ public event OnNfcStatusChangedEventHandler OnNfcStatusChanged;
+ public event TagListeningStatusChangedEventHandler OnTagListeningStatusChanged;
+
+ bool _isWriting;
+ bool _isFormatting;
+ bool _customInvalidation = false;
+
+ INFCTag _tag;
+
+ NFCTagReaderSession NfcSession { get; set; }
+
+ ///
+ /// Checks if NFC Feature is available
+ ///
+ public bool IsAvailable => NFCReaderSession.ReadingAvailable;
+
+ ///
+ /// Checks if NFC Feature is enabled
+ ///
+ public bool IsEnabled => IsAvailable;
+
+ ///
+ /// Checks if writing mode is supported
+ ///
+ public bool IsWritingTagSupported => true;
+
+ ///
+ /// NFC configuration
+ ///
+ public NfcConfiguration Configuration { get; private set; }
+
+ ///
+ /// Default constructor
+ ///
+ public NFCImplementation()
+ {
+ Configuration = NfcConfiguration.GetDefaultConfiguration();
+ }
+
+ ///
+ /// Update NFC configuration
+ ///
+ ///
+ public void SetConfiguration(NfcConfiguration configuration) => Configuration.Update(configuration);
+
+ ///
+ /// Starts tags detection
+ ///
+ public void StartListening()
+ {
+ _customInvalidation = false;
+ _isWriting = false;
+ _isFormatting = false;
+
+ NfcSession = new NFCTagReaderSession(NFCPollingOption.Iso14443 | NFCPollingOption.Iso15693, this, DispatchQueue.CurrentQueue)
+ {
+ AlertMessage = Configuration.Messages.NFCDialogAlertMessage
+ };
+ NfcSession?.BeginSession();
+ OnTagListeningStatusChanged?.Invoke(true);
+ }
+
+ ///
+ /// Stops tags detection
+ ///
+ public void StopListening()
+ {
+ NfcSession?.InvalidateSession();
+ }
+
+ ///
+ /// Starts tag publishing (writing or formatting)
+ ///
+ /// Format tag
+ public void StartPublishing(bool clearMessage = false)
+ {
+ if (!IsAvailable)
+ throw new InvalidOperationException(Configuration.Messages.NFCWritingNotSupported);
+
+ _customInvalidation = false;
+ _isWriting = true;
+ _isFormatting = clearMessage;
+
+ NfcSession = new NFCTagReaderSession(NFCPollingOption.Iso14443 | NFCPollingOption.Iso15693, this, DispatchQueue.CurrentQueue)
+ {
+ AlertMessage = Configuration.Messages.NFCDialogAlertMessage
+ };
+ NfcSession?.BeginSession();
+ OnTagListeningStatusChanged?.Invoke(true);
+ }
+
+ ///
+ /// Stops tag publishing
+ ///
+ public void StopPublishing()
+ {
+ _isWriting = _isFormatting = _customInvalidation = false;
+ _tag = null;
+ NfcSession?.InvalidateSession();
+ }
+
+ ///
+ /// Publish or write a message on a tag
+ ///
+ /// see
+ /// make tag read-only
+ public void PublishMessage(ITagInfo tagInfo, bool makeReadOnly = false) => WriteOrClearMessage(_tag, tagInfo, false, makeReadOnly);
+
+ ///
+ /// Format tag
+ ///
+ /// see
+ public void ClearMessage(ITagInfo tagInfo) => WriteOrClearMessage(_tag, tagInfo, true);
+
+ ///
+ /// Event raised when NFC tags are detected
+ ///
+ /// iOS
+ /// Array of iOS
+ public override void DidDetectTags(NFCTagReaderSession session, INFCTag[] tags)
+ {
+ _customInvalidation = false;
+ _tag = tags.First();
+
+ var connectionError = string.Empty;
+ session.ConnectTo(_tag, (error) =>
+ {
+ if (error != null)
+ {
+ connectionError = error.LocalizedDescription;
+ Invalidate(session, connectionError);
+ return;
+ }
+
+ var ndefTag = NfcNdefTagExtensions.GetNdefTag(_tag);
+
+ if (ndefTag == null)
+ {
+ Invalidate(session, Configuration.Messages.NFCErrorNotCompliantTag);
+ return;
+ }
+
+ ndefTag.QueryNdefStatus((status, capacity, error) =>
+ {
+ if (error != null)
+ {
+ Invalidate(session, error.LocalizedDescription);
+ return;
+ }
+
+ var isNdefSupported = status != NFCNdefStatus.NotSupported;
+
+ var identifier = NfcNdefTagExtensions.GetTagIdentifier(ndefTag);
+ var nTag = new TagInfo(identifier, isNdefSupported)
+ {
+ IsWritable = status == NFCNdefStatus.ReadWrite,
+ Capacity = Convert.ToInt32(capacity)
+ };
+
+ if (!isNdefSupported)
+ {
+ session.AlertMessage = Configuration.Messages.NFCErrorNotSupportedTag;
+
+ OnMessageReceived?.Invoke(nTag);
+ Invalidate(session);
+ return;
+ }
+
+ if (_isWriting)
+ {
+ // Write mode
+ OnTagDiscovered?.Invoke(nTag, _isFormatting);
+ }
+ else
+ {
+ // Read mode
+ ndefTag.ReadNdef((message, error) =>
+ {
+ // iOS Error: NFCReaderError.NdefReaderSessionErrorZeroLengthMessage (NDEF tag does not contain any NDEF message)
+ // NFCReaderError.NdefReaderSessionErrorZeroLengthMessage constant should be equals to 403 instead of 304
+ // see https://developer.apple.com/documentation/corenfc/nfcreadererror/code/ndefreadersessionerrorzerolengthmessage
+ if (error != null && error.Code != 403)
+ {
+ Invalidate(session, Configuration.Messages.NFCErrorRead);
+ return;
+ }
+
+ session.AlertMessage = Configuration.Messages.NFCSuccessRead;
+
+ nTag.Records = NFCNdefPayloadExtensions.GetRecords(message?.Records);
+ OnMessageReceived?.Invoke(nTag);
+ Invalidate(session);
+ });
+ }
+ });
+ });
+ }
+
+ ///
+ /// Event raised when an error happened during detection
+ ///
+ /// iOS
+ /// iOS
+ public override void DidInvalidate(NFCTagReaderSession session, NSError error)
+ {
+ OnTagListeningStatusChanged?.Invoke(false);
+
+ var readerError = (NFCReaderError)(long)error.Code;
+ if (readerError != NFCReaderError.ReaderSessionInvalidationErrorFirstNDEFTagRead && readerError != NFCReaderError.ReaderSessionInvalidationErrorUserCanceled)
+ {
+ var alertController = UIAlertController.Create(Configuration.Messages.NFCSessionInvalidated, error.LocalizedDescription.ToLower().Equals(SessionTimeoutMessage) ? Configuration.Messages.NFCSessionTimeout : error.LocalizedDescription, UIAlertControllerStyle.Alert);
+ alertController.AddAction(UIAlertAction.Create(Configuration.Messages.NFCSessionInvalidatedButton, UIAlertActionStyle.Default, null));
+ OniOSReadingSessionCancelled?.Invoke(null, EventArgs.Empty);
+ DispatchQueue.MainQueue.DispatchAsync(() =>
+ {
+ GetCurrentController().PresentViewController(alertController, true, null);
+ });
+ }
+ else if (readerError == NFCReaderError.ReaderSessionInvalidationErrorUserCanceled && !_customInvalidation)
+ OniOSReadingSessionCancelled?.Invoke(null, EventArgs.Empty);
+ }
+
+ ///
+ /// Write or Clear a NDEF message
+ ///
+ ///
+ ///
+ /// Clear Message
+ /// Make a tag read-only
+ internal void WriteOrClearMessage(INFCTag tag, ITagInfo tagInfo, bool clearMessage = false, bool makeReadOnly = false)
+ {
+ if (NfcSession == null)
+ return;
+
+ if (tag == null)
+ {
+ Invalidate(NfcSession, Configuration.Messages.NFCErrorMissingTag);
+ return;
+ }
+
+ if (tagInfo == null || (!clearMessage && tagInfo.Records.Any(record => record.Payload == null)))
+ {
+ Invalidate(NfcSession, Configuration.Messages.NFCErrorMissingTagInfo);
+ return;
+ }
+
+ var ndefTag = NfcNdefTagExtensions.GetNdefTag(tag);
+ if (ndefTag == null)
+ {
+ Invalidate(NfcSession, Configuration.Messages.NFCErrorNotCompliantTag);
+ return;
+ }
+
+ try
+ {
+ if (!ndefTag.Available)
+ {
+ NfcSession.ConnectTo(tag, (error) =>
+ {
+ if (error != null)
+ {
+ Invalidate(NfcSession, error.LocalizedDescription);
+ return;
+ }
+
+ ExecuteWriteOrClear(NfcSession, ndefTag, tagInfo, clearMessage);
+ });
+ }
+ else
+ {
+ ExecuteWriteOrClear(NfcSession, ndefTag, tagInfo, clearMessage);
+ }
+
+ if (!clearMessage && makeReadOnly)
+ {
+ MakeTagReadOnly(NfcSession, tag, ndefTag);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.StackTrace);
+ }
+ finally
+ {
+ OnTagDisconnected?.Invoke(null, EventArgs.Empty);
+ }
+ }
+
+ #region Private
+
+ ///
+ /// Returns the current iOS controller
+ ///
+ /// Object
+ UIViewController GetCurrentController()
+ {
+ var window = UIApplication.SharedApplication.KeyWindow;
+ var vc = window.RootViewController;
+ while (vc.PresentedViewController != null)
+ vc = vc.PresentedViewController;
+ return vc;
+ }
+
+ ///
+ /// Invalidate the session
+ ///
+ ///
+ /// Message to show
+ void Invalidate(NFCTagReaderSession session, string message = null)
+ {
+ _customInvalidation = true;
+ if (string.IsNullOrWhiteSpace(message))
+ session.InvalidateSession();
+ else
+ session.InvalidateSession(message);
+ }
+
+ ///
+ /// Writes or clears a TAG
+ ///
+ ///
+ ///
+ ///
+ /// Clear message
+ void ExecuteWriteOrClear(NFCTagReaderSession session, INFCNdefTag tag, ITagInfo tagInfo, bool clearMessage = false)
+ {
+ tag.QueryNdefStatus((status, capacity, error) =>
+ {
+ if (error != null)
+ {
+ Invalidate(session, error.LocalizedDescription);
+ return;
+ }
+
+ if (status == NFCNdefStatus.ReadOnly)
+ {
+ Invalidate(session, Configuration.Messages.NFCErrorReadOnlyTag);
+ return;
+ }
+
+ if (Convert.ToInt32(capacity) < NFCUtils.GetSize(tagInfo.Records))
+ {
+ Invalidate(session, Configuration.Messages.NFCErrorCapacityTag);
+ return;
+ }
+
+ NFCNdefMessage message = null;
+ if (!clearMessage)
+ {
+ session.AlertMessage = Configuration.Messages.NFCSuccessWrite;
+
+ var records = new List();
+ for (var i = 0; i < tagInfo.Records.Length; i++)
+ {
+ var record = tagInfo.Records[i];
+ if (NFCNdefPayloadExtensions.GetiOSPayload(record, Configuration) is NFCNdefPayload ndefPayload)
+ records.Add(ndefPayload);
+ }
+
+ if (records.Any())
+ message = new NFCNdefMessage(records.ToArray());
+ }
+ else
+ {
+ session.AlertMessage = Configuration.Messages.NFCSuccessClear;
+ message = NFCNdefMessageExtensions.EmptyNdefMessage;
+ }
+
+ if (message != null)
+ {
+ tag.WriteNdef(message, (error) =>
+ {
+ if (error != null)
+ {
+ Invalidate(session, error.LocalizedDescription);
+ return;
+ }
+
+ tagInfo.Records = NFCNdefPayloadExtensions.GetRecords(message.Records);
+ OnMessagePublished?.Invoke(tagInfo);
+ Invalidate(NfcSession);
+ });
+ }
+ else
+ Invalidate(session, Configuration.Messages.NFCErrorWrite);
+ });
+ }
+
+ ///
+ /// Make a tag read-only
+ /// WARNING: This operation is permanent
+ ///
+ ///
+ ///
+ ///
+ void MakeTagReadOnly(NFCTagReaderSession session, INFCTag tag, INFCNdefTag ndefTag)
+ {
+ session.ConnectTo(tag, (error) =>
+ {
+ if (error != null)
+ {
+ Console.WriteLine(error.LocalizedDescription);
+ return;
+ }
+
+ ndefTag.WriteLock((error) =>
+ {
+ if (error != null)
+ Console.WriteLine("Error when locking a tag on iOS: " + error.LocalizedDescription);
+ else
+ Console.WriteLine("Locking Successful!");
+ });
+ });
+ }
+
+ #endregion
+ }
+
+ ///
+ /// Old iOS implementation of (iOS < 13)
+ ///
+ public class NFCImplementation_Before_iOS13 : NFCNdefReaderSessionDelegate, INFC
+ {
+ public const string SessionTimeoutMessage = "session timeout";
+
+ private bool _isWriting;
+ private bool _isFormatting;
+ private bool _customInvalidation = false;
+ private INFCNdefTag _tag;
+
+ public event EventHandler OnTagConnected;
+ public event EventHandler OnTagDisconnected;
+ public event NdefMessageReceivedEventHandler OnMessageReceived;
+ public event NdefMessagePublishedEventHandler OnMessagePublished;
+ public event TagDiscoveredEventHandler OnTagDiscovered;
+ public event EventHandler OniOSReadingSessionCancelled;
+ public event OnNfcStatusChangedEventHandler OnNfcStatusChanged;
+ public event TagListeningStatusChangedEventHandler OnTagListeningStatusChanged;
+
+ NFCNdefReaderSession NfcSession { get; set; }
+
+ ///
+ /// Checks if NFC Feature is available
+ ///
+ public bool IsAvailable => NFCNdefReaderSession.ReadingAvailable;
+
+ ///
+ /// Checks if NFC Feature is enabled
+ ///
+ public bool IsEnabled => IsAvailable;
+
+ ///
+ /// Checks if writing mode is supported
+ ///
+ public bool IsWritingTagSupported => NFCUtils.IsWritingSupported();
+
+ ///
+ /// NFC configuration
+ ///
+ public NfcConfiguration Configuration { get; private set; }
+
+ ///
+ /// Default constructor
+ ///
+ public NFCImplementation_Before_iOS13()
+ {
+ Configuration = NfcConfiguration.GetDefaultConfiguration();
+ }
+
+ ///
+ /// Update NFC configuration
+ ///
+ ///
+ public void SetConfiguration(NfcConfiguration configuration) => Configuration.Update(configuration);
+
+ ///
+ /// Starts tags detection
+ ///
+ public void StartListening()
+ {
+ _customInvalidation = false;
+ _isWriting = false;
+ _isFormatting = false;
+
+ NfcSession = new NFCNdefReaderSession(this, DispatchQueue.CurrentQueue, true)
+ {
+ AlertMessage = Configuration.Messages.NFCDialogAlertMessage
+ };
+
+ NfcSession?.BeginSession();
+ OnTagListeningStatusChanged?.Invoke(true);
+ }
+
+ ///
+ /// Stops tags detection
+ ///
+ public void StopListening()
+ {
+ NfcSession?.InvalidateSession();
+ }
+
+ ///
+ /// Starts tag publishing (writing or formatting)
+ ///
+ /// Format tag
+ public void StartPublishing(bool clearMessage = false)
+ {
+ if (!IsAvailable)
+ {
+ throw new InvalidOperationException(Configuration.Messages.NFCWritingNotSupported);
+ }
+
+ _customInvalidation = false;
+ _isWriting = true;
+ _isFormatting = clearMessage;
+
+ NfcSession = new NFCNdefReaderSession(this, DispatchQueue.CurrentQueue, true)
+ {
+ AlertMessage = Configuration.Messages.NFCDialogAlertMessage
+ };
+ NfcSession?.BeginSession();
+ OnTagListeningStatusChanged?.Invoke(true);
+ }
+
+ ///
+ /// Stops tag publishing
+ ///
+ public void StopPublishing()
+ {
+ _isWriting = _isFormatting = _customInvalidation = false;
+ _tag = null;
+ NfcSession?.InvalidateSession();
+ }
+
+ ///
+ /// Publish or write a message on a tag
+ ///
+ /// see
+ /// Make a tag read-only
+ public void PublishMessage(ITagInfo tagInfo, bool makeReadOnly = false) => WriteOrClearMessage(_tag, tagInfo, false, makeReadOnly);
+
+ ///
+ /// Format tag
+ ///
+ /// see
+ public void ClearMessage(ITagInfo tagInfo) => WriteOrClearMessage(_tag, tagInfo, true);
+
+ ///
+ /// Event raised when NDEF messages are detected
+ ///
+ /// iOS
+ /// Array of iOS
+ public override void DidDetect(NFCNdefReaderSession session, NFCNdefMessage[] messages)
+ {
+ OnTagConnected?.Invoke(null, EventArgs.Empty);
+
+ if (messages != null && messages.Length > 0)
+ {
+ var first = messages[0];
+ var tagInfo = new TagInfo
+ {
+ IsWritable = false,
+ Records = NFCNdefPayloadExtensions.GetRecords(first.Records)
+ };
+ OnMessageReceived?.Invoke(tagInfo);
+ }
+
+ OnTagDisconnected?.Invoke(null, EventArgs.Empty);
+ }
+
+ ///
+ /// Event raised when NFC tag detected
+ ///
+ /// iOS
+ /// Array of iOS
+ public override void DidDetectTags(NFCNdefReaderSession session, INFCNdefTag[] tags)
+ {
+ _customInvalidation = false;
+ _tag = tags.First();
+
+ session.ConnectToTag(_tag, error =>
+ {
+ if (error != null)
+ {
+ Invalidate(session, error.LocalizedDescription);
+ return;
+ }
+
+ if (_tag == null)
+ {
+ Invalidate(session, Configuration.Messages.NFCErrorNotCompliantTag);
+ return;
+ }
+
+ _tag.QueryNdefStatus((status, capacity, ndefError) =>
+ {
+ if (ndefError != null)
+ {
+ Invalidate(session, ndefError.LocalizedDescription);
+ return;
+ }
+
+ var isNdefSupported = status != NFCNdefStatus.NotSupported;
+
+ var identifier = NfcNdefTagExtensions.GetTagIdentifier(_tag);
+ var nTag = new TagInfo(identifier, isNdefSupported)
+ {
+ IsWritable = status == NFCNdefStatus.ReadWrite,
+ Capacity = Convert.ToInt32(capacity)
+ };
+
+ if (!isNdefSupported)
+ {
+ session.AlertMessage = Configuration.Messages.NFCErrorNotSupportedTag;
+
+ OnMessageReceived?.Invoke(nTag);
+ Invalidate(session);
+ return;
+ }
+
+ if (_isWriting)
+ {
+ // Write mode
+ OnTagDiscovered?.Invoke(nTag, _isFormatting);
+ }
+ else
+ {
+ // Read mode
+ _tag.ReadNdef((message, readError) =>
+ {
+ if (readError != null)
+ {
+ Invalidate(session, readError.Code == (int)NFCReaderError.NdefReaderSessionErrorZeroLengthMessage
+ ? Configuration.Messages.NFCErrorEmptyTag
+ : Configuration.Messages.NFCErrorRead);
+ return;
+ }
+
+ session.AlertMessage = Configuration.Messages.NFCSuccessRead;
+
+ nTag.Records = NFCNdefPayloadExtensions.GetRecords(message?.Records);
+ OnMessageReceived?.Invoke(nTag);
+ Invalidate(session);
+ });
+ }
+ });
+ });
+ }
+
+ ///
+ /// Event raised when an error happened during detection
+ ///
+ /// iOS
+ /// iOS
+ public override void DidInvalidate(NFCNdefReaderSession session, NSError error)
+ {
+ OnTagListeningStatusChanged?.Invoke(false);
+
+ var readerError = (NFCReaderError)(long)error.Code;
+ if (readerError != NFCReaderError.ReaderSessionInvalidationErrorFirstNDEFTagRead && readerError != NFCReaderError.ReaderSessionInvalidationErrorUserCanceled)
+ {
+ var alertController = UIAlertController.Create(Configuration.Messages.NFCSessionInvalidated, error.LocalizedDescription.ToLower().Equals(SessionTimeoutMessage) ? Configuration.Messages.NFCSessionTimeout : error.LocalizedDescription, UIAlertControllerStyle.Alert);
+ alertController.AddAction(UIAlertAction.Create(Configuration.Messages.NFCSessionInvalidatedButton, UIAlertActionStyle.Default, null));
+ OniOSReadingSessionCancelled?.Invoke(null, EventArgs.Empty);
+ DispatchQueue.MainQueue.DispatchAsync(() =>
+ {
+ GetCurrentController().PresentViewController(alertController, true, null);
+ });
+ }
+ else if (readerError == NFCReaderError.ReaderSessionInvalidationErrorUserCanceled && !_customInvalidation)
+ {
+ OniOSReadingSessionCancelled?.Invoke(null, EventArgs.Empty);
+ }
+ }
+
+ ///
+ /// Write or Clear a NDEF message
+ ///
+ ///
+ ///
+ /// Clear Message
+ /// Make a tag read-only
+ internal void WriteOrClearMessage(INFCNdefTag tag, ITagInfo tagInfo, bool clearMessage = false, bool makeReadOnly = false)
+ {
+ if (NfcSession == null)
+ {
+ return;
+ }
+
+ if (tag == null)
+ {
+ Invalidate(NfcSession, Configuration.Messages.NFCErrorMissingTag);
+ return;
+ }
+
+ if (tagInfo == null || (!clearMessage && tagInfo.Records.Any(record => record.Payload == null)))
+ {
+ Invalidate(NfcSession, Configuration.Messages.NFCErrorMissingTagInfo);
+ return;
+ }
+
+ if (_tag == null)
+ {
+ Invalidate(NfcSession, Configuration.Messages.NFCErrorNotCompliantTag);
+ return;
+ }
+
+ try
+ {
+ if (!_tag.Available)
+ {
+ NfcSession.ConnectToTag(_tag, (error) =>
+ {
+ if (error != null)
+ {
+ Invalidate(NfcSession, error.LocalizedDescription);
+ return;
+ }
+
+ ExecuteWriteOrClear(NfcSession, _tag, tagInfo, clearMessage);
+ });
+ }
+ else
+ {
+ ExecuteWriteOrClear(NfcSession, _tag, tagInfo, clearMessage);
+ }
+
+ if (!clearMessage && makeReadOnly)
+ {
+ MakeTagReadOnly(NfcSession, tag);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.StackTrace);
+ }
+ finally
+ {
+ OnTagDisconnected?.Invoke(null, EventArgs.Empty);
+ }
+ }
+
+ #region Private
+
+ ///
+ /// Returns the current iOS controller
+ ///
+ /// Object
+ UIViewController GetCurrentController()
+ {
+ var window = UIApplication.SharedApplication.KeyWindow;
+ var vc = window.RootViewController;
+ while (vc.PresentedViewController != null)
+ vc = vc.PresentedViewController;
+ return vc;
+ }
+
+ ///
+ /// Writes or clears a TAG
+ ///
+ ///
+ ///
+ ///
+ /// Clear message
+ private void ExecuteWriteOrClear(NFCNdefReaderSession session, INFCNdefTag tag, ITagInfo tagInfo, bool clearMessage = false)
+ {
+ tag.QueryNdefStatus((status, capacity, error) =>
+ {
+ if (error != null)
+ {
+ Invalidate(session, error.LocalizedDescription);
+ return;
+ }
+
+ if (status == NFCNdefStatus.ReadOnly)
+ {
+ Invalidate(session, Configuration.Messages.NFCErrorReadOnlyTag);
+ return;
+ }
+
+ if (Convert.ToInt32(capacity) < NFCUtils.GetSize(tagInfo.Records))
+ {
+ Invalidate(session, Configuration.Messages.NFCErrorCapacityTag);
+ return;
+ }
+
+ NFCNdefMessage message = null;
+ if (!clearMessage)
+ {
+ session.AlertMessage = Configuration.Messages.NFCSuccessWrite;
+
+ var records = new List();
+ for (var i = 0; i < tagInfo.Records.Length; i++)
+ {
+ var record = tagInfo.Records[i];
+ if (NFCNdefPayloadExtensions.GetiOSPayload(record, Configuration) is NFCNdefPayload ndefPayload)
+ records.Add(ndefPayload);
+ }
+
+ if (records.Any())
+ message = new NFCNdefMessage(records.ToArray());
+ }
+ else
+ {
+ session.AlertMessage = Configuration.Messages.NFCSuccessClear;
+ message = NFCNdefMessageExtensions.EmptyNdefMessage;
+ }
+
+ if (message != null)
+ {
+ tag.WriteNdef(message, (error) =>
+ {
+ if (error != null)
+ {
+ Invalidate(session, error.LocalizedDescription);
+ return;
+ }
+
+ tagInfo.Records = NFCNdefPayloadExtensions.GetRecords(message.Records);
+ OnMessagePublished?.Invoke(tagInfo);
+ Invalidate(NfcSession);
+ });
+ }
+ else
+ Invalidate(session, Configuration.Messages.NFCErrorWrite);
+ });
+ }
+
+ ///
+ /// Make a tag read-only
+ /// WARNING: This operation is permanent
+ ///
+ ///
+ ///
+ ///
+ private void MakeTagReadOnly(NFCNdefReaderSession session, INFCNdefTag tag)
+ {
+ session.ConnectToTag(tag, (error) =>
+ {
+ if (error != null)
+ {
+ Console.WriteLine(error.LocalizedDescription);
+ return;
+ }
+
+ tag.WriteLock((error) =>
+ {
+ if (error != null)
+ Console.WriteLine("Error when locking a tag on iOS: " + error.LocalizedDescription);
+ else
+ Console.WriteLine("Locking Successful!");
+ });
+ });
+ }
+
+ ///
+ /// Invalidate the session
+ ///
+ ///
+ /// Message to show
+ void Invalidate(NFCNdefReaderSession session, string message = null)
+ {
+ _customInvalidation = true;
+ if (string.IsNullOrWhiteSpace(message))
+ session.InvalidateSession();
+ else
+ session.InvalidateSession(message);
+ }
+
+ #endregion
+ }
+
+ ///
+ /// NFC Ndef Message extensions class
+ ///
+ internal static class NFCNdefMessageExtensions
+ {
+ ///
+ /// Convert an iOS into an array of bytes
+ ///
+ /// iOS
+ /// Array of bytes
+ public static byte[] ToByteArray(this NSData data)
+ {
+ var bytes = new byte[data.Length];
+ if (data.Length > 0) System.Runtime.InteropServices.Marshal.Copy(data.Bytes, bytes, 0, Convert.ToInt32(data.Length));
+ return bytes;
+ }
+
+ ///
+ /// Converte an iOS into an array of bytes
+ ///
+ /// iOS
+ /// Array of bytes
+ public static byte[] ToByteArray(this NFCNdefMessage message)
+ {
+ var records = message?.Records;
+
+ // Empty message: single empty record
+ if (records == null || records.Length == 0)
+ {
+ records = new NFCNdefPayload[] { null };
+ }
+
+ var m = new MemoryStream();
+ for (var i = 0; i < records.Length; i++)
+ {
+ var record = records[i];
+ var typeNameFormat = record?.TypeNameFormat ?? NFCTypeNameFormat.Empty;
+ var payload = record?.Payload;
+ var id = record?.Identifier;
+ var type = record?.Type;
+
+ var flags = (byte)typeNameFormat;
+
+ // Message begin / end flags. If there is only one record in the message, both flags are set.
+ if (i == 0)
+ flags |= 0x80; // MB (message begin = first record in the message)
+ if (i == records.Length - 1)
+ flags |= 0x40; // ME (message end = last record in the message)
+
+ // cf (chunked records) not supported yet
+
+ // SR (Short Record)?
+ if (payload == null || payload.Length < 255)
+ flags |= 0x10;
+
+ // ID present?
+ if (id != null && id.Length > 0)
+ flags |= 0x08;
+
+ m.WriteByte(flags);
+
+ // Type length
+ if (type != null)
+ m.WriteByte((byte)type.Length);
+ else
+ m.WriteByte(0);
+
+ // Payload length 1 byte (SR) or 4 bytes
+ if (payload == null)
+ {
+ m.WriteByte(0);
+ }
+ else
+ {
+ if ((flags & 0x10) != 0)
+ {
+ // SR
+ m.WriteByte((byte)payload.Length);
+ }
+ else
+ {
+ // No SR (Short Record)
+ var payloadLength = (uint)payload.Length;
+ m.WriteByte((byte)(payloadLength >> 24));
+ m.WriteByte((byte)(payloadLength >> 16));
+ m.WriteByte((byte)(payloadLength >> 8));
+ m.WriteByte((byte)(payloadLength & 0x000000ff));
+ }
+ }
+
+ // ID length
+ if (id != null && (flags & 0x08) != 0)
+ m.WriteByte((byte)id.Length);
+
+ // Type length
+ if (type != null && type.Length > 0)
+ m.Write(type.ToArray(), 0, (int)type.Length);
+
+ // ID data
+ if (id != null && id.Length > 0)
+ m.Write(id.ToArray(), 0, (int)id.Length);
+
+ // Payload data
+ if (payload != null && payload.Length > 0)
+ m.Write(payload.ToArray(), 0, (int)payload.Length);
+ }
+
+ return m.ToArray();
+ }
+
+ ///
+ /// Returns an empty iOS
+ ///
+ /// iOS
+ internal static NFCNdefMessage EmptyNdefMessage
+ {
+ get
+ {
+ var records = new NFCNdefPayload[1];
+ records[0] = NFCNdefPayloadExtensions.EmptyPayload;
+ return new NFCNdefMessage(records);
+ }
+ }
+ }
+
+ ///
+ /// NFC Ndef Payload Extensions Class
+ ///
+ internal static class NFCNdefPayloadExtensions
+ {
+ ///
+ /// Returns ndef payload into MimeType
+ ///
+ ///
+ /// string
+ public static string ToMimeType(this NFCNdefPayload payload)
+ {
+ switch (payload.TypeNameFormat)
+ {
+ case NFCTypeNameFormat.NFCWellKnown:
+ if (payload.Type.ToString() == "T")
+ return "text/plain";
+ break;
+ case NFCTypeNameFormat.Media:
+ return payload.Type.ToString();
+ }
+ return null;
+ }
+
+ ///
+ /// Returns Ndef payload into URI
+ ///
+ ///
+ ///
+ public static Uri ToUri(this NFCNdefPayload payload)
+ {
+ switch (payload.TypeNameFormat)
+ {
+ case NFCTypeNameFormat.NFCWellKnown:
+ if (payload.Type.ToString() == "U")
+ {
+ var uri = payload.Payload?.ParseWktUri();
+ return uri;
+ }
+ break;
+ case NFCTypeNameFormat.AbsoluteUri:
+ case NFCTypeNameFormat.Media:
+ var content = Encoding.UTF8.GetString(payload.Payload?.ToByteArray());
+ if (Uri.TryCreate(content, UriKind.RelativeOrAbsolute, out var result))
+ return result;
+
+ break;
+ }
+ return null;
+ }
+
+ ///
+ /// Returns complete URI of TNF_WELL_KNOWN, RTD_URI records.
+ ///
+ ///
+ private static Uri ParseWktUri(this NSData data)
+ {
+ var payload = data.ToByteArray();
+
+ if (payload.Length < 2)
+ return null;
+
+ var prefixIndex = payload[0] & 0xFF;
+ if (prefixIndex < 0 || prefixIndex >= _uri_Prefixes_Map.Length)
+ return null;
+
+ var prefix = _uri_Prefixes_Map[prefixIndex];
+ var suffix = Encoding.UTF8.GetString(CopyOfRange(payload, 1, payload.Length));
+
+ if (Uri.TryCreate(prefix + suffix, UriKind.Absolute, out var result))
+ return result;
+
+ return null;
+ }
+
+ ///
+ /// Copy a range of an array into another array
+ ///
+ /// Array of
+ /// Start
+ /// End
+ /// Array of
+ private static byte[] CopyOfRange(byte[] src, int start, int end)
+ {
+ var length = end - start;
+ var dest = new byte[length];
+ for (var i = 0; i < length; i++)
+ dest[i] = src[start + i];
+ return dest;
+ }
+
+ ///
+ /// NFC Forum "URI Record Type Definition"
+ /// This is a mapping of "URI Identifier Codes" to URI string prefixes,
+ /// per section 3.2.2 of the NFC Forum URI Record Type Definition document.
+ ///
+ private static readonly string[] _uri_Prefixes_Map = new string[] {
+ "", // 0x00
+ "http://www.", // 0x01
+ "https://www.", // 0x02
+ "http://", // 0x03
+ "https://", // 0x04
+ "tel:", // 0x05
+ "mailto:", // 0x06
+ "ftp://anonymous:anonymous@", // 0x07
+ "ftp://ftp.", // 0x08
+ "ftps://", // 0x09
+ "sftp://", // 0x0A
+ "smb://", // 0x0B
+ "nfs://", // 0x0C
+ "ftp://", // 0x0D
+ "dav://", // 0x0E
+ "news:", // 0x0F
+ "telnet://", // 0x10
+ "imap:", // 0x11
+ "rtsp://", // 0x12
+ "urn:", // 0x13
+ "pop:", // 0x14
+ "sip:", // 0x15
+ "sips:", // 0x16
+ "tftp:", // 0x17
+ "btspp://", // 0x18
+ "btl2cap://", // 0x19
+ "btgoep://", // 0x1A
+ "tcpobex://", // 0x1B
+ "irdaobex://", // 0x1C
+ "file://", // 0x1D
+ "urn:epc:id:", // 0x1E
+ "urn:epc:tag:", // 0x1F
+ "urn:epc:pat:", // 0x20
+ "urn:epc:raw:", // 0x21
+ "urn:epc:", // 0x22
+ "urn:nfc:", // 0x23
+ };
+
+ ///
+ /// Returns an empty iOS
+ ///
+ /// iOS
+ internal static NFCNdefPayload EmptyPayload => new(NFCTypeNameFormat.Empty, new NSData(), new NSData(), new NSData());
+
+ ///
+ /// Transforms an array of into an array of
+ ///
+ /// Array of
+ /// Array of
+ internal static NFCNdefRecord[] GetRecords(NFCNdefPayload[] records)
+ {
+ if (records == null)
+ return new NFCNdefRecord[0];
+
+ var results = new NFCNdefRecord[records.Length];
+ for (var i = 0; i < records.Length; i++)
+ {
+ var record = records[i];
+ var ndefRecord = new NFCNdefRecord
+ {
+ TypeFormat = (NFCNdefTypeFormat)record.TypeNameFormat,
+ Uri = records[i].ToUri()?.ToString(),
+ MimeType = records[i].ToMimeType(),
+ Payload = record.Payload?.ToByteArray()
+ };
+ results.SetValue(ndefRecord, i);
+ }
+ return results;
+ }
+
+ ///
+ /// Returns NDEF payload
+ ///
+ ///
+ ///
+ internal static NFCNdefPayload GetiOSPayload(NFCNdefRecord record, NfcConfiguration configuration)
+ {
+ if (record == null)
+ return null;
+
+ NFCNdefPayload payload = null;
+ switch (record.TypeFormat)
+ {
+ case NFCNdefTypeFormat.WellKnown:
+ var lang = record.LanguageCode;
+ if (string.IsNullOrWhiteSpace(lang)) lang = configuration.DefaultLanguageCode;
+ var langData = Encoding.ASCII.GetBytes(lang.Substring(0, 2));
+ var payloadData = new byte[] { 0x02 }.Concat(langData).Concat(record.Payload).ToArray();
+ payload = new NFCNdefPayload(NFCTypeNameFormat.NFCWellKnown, NSData.FromString("T"), new NSData(), NSData.FromString(Encoding.UTF8.GetString(payloadData), NSStringEncoding.UTF8));
+ break;
+ case NFCNdefTypeFormat.Mime:
+ payload = new NFCNdefPayload(NFCTypeNameFormat.Media, record.MimeType, new NSData(), NSData.FromArray(record.Payload));
+ break;
+ case NFCNdefTypeFormat.Uri:
+ payload = NFCNdefPayload.CreateWellKnownTypePayload(NSUrl.FromString(Encoding.UTF8.GetString(record.Payload)));
+ break;
+ case NFCNdefTypeFormat.External:
+ payload = new NFCNdefPayload(NFCTypeNameFormat.NFCExternal, record.ExternalType, new NSData(), NSData.FromString(Encoding.UTF8.GetString(record.Payload), NSStringEncoding.UTF8));
+ break;
+ case NFCNdefTypeFormat.Empty:
+ payload = EmptyPayload;
+ break;
+ case NFCNdefTypeFormat.Unknown:
+ case NFCNdefTypeFormat.Unchanged:
+ case NFCNdefTypeFormat.Reserved:
+ default:
+ break;
+ }
+ return payload;
+ }
+ }
+
+ ///
+ /// NFC Tag Extensions Class
+ ///
+ internal static class NfcNdefTagExtensions
+ {
+ ///
+ /// Get Ndef tag
+ ///
+ ///
+ ///
+ internal static INFCNdefTag GetNdefTag(INFCTag tag)
+ {
+ if (tag == null || !tag.Available)
+ return null;
+
+ INFCNdefTag ndef;
+
+#if NET6_0_OR_GREATER
+ if (tag.Type == CoreNFC.NFCTagType.MiFare)
+ ndef = tag.AsNFCMiFareTag;
+ else if (tag.Type == CoreNFC.NFCTagType.Iso7816Compatible)
+ ndef = tag.AsNFCIso7816Tag;
+ else if (tag.Type == CoreNFC.NFCTagType.Iso15693)
+ ndef = tag.AsNFCIso15693Tag;
+ else if (tag.Type == CoreNFC.NFCTagType.FeliCa)
+ ndef = tag.AsNFCFeliCaTag;
+ else
+ ndef = null;
+#else
+ if (tag.GetNFCMiFareTag() != null)
+ ndef = tag.GetNFCMiFareTag();
+ else if (tag.GetNFCIso7816Tag() != null)
+ ndef = tag.GetNFCIso7816Tag();
+ else if (tag.GetNFCIso15693Tag() != null)
+ ndef = tag.GetNFCIso15693Tag();
+ else if (tag.GetNFCFeliCaTag() != null)
+ ndef = tag.GetNFCFeliCaTag();
+ else
+ ndef = null;
+#endif
+
+ return ndef;
+ }
+
+ ///
+ /// Returns NFC Tag identifier
+ ///
+ ///
+ /// Tag identifier
+ internal static byte[] GetTagIdentifier(INFCNdefTag tag)
+ {
+ byte[] identifier = null;
+ if (tag is INFCMiFareTag mifareTag)
+ {
+ identifier = mifareTag.Identifier.ToByteArray();
+ }
+ else if (tag is INFCFeliCaTag felicaTag)
+ {
+ identifier = felicaTag.CurrentIdm.ToByteArray();
+ }
+ else if (tag is INFCIso15693Tag iso15693Tag)
+ {
+ identifier = iso15693Tag.Identifier.ToByteArray().Reverse().ToArray();
+ }
+ else if (tag is INFCIso7816Tag iso7816Tag)
+ {
+ identifier = iso7816Tag.Identifier.ToByteArray();
+ }
+ return identifier;
+ }
+ }
+}
diff --git a/src/WorkFlowCheck.API.sln b/src/WorkFlowCheck.API.sln
index 9941426..16375c7 100644
--- a/src/WorkFlowCheck.API.sln
+++ b/src/WorkFlowCheck.API.sln
@@ -1,46 +1,46 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 18
-VisualStudioVersion = 18.2.11408.102 d18.0
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlowCheck.API", "WorkFlowCheck.API\WorkFlowCheck.API.csproj", "{2466E04A-CB0C-4421-9074-A928F819926C}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlowCheck.DL", "WorkFlowCheck.DL\WorkFlowCheck.DL.csproj", "{25A8C0E7-18C7-4672-ABE8-29596E7E9B72}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlowCheck.BL", "WorkFlowCheck.BL\WorkFlowCheck.BL.csproj", "{73049F81-7A5D-4819-ADB8-A9926672365E}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlowCheck.Common", "WorkFlowCheck.Common\WorkFlowCheck.Common.csproj", "{7F94D6CB-3358-4687-88E1-FA46053D6B71}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlowCheck.Web", "WorkFlowCheck.Web\WorkFlowCheck.Web.csproj", "{B4D9960A-9BCF-41DA-9103-5DABA8D2623F}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {2466E04A-CB0C-4421-9074-A928F819926C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2466E04A-CB0C-4421-9074-A928F819926C}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2466E04A-CB0C-4421-9074-A928F819926C}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2466E04A-CB0C-4421-9074-A928F819926C}.Release|Any CPU.Build.0 = Release|Any CPU
- {25A8C0E7-18C7-4672-ABE8-29596E7E9B72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {25A8C0E7-18C7-4672-ABE8-29596E7E9B72}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {25A8C0E7-18C7-4672-ABE8-29596E7E9B72}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {25A8C0E7-18C7-4672-ABE8-29596E7E9B72}.Release|Any CPU.Build.0 = Release|Any CPU
- {73049F81-7A5D-4819-ADB8-A9926672365E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {73049F81-7A5D-4819-ADB8-A9926672365E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {73049F81-7A5D-4819-ADB8-A9926672365E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {73049F81-7A5D-4819-ADB8-A9926672365E}.Release|Any CPU.Build.0 = Release|Any CPU
- {7F94D6CB-3358-4687-88E1-FA46053D6B71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7F94D6CB-3358-4687-88E1-FA46053D6B71}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7F94D6CB-3358-4687-88E1-FA46053D6B71}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7F94D6CB-3358-4687-88E1-FA46053D6B71}.Release|Any CPU.Build.0 = Release|Any CPU
- {B4D9960A-9BCF-41DA-9103-5DABA8D2623F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B4D9960A-9BCF-41DA-9103-5DABA8D2623F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B4D9960A-9BCF-41DA-9103-5DABA8D2623F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B4D9960A-9BCF-41DA-9103-5DABA8D2623F}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 18
+VisualStudioVersion = 18.2.11408.102 d18.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlowCheck.API", "WorkFlowCheck.API\WorkFlowCheck.API.csproj", "{2466E04A-CB0C-4421-9074-A928F819926C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlowCheck.DL", "WorkFlowCheck.DL\WorkFlowCheck.DL.csproj", "{25A8C0E7-18C7-4672-ABE8-29596E7E9B72}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlowCheck.BL", "WorkFlowCheck.BL\WorkFlowCheck.BL.csproj", "{73049F81-7A5D-4819-ADB8-A9926672365E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlowCheck.Common", "WorkFlowCheck.Common\WorkFlowCheck.Common.csproj", "{7F94D6CB-3358-4687-88E1-FA46053D6B71}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkFlowCheck.Web", "WorkFlowCheck.Web\WorkFlowCheck.Web.csproj", "{B4D9960A-9BCF-41DA-9103-5DABA8D2623F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2466E04A-CB0C-4421-9074-A928F819926C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2466E04A-CB0C-4421-9074-A928F819926C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2466E04A-CB0C-4421-9074-A928F819926C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2466E04A-CB0C-4421-9074-A928F819926C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {25A8C0E7-18C7-4672-ABE8-29596E7E9B72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {25A8C0E7-18C7-4672-ABE8-29596E7E9B72}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {25A8C0E7-18C7-4672-ABE8-29596E7E9B72}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {25A8C0E7-18C7-4672-ABE8-29596E7E9B72}.Release|Any CPU.Build.0 = Release|Any CPU
+ {73049F81-7A5D-4819-ADB8-A9926672365E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {73049F81-7A5D-4819-ADB8-A9926672365E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {73049F81-7A5D-4819-ADB8-A9926672365E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {73049F81-7A5D-4819-ADB8-A9926672365E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7F94D6CB-3358-4687-88E1-FA46053D6B71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7F94D6CB-3358-4687-88E1-FA46053D6B71}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7F94D6CB-3358-4687-88E1-FA46053D6B71}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7F94D6CB-3358-4687-88E1-FA46053D6B71}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B4D9960A-9BCF-41DA-9103-5DABA8D2623F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B4D9960A-9BCF-41DA-9103-5DABA8D2623F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B4D9960A-9BCF-41DA-9103-5DABA8D2623F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B4D9960A-9BCF-41DA-9103-5DABA8D2623F}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/WorkFlowCheck.API/.config/dotnet-tools.json b/src/WorkFlowCheck.API/.config/dotnet-tools.json
index 4f48799..890cef1 100644
--- a/src/WorkFlowCheck.API/.config/dotnet-tools.json
+++ b/src/WorkFlowCheck.API/.config/dotnet-tools.json
@@ -1,13 +1,13 @@
-{
- "version": 1,
- "isRoot": true,
- "tools": {
- "dotnet-ef": {
- "version": "9.0.0",
- "commands": [
- "dotnet-ef"
- ],
- "rollForward": false
- }
- }
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "dotnet-ef": {
+ "version": "9.0.0",
+ "commands": [
+ "dotnet-ef"
+ ],
+ "rollForward": false
+ }
+ }
}
\ No newline at end of file
diff --git a/src/WorkFlowCheck.API/Controllers/CheckListController.cs b/src/WorkFlowCheck.API/Controllers/CheckListController.cs
index e49e1ee..a2ebee6 100644
--- a/src/WorkFlowCheck.API/Controllers/CheckListController.cs
+++ b/src/WorkFlowCheck.API/Controllers/CheckListController.cs
@@ -1,463 +1,463 @@
-using Microsoft.AspNetCore.Mvc;
-using Serilog;
-using WorkFlowCheck.BL.Services;
-using WorkFlowCheck.BL.Services.Interfaces;
-using WorkFlowCheck.Common.DataTables;
-using WorkFlowCheck.Common.DTO;
-
-namespace WorkFlowCheck.API.Controllers
-{
- [Route("api/[controller]")]
- [ApiController]
- public class CheckListController : ControllerBase
- {
- private ICheckListService _checkListService;
- public CheckListController(ICheckListService checkListService)
- {
- _checkListService = checkListService;
- }
-
- [HttpGet("GetCheckListHeader/{id}")]
- public async Task> GetCheckListHeader(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var checkListHeaderDTO = await _checkListService.GetCheckListHeaderAsync(id);
-
- if (checkListHeaderDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = checkListHeaderDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpPost("GetFilteredCheckListHeader")]
- public async Task>> GetFilteredCheckListHeader([FromBody] DataTablesRequest dataTablesRequest)
- {
- var retVal = new ApiResponseListDTO>()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _checkListService.GetFilteredCheckListHeaderAsync(dataTablesRequest);
- retVal.Data = result.Data;
- retVal.Total = result.Total;
- retVal.Filtered = result.Filtered;
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
- [HttpGet("CreatePDF/{id}")]
- public async Task> CreatePDF(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var checkListHeader = await _checkListService.GetCheckListHeaderAsync(id);
- var response = await _checkListService.CreateCheckListHeaderPDFAsync(id);
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("GetAllCheckListHeaders/{mode}")]
- public async Task>> GetAllCheckListHeadersAsync(int mode = 0)
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- var checkPointListDTO = await _checkListService.GetAllCheckListHeaderAsync(mode);
-
- if (checkPointListDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = checkPointListDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpPost("UpdateCheckListHeader")]
- public async Task> UpdateCheckListHeader([FromBody] CheckListHeaderDTO checkListHeaderDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _checkListService.UpdateCheckListHeaderAsync(checkListHeaderDTO);
- retVal.Data = result;
-
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
- [HttpPost("StartNewCheckList")]
- public async Task> StartNew([FromBody] CheckListHeaderNewDTO checkListHeaderNewDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- var response = await _checkListService.StartNewCheckListAsync(checkListHeaderNewDTO);
- if (response != null)
- {
- retVal.Data = response;
- }
- }
- catch (Exception ex)
- {
-
- Log.Error(ex.Message);
- }
- return retVal;
- }
- [HttpPost("CloseCheckListHeader")]
- public async Task> CloseCheckListHeader([FromBody] CheckListHeaderCloseDTO checkListHeaderCloseDTO)
- {
- var retVal = new ApiResponseDTO() { IsSuccess = false };
-
- try
- {
- var result = await _checkListService.CloseCheckListHeader(checkListHeaderCloseDTO);
- retVal.Data = result;
- retVal.IsSuccess = result;
-
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
-
- [HttpGet("AcceptCheckListHeader/{id}/{userId}")]
- public async Task> AcceptCheckListHeader(int id, int userId)
- {
- var retVal = new ApiResponseDTO { IsSuccess = false };
-
- var response = await _checkListService.AcceptCheckListHeaderAsync(id, userId);
-
- if (response)
- {
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("BlockCheckListHeader/{id}/{userId}")]
- public async Task> BlockCheckListHeader(int id, int userId)
- {
- var retVal = new ApiResponseDTO { IsSuccess = false };
-
- var response = await _checkListService.BlockCheckListHeaderAsync(id, userId);
-
- if (response)
- {
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("UnBlockCheckListHeader/{id}/{userId}")]
- public async Task> UnBlockCheckListHeader(int id, int userId)
- {
- var retVal = new ApiResponseDTO { IsSuccess = false };
-
- var response = await _checkListService.UnBlockCheckListHeaderAsync(id, userId);
-
- if (response)
- {
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
-
-
- [HttpGet("GetCheckListTemplateHeader/{id}")]
- public async Task> GetCheckListTemplateHeader(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var CheckListTemplateHeaderDTO = await _checkListService.GetCheckListTemplateHeaderAsync(id);
-
- if (CheckListTemplateHeaderDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = CheckListTemplateHeaderDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("GetAllCheckListTemplateHeaders")]
- public async Task>> GetAllCheckListTemplateHeadersAsync()
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- var checkPointListDTO = await _checkListService.GetAllCheckListTemplateHeaderAsync();
-
- if (checkPointListDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = checkPointListDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpPost("UpdateCheckListTemplateHeader")]
- public async Task> UpdateCheckListTemplateHeader([FromBody] CheckListTemplateHeaderDTO CheckListTemplateHeaderDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _checkListService.UpdateCheckListTemplateHeaderAsync(CheckListTemplateHeaderDTO);
- retVal.Data = result;
-
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
- [HttpGet("DeleteCheckListTemplateHeader/{id}")]
- public async Task> DeleteCheckListTemplateHeader(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var result = await _checkListService.DeleteCheckListTemplateHeaderAsync(id);
-
- if (result != null)
- {
- retVal.IsSuccess = true;
- retVal.Data = result;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
-
- [HttpGet("CloneCheckListTemplateHeader/{id}")]
- public async Task> CloneCheckListTemplateHeader(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var result = await _checkListService.CloneCheckListTemplateHeaderAsync(id);
-
- if (result != null)
- {
- retVal.IsSuccess = true;
- retVal.Data = result;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
-
- [HttpGet("GetCheckListTemplateRow/{id}")]
- public async Task> GetCheckListTemplateRow(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var checkListTemplateRowDTO = await _checkListService.GetCheckListTemplateRowAsync(id);
-
- if (checkListTemplateRowDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = checkListTemplateRowDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("DeleteCheckListTemplateRow/{id}")]
- public async Task> DeleteCheckListTemplateRow(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var result = await _checkListService.DeleteCheckListTemplateRowAsync(id);
-
- if (result != null)
- {
- retVal.IsSuccess = true;
- retVal.Data = result;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpPost("UpdateCheckListTemplateRow")]
- public async Task> UpdateCheckListTemplateRow([FromBody] CheckListTemplateRowDTO CheckListTemplateRowDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _checkListService.UpdateCheckListTemplateRowAsync(CheckListTemplateRowDTO);
- retVal.Data = result;
-
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
-
- [HttpGet("GetCheckListRow/{id}")]
- public async Task> GetCheckListRow(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var checkListRowDTO = await _checkListService.GetCheckListRowAsync(id);
-
- if (checkListRowDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = checkListRowDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpPost("UpdateCheckListRow")]
- public async Task> UpdateCheckListRow([FromBody] CheckListRowDTO CheckListRowDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _checkListService.UpdateCheckListRowAsync(CheckListRowDTO);
- retVal.Data = result;
-
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
- }
-}
+using Microsoft.AspNetCore.Mvc;
+using Serilog;
+using WorkFlowCheck.BL.Services;
+using WorkFlowCheck.BL.Services.Interfaces;
+using WorkFlowCheck.Common.DataTables;
+using WorkFlowCheck.Common.DTO;
+
+namespace WorkFlowCheck.API.Controllers
+{
+ [Route("api/[controller]")]
+ [ApiController]
+ public class CheckListController : ControllerBase
+ {
+ private ICheckListService _checkListService;
+ public CheckListController(ICheckListService checkListService)
+ {
+ _checkListService = checkListService;
+ }
+
+ [HttpGet("GetCheckListHeader/{id}")]
+ public async Task> GetCheckListHeader(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var checkListHeaderDTO = await _checkListService.GetCheckListHeaderAsync(id);
+
+ if (checkListHeaderDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = checkListHeaderDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpPost("GetFilteredCheckListHeader")]
+ public async Task>> GetFilteredCheckListHeader([FromBody] DataTablesRequest dataTablesRequest)
+ {
+ var retVal = new ApiResponseListDTO>()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _checkListService.GetFilteredCheckListHeaderAsync(dataTablesRequest);
+ retVal.Data = result.Data;
+ retVal.Total = result.Total;
+ retVal.Filtered = result.Filtered;
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+ [HttpGet("CreatePDF/{id}")]
+ public async Task> CreatePDF(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var checkListHeader = await _checkListService.GetCheckListHeaderAsync(id);
+ var response = await _checkListService.CreateCheckListHeaderPDFAsync(id);
+
+ if (response != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("GetAllCheckListHeaders/{mode}")]
+ public async Task>> GetAllCheckListHeadersAsync(int mode = 0)
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ var checkPointListDTO = await _checkListService.GetAllCheckListHeaderAsync(mode);
+
+ if (checkPointListDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = checkPointListDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpPost("UpdateCheckListHeader")]
+ public async Task> UpdateCheckListHeader([FromBody] CheckListHeaderDTO checkListHeaderDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _checkListService.UpdateCheckListHeaderAsync(checkListHeaderDTO);
+ retVal.Data = result;
+
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+ [HttpPost("StartNewCheckList")]
+ public async Task> StartNew([FromBody] CheckListHeaderNewDTO checkListHeaderNewDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var response = await _checkListService.StartNewCheckListAsync(checkListHeaderNewDTO);
+ if (response != null)
+ {
+ retVal.Data = response;
+ }
+ }
+ catch (Exception ex)
+ {
+
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+ [HttpPost("CloseCheckListHeader")]
+ public async Task> CloseCheckListHeader([FromBody] CheckListHeaderCloseDTO checkListHeaderCloseDTO)
+ {
+ var retVal = new ApiResponseDTO() { IsSuccess = false };
+
+ try
+ {
+ var result = await _checkListService.CloseCheckListHeader(checkListHeaderCloseDTO);
+ retVal.Data = result;
+ retVal.IsSuccess = result;
+
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+
+ [HttpGet("AcceptCheckListHeader/{id}/{userId}")]
+ public async Task> AcceptCheckListHeader(int id, int userId)
+ {
+ var retVal = new ApiResponseDTO { IsSuccess = false };
+
+ var response = await _checkListService.AcceptCheckListHeaderAsync(id, userId);
+
+ if (response)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("BlockCheckListHeader/{id}/{userId}")]
+ public async Task> BlockCheckListHeader(int id, int userId)
+ {
+ var retVal = new ApiResponseDTO { IsSuccess = false };
+
+ var response = await _checkListService.BlockCheckListHeaderAsync(id, userId);
+
+ if (response)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("UnBlockCheckListHeader/{id}/{userId}")]
+ public async Task> UnBlockCheckListHeader(int id, int userId)
+ {
+ var retVal = new ApiResponseDTO { IsSuccess = false };
+
+ var response = await _checkListService.UnBlockCheckListHeaderAsync(id, userId);
+
+ if (response)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+
+
+ [HttpGet("GetCheckListTemplateHeader/{id}")]
+ public async Task> GetCheckListTemplateHeader(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var CheckListTemplateHeaderDTO = await _checkListService.GetCheckListTemplateHeaderAsync(id);
+
+ if (CheckListTemplateHeaderDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = CheckListTemplateHeaderDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("GetAllCheckListTemplateHeaders")]
+ public async Task>> GetAllCheckListTemplateHeadersAsync()
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ var checkPointListDTO = await _checkListService.GetAllCheckListTemplateHeaderAsync();
+
+ if (checkPointListDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = checkPointListDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpPost("UpdateCheckListTemplateHeader")]
+ public async Task> UpdateCheckListTemplateHeader([FromBody] CheckListTemplateHeaderDTO CheckListTemplateHeaderDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _checkListService.UpdateCheckListTemplateHeaderAsync(CheckListTemplateHeaderDTO);
+ retVal.Data = result;
+
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+ [HttpGet("DeleteCheckListTemplateHeader/{id}")]
+ public async Task> DeleteCheckListTemplateHeader(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var result = await _checkListService.DeleteCheckListTemplateHeaderAsync(id);
+
+ if (result != null)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = result;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+
+ [HttpGet("CloneCheckListTemplateHeader/{id}")]
+ public async Task> CloneCheckListTemplateHeader(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var result = await _checkListService.CloneCheckListTemplateHeaderAsync(id);
+
+ if (result != null)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = result;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+
+ [HttpGet("GetCheckListTemplateRow/{id}")]
+ public async Task> GetCheckListTemplateRow(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var checkListTemplateRowDTO = await _checkListService.GetCheckListTemplateRowAsync(id);
+
+ if (checkListTemplateRowDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = checkListTemplateRowDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("DeleteCheckListTemplateRow/{id}")]
+ public async Task> DeleteCheckListTemplateRow(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var result = await _checkListService.DeleteCheckListTemplateRowAsync(id);
+
+ if (result != null)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = result;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpPost("UpdateCheckListTemplateRow")]
+ public async Task> UpdateCheckListTemplateRow([FromBody] CheckListTemplateRowDTO CheckListTemplateRowDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _checkListService.UpdateCheckListTemplateRowAsync(CheckListTemplateRowDTO);
+ retVal.Data = result;
+
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+
+ [HttpGet("GetCheckListRow/{id}")]
+ public async Task> GetCheckListRow(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var checkListRowDTO = await _checkListService.GetCheckListRowAsync(id);
+
+ if (checkListRowDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = checkListRowDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpPost("UpdateCheckListRow")]
+ public async Task> UpdateCheckListRow([FromBody] CheckListRowDTO CheckListRowDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _checkListService.UpdateCheckListRowAsync(CheckListRowDTO);
+ retVal.Data = result;
+
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+ }
+}
diff --git a/src/WorkFlowCheck.API/Controllers/FCMController.cs b/src/WorkFlowCheck.API/Controllers/FCMController.cs
index c3141dd..3a6ce16 100644
--- a/src/WorkFlowCheck.API/Controllers/FCMController.cs
+++ b/src/WorkFlowCheck.API/Controllers/FCMController.cs
@@ -1,83 +1,83 @@
-using Google.Apis.Auth.OAuth2;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
-using Newtonsoft.Json;
-using Serilog;
-using System.Net.Http.Headers;
-using System.Text;
-using WorkFlowCheck.BL.Services.Interfaces;
-using WorkFlowCheck.Common.DTO;
-
-namespace WorkFlowCheck.API.Controllers
-{
- [Route("api/[controller]")]
- [ApiController]
- public class FCMController : ControllerBase
- {
- private readonly IMessageService _messageService;
- public FCMController(IMessageService messageService)
- {
- _messageService = messageService;
- }
-
- [HttpPost("SendFCMMessage")]
- public async Task> SendFCMMessage([FromBody] FCMMessageDTO fCMMessageDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- retVal.IsSuccess = await _messageService.SendFCMMessage(fCMMessageDTO);
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
-
- [HttpPost("SendFCMMessageToLastToken")]
- public async Task> SendFCMMessageToLastToken([FromBody] FCMMessageDTO fCMMessageDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- retVal.IsSuccess = await _messageService.SendFCMMessageToLastToken(fCMMessageDTO);
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
-
- [HttpPost("SendFCMToken")]
- public async Task> SendFCMToken([FromBody] FCMMessageDTO fCMMessageDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- await _messageService.SendFCMTokenAsync(fCMMessageDTO.Token);
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
- }
-}
+using Google.Apis.Auth.OAuth2;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Newtonsoft.Json;
+using Serilog;
+using System.Net.Http.Headers;
+using System.Text;
+using WorkFlowCheck.BL.Services.Interfaces;
+using WorkFlowCheck.Common.DTO;
+
+namespace WorkFlowCheck.API.Controllers
+{
+ [Route("api/[controller]")]
+ [ApiController]
+ public class FCMController : ControllerBase
+ {
+ private readonly IMessageService _messageService;
+ public FCMController(IMessageService messageService)
+ {
+ _messageService = messageService;
+ }
+
+ [HttpPost("SendFCMMessage")]
+ public async Task> SendFCMMessage([FromBody] FCMMessageDTO fCMMessageDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ retVal.IsSuccess = await _messageService.SendFCMMessage(fCMMessageDTO);
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+
+ [HttpPost("SendFCMMessageToLastToken")]
+ public async Task> SendFCMMessageToLastToken([FromBody] FCMMessageDTO fCMMessageDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ retVal.IsSuccess = await _messageService.SendFCMMessageToLastToken(fCMMessageDTO);
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+
+ [HttpPost("SendFCMToken")]
+ public async Task> SendFCMToken([FromBody] FCMMessageDTO fCMMessageDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ await _messageService.SendFCMTokenAsync(fCMMessageDTO.Token);
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+ }
+}
diff --git a/src/WorkFlowCheck.API/Controllers/SyncController.cs b/src/WorkFlowCheck.API/Controllers/SyncController.cs
index 127034c..eea633c 100644
--- a/src/WorkFlowCheck.API/Controllers/SyncController.cs
+++ b/src/WorkFlowCheck.API/Controllers/SyncController.cs
@@ -1,610 +1,610 @@
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.IdentityModel.Tokens;
-using Serilog;
-using System.Text;
-using WorkFlowCheck.BL.Services;
-using WorkFlowCheck.BL.Services.Interfaces;
-using WorkFlowCheck.Common.DTO;
-using WorkFlowCheck.DL.Entities;
-
-namespace WorkFlowCheck.API.Controllers
-{
- [Route("api/[controller]")]
- [ApiController]
- public class SyncController : ControllerBase
- {
- private ISyncService _syncService;
- private INumberGeneratorService _numberGeneratorService;
- private IMessageService _messageService;
- private IUserService _userService;
-
-
- public SyncController(ISyncService syncService,
- INumberGeneratorService numberGeneratorService,
- IUserService userService,
- IMessageService messageService)
- {
- _syncService = syncService;
- _numberGeneratorService = numberGeneratorService;
- _messageService = messageService;
- _userService = userService;
- }
-
-
- [HttpGet("GetCheckPoint/{id}")]
- public async Task> GetCheckpointAsync(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var checkPointDTO = await _syncService.GetCheckPointAsync(id);
-
- if (checkPointDTO != null)
- {
- retVal.IsSuccess = true;
- retVal.Data = checkPointDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("DeleteCheckPoint/{id}")]
- public async Task> DeleteCheckpointAsync(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var response = await _syncService.DeleteCheckPointAsync(id);
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("GetAllCheckPoints")]
- public async Task>> GetAllCheckpointsAsync()
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- var checkPointListDTO = await _syncService.GetAllCheckPointAsync();
-
- if (checkPointListDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = checkPointListDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpPost("UpdateCheckPoint")]
- public async Task> UpdateCheckPoint([FromBody] CheckPointDTO checkPointDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _syncService.UpdateCheckPointAsync(checkPointDTO);
- retVal.Data = result;
-
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
- [HttpPost("UpdateAllCheckPoint")]
- public async Task>> UpdateAllCheckPoint([FromBody] List checkPointListDTO)
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _syncService.UpdateAllCheckPointAsync(checkPointListDTO);
- retVal.Data = result;
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
-
-
- [HttpGet("GetEquipment/{id}")]
- public async Task> GetEquipmentAsync(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var equipmentDTO = await _syncService.GetEquipmentAsync(id);
-
- if (equipmentDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = equipmentDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("DeleteEquipment/{id}")]
- public async Task> DeleteEquipmentAsync(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var response = await _syncService.DeleteEquipmentAsync(id);
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("GetAllEquipments")]
- public async Task>> GetAllEquipmentsAsync()
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- var equipmentListDTO = await _syncService.GetAllEquipmentAsync();
-
- if (equipmentListDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = equipmentListDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpPost("UpdateEquipment")]
- public async Task> UpdateEquipment([FromBody] EquipmentDTO EquipmentDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _syncService.UpdateEquipmentAsync(EquipmentDTO);
- retVal.Data = result;
-
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
-
-
- [HttpGet("GetLocation/{id}")]
- public async Task> GetLocationAsync(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var locationDTO = await _syncService.GetLocationAsync(id);
-
- if (locationDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = locationDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("DeleteLocation/{id}")]
- public async Task> DeleteLocationAsync(int id)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var response = await _syncService.DeleteLocationAsync(id);
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("GetAllLocations")]
- public async Task>> GetAllLocationsAsync()
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- var locationListDTO = await _syncService.GetAllLocationAsync();
-
- if (locationListDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = locationListDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpPost("UpdateLocation")]
- public async Task> UpdateLocation([FromBody] LocationDTO LocationDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _syncService.UpdateLocationAsync(LocationDTO);
- retVal.Data = result;
-
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
-
-
- [HttpGet("GetAllCheckListTemplateHeader/{userId}")]
- public async Task>> GetAllCheckListTemplateHeaderAsync(int userId)
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- var response = await _syncService.GetAllCheckListTemplateAsync(userId);
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("GetAllCheckListHeader/{userId}")]
- public async Task>> GetAllCheckListHeaderAsync(int userId)
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- var response = await _syncService.GetAllCheckListAsync(userId);
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
-
- [HttpPost("SendCheckListHeader")]
- public async Task> SendCheckListHeader([FromBody] CheckListHeaderDTO checkListHeaderDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _syncService.SendCheckListHeaderAsync(checkListHeaderDTO);
- retVal.Data = "Sikeres beküldés!";
-
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add(ex.Message);
- Log.Error(ex.Message);
- }
- return retVal;
- }
-
- [HttpGet("GetAllNumbergenerators")]
- public async Task>> GetAllNumbergeneratorsAsync()
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- var locationListDTO = await _numberGeneratorService.GetAllNumbergeneratorsAsync();
-
- if (locationListDTO != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = locationListDTO;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
-
-
- [HttpPost("DeviceMessageSend")]
- public async Task> DeviceMessageSend([FromBody] DeviceMessageDTO deviceMessageDTO)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _syncService.DeviceMessageSend(deviceMessageDTO);
- retVal.Data = true;
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add(ex.Message);
- Log.Error(ex.Message);
- }
- return retVal;
- }
-
- [HttpGet("DeviceMessageReadUnreaded/{deviceIdBase64}")]
- public async Task>> DeviceMessageReadUnreaded(string deviceIdBase64)
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
-
- byte[] byteArray = Base64UrlEncoder.DecodeBytes(deviceIdBase64);
- string deviceId = Encoding.UTF8.GetString(byteArray);
-
-
- var response = await _syncService.DeviceMessageReadUnreaded(deviceId);
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("DeviceMessageReadUnreadedRole/{roleId}")]
- public async Task>> DeviceMessageReadUnreadedRole(int roleId)
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
-
- var response = await _syncService.DeviceMessageReadUnreadedRole(roleId);
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
-
- [HttpGet("Download")]
- public async Task DownloadAPKFileAsync()
- {
- try
- {
- string fileName = "com.nuvolar.wfcapp-Signed.apk";
- string downloadFolder = Path.Combine(Directory.GetCurrentDirectory(), "Downloads", "APK");
- string filePath = Path.Combine(downloadFolder, fileName);
-
- if (!System.IO.File.Exists(filePath))
- {
- return NotFound("File not found.");
- }
-
- var fileBytes = await System.IO.File.ReadAllBytesAsync(filePath);
- var fileType = "application/octet-stream";
-
- Response.Headers.Add("Content-Length", fileBytes.Length.ToString());
-
- return File(fileBytes, fileType, fileName);
- }
- catch (Exception ex)
- {
- return StatusCode(500, $"Error: {ex.Message}");
- }
- }
-
- [HttpGet("SendTestMail")]
- public async Task> SendTestMail()
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true
- };
-
- try
- {
- var result = await _messageService.SendMailAsync(
- new List()
- {
- "ivan.szabo.sis@gmail.com",
- }, "Teszt", "Ok");
- retVal.Data = true;
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add(ex.Message);
- Log.Error(ex.Message);
- }
- return retVal;
- }
-
-
- [HttpGet("GetAllMobileUsers")]
- public async Task>> GetAllMobileUsers()
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- Data = new List()
- };
- var usersListDTO = await _userService.GetAllUserAsync();
-
- retVal.Data.AddRange(usersListDTO
- .Where(user => user.RoleDTO.Any(role => role.CanUseMobilApp))
- .Select(user => new MobileUserDTO
- {
- Id = user.Id,
- Email = user.Email,
- FirstName = user.FirstName,
- LastName = user.LastName,
- NFCActive = user.NFCActive,
- NFCCode = user.NFCCode,
- UserName = user.UserName
- })
- );
- if (retVal.Data == null || retVal.Data.Count <= 0) { retVal.IsSuccess = false; retVal.Errors.Add("No data!"); }
- return retVal;
- }
-
- [HttpPost("UpdateAllMobileUser")]
- public async Task>> UpdateAllMobileUser([FromBody] List mobileUserListDTO)
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true
- };
-
- try
- {
- foreach (var mobileUserDTO in mobileUserListDTO)
- {
- var userDTO = await _userService.GetUserAsync(mobileUserDTO.Id);
- if (userDTO != null && userDTO.Id == mobileUserDTO.Id)
- {
- userDTO.NFCCode = mobileUserDTO.NFCCode;
- var result = await _userService.UpdateUserAsync(userDTO);
-
- }
-
- }
- }
- catch (Exception ex)
- {
- retVal.IsSuccess = false;
- Log.Error(ex.Message);
- }
- return retVal;
- }
- }
-}
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.IdentityModel.Tokens;
+using Serilog;
+using System.Text;
+using WorkFlowCheck.BL.Services;
+using WorkFlowCheck.BL.Services.Interfaces;
+using WorkFlowCheck.Common.DTO;
+using WorkFlowCheck.DL.Entities;
+
+namespace WorkFlowCheck.API.Controllers
+{
+ [Route("api/[controller]")]
+ [ApiController]
+ public class SyncController : ControllerBase
+ {
+ private ISyncService _syncService;
+ private INumberGeneratorService _numberGeneratorService;
+ private IMessageService _messageService;
+ private IUserService _userService;
+
+
+ public SyncController(ISyncService syncService,
+ INumberGeneratorService numberGeneratorService,
+ IUserService userService,
+ IMessageService messageService)
+ {
+ _syncService = syncService;
+ _numberGeneratorService = numberGeneratorService;
+ _messageService = messageService;
+ _userService = userService;
+ }
+
+
+ [HttpGet("GetCheckPoint/{id}")]
+ public async Task> GetCheckpointAsync(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var checkPointDTO = await _syncService.GetCheckPointAsync(id);
+
+ if (checkPointDTO != null)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = checkPointDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("DeleteCheckPoint/{id}")]
+ public async Task> DeleteCheckpointAsync(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var response = await _syncService.DeleteCheckPointAsync(id);
+
+ if (response != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("GetAllCheckPoints")]
+ public async Task>> GetAllCheckpointsAsync()
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ var checkPointListDTO = await _syncService.GetAllCheckPointAsync();
+
+ if (checkPointListDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = checkPointListDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpPost("UpdateCheckPoint")]
+ public async Task> UpdateCheckPoint([FromBody] CheckPointDTO checkPointDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _syncService.UpdateCheckPointAsync(checkPointDTO);
+ retVal.Data = result;
+
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+ [HttpPost("UpdateAllCheckPoint")]
+ public async Task>> UpdateAllCheckPoint([FromBody] List checkPointListDTO)
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _syncService.UpdateAllCheckPointAsync(checkPointListDTO);
+ retVal.Data = result;
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+
+
+ [HttpGet("GetEquipment/{id}")]
+ public async Task> GetEquipmentAsync(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var equipmentDTO = await _syncService.GetEquipmentAsync(id);
+
+ if (equipmentDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = equipmentDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("DeleteEquipment/{id}")]
+ public async Task> DeleteEquipmentAsync(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var response = await _syncService.DeleteEquipmentAsync(id);
+
+ if (response != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("GetAllEquipments")]
+ public async Task>> GetAllEquipmentsAsync()
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ var equipmentListDTO = await _syncService.GetAllEquipmentAsync();
+
+ if (equipmentListDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = equipmentListDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpPost("UpdateEquipment")]
+ public async Task> UpdateEquipment([FromBody] EquipmentDTO EquipmentDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _syncService.UpdateEquipmentAsync(EquipmentDTO);
+ retVal.Data = result;
+
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+
+
+ [HttpGet("GetLocation/{id}")]
+ public async Task> GetLocationAsync(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var locationDTO = await _syncService.GetLocationAsync(id);
+
+ if (locationDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = locationDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("DeleteLocation/{id}")]
+ public async Task> DeleteLocationAsync(int id)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var response = await _syncService.DeleteLocationAsync(id);
+
+ if (response != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("GetAllLocations")]
+ public async Task>> GetAllLocationsAsync()
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ var locationListDTO = await _syncService.GetAllLocationAsync();
+
+ if (locationListDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = locationListDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpPost("UpdateLocation")]
+ public async Task> UpdateLocation([FromBody] LocationDTO LocationDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _syncService.UpdateLocationAsync(LocationDTO);
+ retVal.Data = result;
+
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+
+
+ [HttpGet("GetAllCheckListTemplateHeader/{userId}")]
+ public async Task>> GetAllCheckListTemplateHeaderAsync(int userId)
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ var response = await _syncService.GetAllCheckListTemplateAsync(userId);
+
+ if (response != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("GetAllCheckListHeader/{userId}")]
+ public async Task>> GetAllCheckListHeaderAsync(int userId)
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ var response = await _syncService.GetAllCheckListAsync(userId);
+
+ if (response != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+
+ [HttpPost("SendCheckListHeader")]
+ public async Task> SendCheckListHeader([FromBody] CheckListHeaderDTO checkListHeaderDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _syncService.SendCheckListHeaderAsync(checkListHeaderDTO);
+ retVal.Data = "Sikeres beküldés!";
+
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add(ex.Message);
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+
+ [HttpGet("GetAllNumbergenerators")]
+ public async Task>> GetAllNumbergeneratorsAsync()
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ var locationListDTO = await _numberGeneratorService.GetAllNumbergeneratorsAsync();
+
+ if (locationListDTO != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = locationListDTO;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+
+
+ [HttpPost("DeviceMessageSend")]
+ public async Task> DeviceMessageSend([FromBody] DeviceMessageDTO deviceMessageDTO)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _syncService.DeviceMessageSend(deviceMessageDTO);
+ retVal.Data = true;
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add(ex.Message);
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+
+ [HttpGet("DeviceMessageReadUnreaded/{deviceIdBase64}")]
+ public async Task>> DeviceMessageReadUnreaded(string deviceIdBase64)
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+
+ byte[] byteArray = Base64UrlEncoder.DecodeBytes(deviceIdBase64);
+ string deviceId = Encoding.UTF8.GetString(byteArray);
+
+
+ var response = await _syncService.DeviceMessageReadUnreaded(deviceId);
+
+ if (response != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("DeviceMessageReadUnreadedRole/{roleId}")]
+ public async Task>> DeviceMessageReadUnreadedRole(int roleId)
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+
+ var response = await _syncService.DeviceMessageReadUnreadedRole(roleId);
+
+ if (response != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+
+ [HttpGet("Download")]
+ public async Task DownloadAPKFileAsync()
+ {
+ try
+ {
+ string fileName = "com.nuvolar.wfcapp-Signed.apk";
+ string downloadFolder = Path.Combine(Directory.GetCurrentDirectory(), "Downloads", "APK");
+ string filePath = Path.Combine(downloadFolder, fileName);
+
+ if (!System.IO.File.Exists(filePath))
+ {
+ return NotFound("File not found.");
+ }
+
+ var fileBytes = await System.IO.File.ReadAllBytesAsync(filePath);
+ var fileType = "application/octet-stream";
+
+ Response.Headers.Add("Content-Length", fileBytes.Length.ToString());
+
+ return File(fileBytes, fileType, fileName);
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, $"Error: {ex.Message}");
+ }
+ }
+
+ [HttpGet("SendTestMail")]
+ public async Task> SendTestMail()
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ var result = await _messageService.SendMailAsync(
+ new List()
+ {
+ "ivan.szabo.sis@gmail.com",
+ }, "Teszt", "Ok");
+ retVal.Data = true;
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add(ex.Message);
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+
+
+ [HttpGet("GetAllMobileUsers")]
+ public async Task>> GetAllMobileUsers()
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ Data = new List()
+ };
+ var usersListDTO = await _userService.GetAllUserAsync();
+
+ retVal.Data.AddRange(usersListDTO
+ .Where(user => user.RoleDTO.Any(role => role.CanUseMobilApp))
+ .Select(user => new MobileUserDTO
+ {
+ Id = user.Id,
+ Email = user.Email,
+ FirstName = user.FirstName,
+ LastName = user.LastName,
+ NFCActive = user.NFCActive,
+ NFCCode = user.NFCCode,
+ UserName = user.UserName
+ })
+ );
+ if (retVal.Data == null || retVal.Data.Count <= 0) { retVal.IsSuccess = false; retVal.Errors.Add("No data!"); }
+ return retVal;
+ }
+
+ [HttpPost("UpdateAllMobileUser")]
+ public async Task>> UpdateAllMobileUser([FromBody] List mobileUserListDTO)
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true
+ };
+
+ try
+ {
+ foreach (var mobileUserDTO in mobileUserListDTO)
+ {
+ var userDTO = await _userService.GetUserAsync(mobileUserDTO.Id);
+ if (userDTO != null && userDTO.Id == mobileUserDTO.Id)
+ {
+ userDTO.NFCCode = mobileUserDTO.NFCCode;
+ var result = await _userService.UpdateUserAsync(userDTO);
+
+ }
+
+ }
+ }
+ catch (Exception ex)
+ {
+ retVal.IsSuccess = false;
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+ }
+}
diff --git a/src/WorkFlowCheck.API/Controllers/SystemController.cs b/src/WorkFlowCheck.API/Controllers/SystemController.cs
index d0ca942..005899c 100644
--- a/src/WorkFlowCheck.API/Controllers/SystemController.cs
+++ b/src/WorkFlowCheck.API/Controllers/SystemController.cs
@@ -1,399 +1,399 @@
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
-using Serilog;
-using WorkFlowCheck.BL.Services.Interfaces;
-using WorkFlowCheck.Common.DTO;
-
-namespace WorkFlowCheck.API.Controllers
-{
- [Route("api/[controller]")]
- [ApiController]
- public class SystemController : ControllerBase
- {
-
- private readonly ISystemService _systemService;
-
- public SystemController(ISystemService systemService)
- {
- _systemService = systemService;
- }
-
- [HttpGet("GetDatabaseAndVersionInfo")]
- public async Task> GetDatabaseAndVersionInfo()
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = true,
- };
- var result = await _systemService.GetDatabaseAndVersionInfoAsync();
-
- if (result != null)
- {
- retVal.IsSuccess = true;
- retVal.Data = result;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
-
- [HttpGet("GetAllImageFiles")]
- public async Task>> GetAllImageFilesAsync()
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- try
- {
- var allowedExtensions = new[] { ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".webp", ".tiff" };
- var imageFolder = Path.Combine(Directory.GetCurrentDirectory(), "Images");
- var files = Directory.GetFiles(imageFolder)
- .Where(f => allowedExtensions.Contains(Path.GetExtension(f).ToLower()))
- .Select(f =>
- {
- var fileInfo = new FileInfo(f);
- return new
- {
- FileName = fileInfo.Name,
- FileSize = FormatFileSize(fileInfo.Length),
- CreatedDate = fileInfo.CreationTime.ToString("yyyy.MM.dd HH:mm"),
- };
- });
-
- var checkListFileInfos = new List();
- foreach (var file in files.OrderBy(o => o.FileName).ToList())
- {
- var checkListFileInfoDTO = new ImageFileDTO()
- {
- FileName = file.FileName,
- FileSize = file.FileSize,
- CreateDate = file.CreatedDate,
-
- };
- checkListFileInfos.Add(checkListFileInfoDTO);
- }
-
- if (checkListFileInfos != null)
- {
- retVal.IsSuccess = true;
- retVal.Data = checkListFileInfos;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
- }
- catch (Exception ex)
- {
- Log.Error(ex.Message);
- }
- return retVal;
- }
- [HttpGet("GetAllPDFFiles")]
- public async Task>> GetAllPDFilesAsync()
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- try
- {
- var pdfFolder = Path.Combine(Directory.GetCurrentDirectory(), "PDF");
- var files = Directory.GetFiles(pdfFolder, "*.pdf")
- .Select(f =>
- {
- var fileInfo = new FileInfo(f);
- return new
- {
- FileName = fileInfo.Name,
- FileSize = FormatFileSize(fileInfo.Length),
- CreatedDate = fileInfo.CreationTime.ToString("yyyy.MM.dd HH:mm"),
- };
- });
-
- var checkListFileInfos = new List();
- foreach (var file in files.OrderBy(o => o.FileName).ToList())
- {
- var checkListFileInfoDTO = new ImageFileDTO()
- {
- FileName = file.FileName,
- FileSize = file.FileSize,
- CreateDate = file.CreatedDate,
-
- };
- checkListFileInfos.Add(checkListFileInfoDTO);
- }
-
- if (checkListFileInfos != null)
- {
- retVal.IsSuccess = true;
- retVal.Data = checkListFileInfos;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
- }
- catch (Exception ex)
- {
- Log.Error(ex.Message);
- }
- return retVal;
- }
- [HttpGet("GetAllLogAuditFiles")]
- public async Task>> GetAllLogAuditFilesAsync()
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- try
- {
- var logAuditFiles = Path.Combine(Directory.GetCurrentDirectory(), "Logs\\AuditFlow");
- var files = Directory.GetFiles(logAuditFiles, "*.log")
- .Select(f =>
- {
- var fileInfo = new FileInfo(f);
- return new
- {
- FileName = fileInfo.Name,
- FileSize = FormatFileSize(fileInfo.Length),
- CreatedDate = fileInfo.CreationTime.ToString("yyyy.MM.dd HH:mm"),
- };
- });
-
- var checkListFileInfos = new List();
- foreach (var file in files.OrderBy(o => o.FileName).ToList())
- {
- var checkListFileInfoDTO = new LogFileDTO()
- {
- FileName = file.FileName,
- FileSize = file.FileSize,
- CreateDate = file.CreatedDate,
-
- };
- checkListFileInfos.Add(checkListFileInfoDTO);
- }
-
- if (checkListFileInfos != null)
- {
- retVal.IsSuccess = true;
- retVal.Data = checkListFileInfos;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
- }
- catch (Exception ex)
- {
- Log.Error(ex.Message);
- }
- return retVal;
- }
- [HttpGet("GetAllLogBusinessFiles")]
- public async Task>> GetAllLogBusinessFilesAsync()
- {
- var retVal = new ApiResponseDTO>()
- {
- IsSuccess = true,
- };
- try
- {
- var logBusinessFiles = Path.Combine(Directory.GetCurrentDirectory(), "Logs\\BusinessFlow");
- var files = Directory.GetFiles(logBusinessFiles, "*.log")
- .Select(f =>
- {
- var fileInfo = new FileInfo(f);
- return new
- {
- FileName = fileInfo.Name,
- FileSize = FormatFileSize(fileInfo.Length),
- CreatedDate = fileInfo.CreationTime.ToString("yyyy.MM.dd HH:mm"),
- };
- });
-
- var checkListFileInfos = new List();
- foreach (var file in files.OrderBy(o => o.FileName).ToList())
- {
- var checkListFileInfoDTO = new LogFileDTO()
- {
- FileName = file.FileName,
- FileSize = file.FileSize,
- CreateDate = file.CreatedDate,
-
- };
- checkListFileInfos.Add(checkListFileInfoDTO);
- }
-
- if (checkListFileInfos != null)
- {
- retVal.IsSuccess = true;
- retVal.Data = checkListFileInfos;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
- }
- catch (Exception ex)
- {
- Log.Error(ex.Message);
- }
- return retVal;
- }
-
- [HttpGet("DownloadFile/{filename}")]
- public async Task> DownloadFile(string filename)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = false,
- };
- var imageFile = Path.Combine(Directory.GetCurrentDirectory(), "Images", filename);
-
- if (!System.IO.File.Exists(imageFile))
- {
- retVal.Errors.Add($"{filename} does not exist");
- return retVal;
- }
-
- byte[] response = System.IO.File.ReadAllBytes(imageFile);
-
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("DownloadPDFFile/{filename}")]
- public async Task> DownloadPDFFile(string filename)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = false,
- };
- var imageFile = Path.Combine(Directory.GetCurrentDirectory(), "PDF", filename);
-
- if (!System.IO.File.Exists(imageFile))
- {
- retVal.Errors.Add($"{filename} does not exist");
- return retVal;
- }
-
- byte[] response = System.IO.File.ReadAllBytes(imageFile);
-
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
-
-
- [HttpGet("DownloadAuditLogFile/{filename}")]
- public async Task> DownloadAuditLogFile(string filename)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = false,
- };
- var imageFile = Path.Combine(Directory.GetCurrentDirectory(), "Logs\\AuditFlow", filename);
-
- if (!System.IO.File.Exists(imageFile))
- {
- retVal.Errors.Add($"{filename} does not exist");
- return retVal;
- }
-
- byte[] response = System.IO.File.ReadAllBytes(imageFile);
-
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
- [HttpGet("DownloadBusinessLogFile/{filename}")]
- public async Task> DownloadBusinessLogFile(string filename)
- {
- var retVal = new ApiResponseDTO()
- {
- IsSuccess = false,
- };
- var imageFile = Path.Combine(Directory.GetCurrentDirectory(), "Logs\\BusinessFlow", filename);
-
- if (!System.IO.File.Exists(imageFile))
- {
- retVal.Errors.Add($"{filename} does not exist");
- return retVal;
- }
-
- byte[] response = System.IO.File.ReadAllBytes(imageFile);
-
-
- if (response != null)
- {
-
- retVal.IsSuccess = true;
- retVal.Data = response;
- }
- else
- {
- retVal.IsSuccess = false;
- retVal.Errors.Add("No data!");
- }
-
- return retVal;
- }
-
- private string FormatFileSize(long bytes)
- {
- string[] sizes = { "B", "KB", "MB", "GB", "TB" };
- double len = bytes;
- int order = 0;
- while (len >= 1024 && order < sizes.Length - 1)
- {
- order++;
- len /= 1024;
- }
- return $"{len:0.##} {sizes[order]}";
- }
- }
-}
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Serilog;
+using WorkFlowCheck.BL.Services.Interfaces;
+using WorkFlowCheck.Common.DTO;
+
+namespace WorkFlowCheck.API.Controllers
+{
+ [Route("api/[controller]")]
+ [ApiController]
+ public class SystemController : ControllerBase
+ {
+
+ private readonly ISystemService _systemService;
+
+ public SystemController(ISystemService systemService)
+ {
+ _systemService = systemService;
+ }
+
+ [HttpGet("GetDatabaseAndVersionInfo")]
+ public async Task> GetDatabaseAndVersionInfo()
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = true,
+ };
+ var result = await _systemService.GetDatabaseAndVersionInfoAsync();
+
+ if (result != null)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = result;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+
+ [HttpGet("GetAllImageFiles")]
+ public async Task>> GetAllImageFilesAsync()
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ try
+ {
+ var allowedExtensions = new[] { ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".webp", ".tiff" };
+ var imageFolder = Path.Combine(Directory.GetCurrentDirectory(), "Images");
+ var files = Directory.GetFiles(imageFolder)
+ .Where(f => allowedExtensions.Contains(Path.GetExtension(f).ToLower()))
+ .Select(f =>
+ {
+ var fileInfo = new FileInfo(f);
+ return new
+ {
+ FileName = fileInfo.Name,
+ FileSize = FormatFileSize(fileInfo.Length),
+ CreatedDate = fileInfo.CreationTime.ToString("yyyy.MM.dd HH:mm"),
+ };
+ });
+
+ var checkListFileInfos = new List();
+ foreach (var file in files.OrderBy(o => o.FileName).ToList())
+ {
+ var checkListFileInfoDTO = new ImageFileDTO()
+ {
+ FileName = file.FileName,
+ FileSize = file.FileSize,
+ CreateDate = file.CreatedDate,
+
+ };
+ checkListFileInfos.Add(checkListFileInfoDTO);
+ }
+
+ if (checkListFileInfos != null)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = checkListFileInfos;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+ [HttpGet("GetAllPDFFiles")]
+ public async Task>> GetAllPDFilesAsync()
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ try
+ {
+ var pdfFolder = Path.Combine(Directory.GetCurrentDirectory(), "PDF");
+ var files = Directory.GetFiles(pdfFolder, "*.pdf")
+ .Select(f =>
+ {
+ var fileInfo = new FileInfo(f);
+ return new
+ {
+ FileName = fileInfo.Name,
+ FileSize = FormatFileSize(fileInfo.Length),
+ CreatedDate = fileInfo.CreationTime.ToString("yyyy.MM.dd HH:mm"),
+ };
+ });
+
+ var checkListFileInfos = new List();
+ foreach (var file in files.OrderBy(o => o.FileName).ToList())
+ {
+ var checkListFileInfoDTO = new ImageFileDTO()
+ {
+ FileName = file.FileName,
+ FileSize = file.FileSize,
+ CreateDate = file.CreatedDate,
+
+ };
+ checkListFileInfos.Add(checkListFileInfoDTO);
+ }
+
+ if (checkListFileInfos != null)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = checkListFileInfos;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+ [HttpGet("GetAllLogAuditFiles")]
+ public async Task>> GetAllLogAuditFilesAsync()
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ try
+ {
+ var logAuditFiles = Path.Combine(Directory.GetCurrentDirectory(), "Logs\\AuditFlow");
+ var files = Directory.GetFiles(logAuditFiles, "*.log")
+ .Select(f =>
+ {
+ var fileInfo = new FileInfo(f);
+ return new
+ {
+ FileName = fileInfo.Name,
+ FileSize = FormatFileSize(fileInfo.Length),
+ CreatedDate = fileInfo.CreationTime.ToString("yyyy.MM.dd HH:mm"),
+ };
+ });
+
+ var checkListFileInfos = new List();
+ foreach (var file in files.OrderBy(o => o.FileName).ToList())
+ {
+ var checkListFileInfoDTO = new LogFileDTO()
+ {
+ FileName = file.FileName,
+ FileSize = file.FileSize,
+ CreateDate = file.CreatedDate,
+
+ };
+ checkListFileInfos.Add(checkListFileInfoDTO);
+ }
+
+ if (checkListFileInfos != null)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = checkListFileInfos;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+ [HttpGet("GetAllLogBusinessFiles")]
+ public async Task>> GetAllLogBusinessFilesAsync()
+ {
+ var retVal = new ApiResponseDTO>()
+ {
+ IsSuccess = true,
+ };
+ try
+ {
+ var logBusinessFiles = Path.Combine(Directory.GetCurrentDirectory(), "Logs\\BusinessFlow");
+ var files = Directory.GetFiles(logBusinessFiles, "*.log")
+ .Select(f =>
+ {
+ var fileInfo = new FileInfo(f);
+ return new
+ {
+ FileName = fileInfo.Name,
+ FileSize = FormatFileSize(fileInfo.Length),
+ CreatedDate = fileInfo.CreationTime.ToString("yyyy.MM.dd HH:mm"),
+ };
+ });
+
+ var checkListFileInfos = new List();
+ foreach (var file in files.OrderBy(o => o.FileName).ToList())
+ {
+ var checkListFileInfoDTO = new LogFileDTO()
+ {
+ FileName = file.FileName,
+ FileSize = file.FileSize,
+ CreateDate = file.CreatedDate,
+
+ };
+ checkListFileInfos.Add(checkListFileInfoDTO);
+ }
+
+ if (checkListFileInfos != null)
+ {
+ retVal.IsSuccess = true;
+ retVal.Data = checkListFileInfos;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.Message);
+ }
+ return retVal;
+ }
+
+ [HttpGet("DownloadFile/{filename}")]
+ public async Task> DownloadFile(string filename)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = false,
+ };
+ var imageFile = Path.Combine(Directory.GetCurrentDirectory(), "Images", filename);
+
+ if (!System.IO.File.Exists(imageFile))
+ {
+ retVal.Errors.Add($"{filename} does not exist");
+ return retVal;
+ }
+
+ byte[] response = System.IO.File.ReadAllBytes(imageFile);
+
+
+ if (response != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("DownloadPDFFile/{filename}")]
+ public async Task> DownloadPDFFile(string filename)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = false,
+ };
+ var imageFile = Path.Combine(Directory.GetCurrentDirectory(), "PDF", filename);
+
+ if (!System.IO.File.Exists(imageFile))
+ {
+ retVal.Errors.Add($"{filename} does not exist");
+ return retVal;
+ }
+
+ byte[] response = System.IO.File.ReadAllBytes(imageFile);
+
+
+ if (response != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+
+
+ [HttpGet("DownloadAuditLogFile/{filename}")]
+ public async Task> DownloadAuditLogFile(string filename)
+ {
+ var retVal = new ApiResponseDTO()
+ {
+ IsSuccess = false,
+ };
+ var imageFile = Path.Combine(Directory.GetCurrentDirectory(), "Logs\\AuditFlow", filename);
+
+ if (!System.IO.File.Exists(imageFile))
+ {
+ retVal.Errors.Add($"{filename} does not exist");
+ return retVal;
+ }
+
+ byte[] response = System.IO.File.ReadAllBytes(imageFile);
+
+
+ if (response != null)
+ {
+
+ retVal.IsSuccess = true;
+ retVal.Data = response;
+ }
+ else
+ {
+ retVal.IsSuccess = false;
+ retVal.Errors.Add("No data!");
+ }
+
+ return retVal;
+ }
+ [HttpGet("DownloadBusinessLogFile/{filename}")]
+ public async Task