From e19d4114c92e48994f631a36418741ea84836075 Mon Sep 17 00:00:00 2001 From: codingbandit Date: Tue, 26 Feb 2019 09:49:56 -0500 Subject: [PATCH] Final Beta 4.1 implementation (#140) * Release (#101) * Small Powershell Fix (#88) * commented out starting of the stream deck app - this is handled in the Debug -> Application Arguments * Fixed the Fritz.png error * restored the osx post build script and added detailed comments (#90) * Updates to the Powershell script (#98) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Prevent displaying errors in PowerShell script to the user (#93) * bugfix/Silence-non-critical-PowerShell-errors: Prevent displaying errors for operations which can expectedly fail * bugfix/Silence-non-critical-PowerShell-errors: Make the template's .ps1 file match the sample * bugfix/Update-gitignore-with-VSCode-files: Add ignorables for VSCode (#94) * Feature/sample property inspector (#95) * work in progress - sample property inspector * worked through intricacies of the deserialized dynamic payload * Updated Templates * Attempt to fix the template test (#100) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Release with fix to testTemplate (#103) * Small Powershell Fix (#88) * commented out starting of the stream deck app - this is handled in the Debug -> Application Arguments * Fixed the Fritz.png error * restored the osx post build script and added detailed comments (#90) * Updates to the Powershell script (#98) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Prevent displaying errors in PowerShell script to the user (#93) * bugfix/Silence-non-critical-PowerShell-errors: Prevent displaying errors for operations which can expectedly fail * bugfix/Silence-non-critical-PowerShell-errors: Make the template's .ps1 file match the sample * bugfix/Update-gitignore-with-VSCode-files: Add ignorables for VSCode (#94) * Feature/sample property inspector (#95) * work in progress - sample property inspector * worked through intricacies of the deserialized dynamic payload * Updated Templates * Attempt to fix the template test (#100) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Added a no-restore directive to the testTemplate script * working version of the beta version of the stream deck software (note: did not update template) * Updated template files, removed extraneous content entries in the csproj * Working Philips Hue Light Button (MVP) * in progress - multi-action support * multi-instance of actions (and support for multiple actions) * Completed Multi-Action implementation of Philips Hue Plugin * small change, OnWillAppear for actions with SettingsModels moved to base class - obtains settings directly from args instead of requesting them * set minimum StreamDeck software version in the manifest.json * Migrated to 4.1 beta 2 * introduced a view model in js to support multiple field property inspectors (#108) * [WIP] Proposal: Refactor Registration Scripts (#110) * migrating registration scripts to a central spot shared by all projects * adding a .gitattributes to prevent cross platform whitespace munging as well as some merge hinting * fix to always pull from current working directory, added logic to pull the csproj file from the working directory as well by file type rather than by name * introduced the most recent powershell changes into this version of the script * this could be a white space issue. * Move plugin logic into action classes (#111) * Add a method to immediately attach a debugger before any functional code has run. * Make changes so that a plugin can support multiple actions Add and throw exceptions for validating actions Convert "MySamplePlugin" to be an action/handler Refactor cancellation token and add ConnectionManager unit tests * Fix build errors from merge misses Mark refactored classes and methods with the "Obsolete" attribute for now. * Update the template to reflect the changes in the SamplePlugin Use the new BaseStreamDeckAction class Update the README with information on creating a new action * Fixed missing method that got dropped during merge * Removing the PhlipsHue plugin - so that I can merge beta 2 stuff back to the beta branch without it (and fixed default inspector value setting) * Updated Template Files for Beta 2 * Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added Default Configuration Builder (#118) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * work in progress * some files that Hugo and Carey modified together (still not building - but there's a plan :D) * Added UUID constructor to fix #119 (#121) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Fixed some tests, added UUID constructor for #119 * Added a 'RegisterAllActions' feature to the ConnectionManager (#122) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Fixed some tests, added UUID constructor for #119 * Added a 'RegisterAllActions' feature to the ConnectionManager * Minimal number of changes made. Should be just enough to make it build. * Deploying v0.3 (#124) * Small Powershell Fix (#88) * commented out starting of the stream deck app - this is handled in the Debug -> Application Arguments * Fixed the Fritz.png error * restored the osx post build script and added detailed comments (#90) * Updates to the Powershell script (#98) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Prevent displaying errors in PowerShell script to the user (#93) * bugfix/Silence-non-critical-PowerShell-errors: Prevent displaying errors for operations which can expectedly fail * bugfix/Silence-non-critical-PowerShell-errors: Make the template's .ps1 file match the sample * bugfix/Update-gitignore-with-VSCode-files: Add ignorables for VSCode (#94) * Feature/sample property inspector (#95) * work in progress - sample property inspector * worked through intricacies of the deserialized dynamic payload * Updated Templates * Attempt to fix the template test (#100) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Added a no-restore directive to the testTemplate script * Released (#104) * Release (#101) * Small Powershell Fix (#88) * commented out starting of the stream deck app - this is handled in the Debug -> Application Arguments * Fixed the Fritz.png error * restored the osx post build script and added detailed comments (#90) * Updates to the Powershell script (#98) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Prevent displaying errors in PowerShell script to the user (#93) * bugfix/Silence-non-critical-PowerShell-errors: Prevent displaying errors for operations which can expectedly fail * bugfix/Silence-non-critical-PowerShell-errors: Make the template's .ps1 file match the sample * bugfix/Update-gitignore-with-VSCode-files: Add ignorables for VSCode (#94) * Feature/sample property inspector (#95) * work in progress - sample property inspector * worked through intricacies of the deserialized dynamic payload * Updated Templates * Attempt to fix the template test (#100) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Release with fix to testTemplate (#103) * Small Powershell Fix (#88) * commented out starting of the stream deck app - this is handled in the Debug -> Application Arguments * Fixed the Fritz.png error * restored the osx post build script and added detailed comments (#90) * Updates to the Powershell script (#98) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Prevent displaying errors in PowerShell script to the user (#93) * bugfix/Silence-non-critical-PowerShell-errors: Prevent displaying errors for operations which can expectedly fail * bugfix/Silence-non-critical-PowerShell-errors: Make the template's .ps1 file match the sample * bugfix/Update-gitignore-with-VSCode-files: Add ignorables for VSCode (#94) * Feature/sample property inspector (#95) * work in progress - sample property inspector * worked through intricacies of the deserialized dynamic payload * Updated Templates * Attempt to fix the template test (#100) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Added a no-restore directive to the testTemplate script * extraneous $bindir concatenation causing issues with copying of files - removed that line of code so it copies over properly (#105) * introduced a view model in js to support multiple field property inspectors (#108) * [WIP] Proposal: Refactor Registration Scripts (#110) * migrating registration scripts to a central spot shared by all projects * adding a .gitattributes to prevent cross platform whitespace munging as well as some merge hinting * fix to always pull from current working directory, added logic to pull the csproj file from the working directory as well by file type rather than by name * introduced the most recent powershell changes into this version of the script * this could be a white space issue. * Move plugin logic into action classes (#111) * Add a method to immediately attach a debugger before any functional code has run. * Make changes so that a plugin can support multiple actions Add and throw exceptions for validating actions Convert "MySamplePlugin" to be an action/handler Refactor cancellation token and add ConnectionManager unit tests * Fix build errors from merge misses Mark refactored classes and methods with the "Obsolete" attribute for now. * Update the template to reflect the changes in the SamplePlugin Use the new BaseStreamDeckAction class Update the README with information on creating a new action * Fixed missing method that got dropped during merge * Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added Default Configuration Builder (#118) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added UUID constructor to fix #119 (#121) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Fixed some tests, added UUID constructor for #119 * Added a 'RegisterAllActions' feature to the ConnectionManager (#122) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Fixed some tests, added UUID constructor for #119 * Added a 'RegisterAllActions' feature to the ConnectionManager * Fixed configuration to use the current executing assembly (#127) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Fixed some tests, added UUID constructor for #119 * Added a 'RegisterAllActions' feature to the ConnectionManager * Updated to properly configure current folder * Configuring IsTestProject * Configuring IsTestProject (#129) * Master (#131) * Fixed Config references to ExecutingAssembly (#128) * Small Powershell Fix (#88) * commented out starting of the stream deck app - this is handled in the Debug -> Application Arguments * Fixed the Fritz.png error * restored the osx post build script and added detailed comments (#90) * Updates to the Powershell script (#98) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Prevent displaying errors in PowerShell script to the user (#93) * bugfix/Silence-non-critical-PowerShell-errors: Prevent displaying errors for operations which can expectedly fail * bugfix/Silence-non-critical-PowerShell-errors: Make the template's .ps1 file match the sample * bugfix/Update-gitignore-with-VSCode-files: Add ignorables for VSCode (#94) * Feature/sample property inspector (#95) * work in progress - sample property inspector * worked through intricacies of the deserialized dynamic payload * Updated Templates * Attempt to fix the template test (#100) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Added a no-restore directive to the testTemplate script * Released (#104) * Release (#101) * Small Powershell Fix (#88) * commented out starting of the stream deck app - this is handled in the Debug -> Application Arguments * Fixed the Fritz.png error * restored the osx post build script and added detailed comments (#90) * Updates to the Powershell script (#98) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Prevent displaying errors in PowerShell script to the user (#93) * bugfix/Silence-non-critical-PowerShell-errors: Prevent displaying errors for operations which can expectedly fail * bugfix/Silence-non-critical-PowerShell-errors: Make the template's .ps1 file match the sample * bugfix/Update-gitignore-with-VSCode-files: Add ignorables for VSCode (#94) * Feature/sample property inspector (#95) * work in progress - sample property inspector * worked through intricacies of the deserialized dynamic payload * Updated Templates * Attempt to fix the template test (#100) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Release with fix to testTemplate (#103) * Small Powershell Fix (#88) * commented out starting of the stream deck app - this is handled in the Debug -> Application Arguments * Fixed the Fritz.png error * restored the osx post build script and added detailed comments (#90) * Updates to the Powershell script (#98) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Prevent displaying errors in PowerShell script to the user (#93) * bugfix/Silence-non-critical-PowerShell-errors: Prevent displaying errors for operations which can expectedly fail * bugfix/Silence-non-critical-PowerShell-errors: Make the template's .ps1 file match the sample * bugfix/Update-gitignore-with-VSCode-files: Add ignorables for VSCode (#94) * Feature/sample property inspector (#95) * work in progress - sample property inspector * worked through intricacies of the deserialized dynamic payload * Updated Templates * Attempt to fix the template test (#100) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Added a no-restore directive to the testTemplate script * extraneous $bindir concatenation causing issues with copying of files - removed that line of code so it copies over properly (#105) * introduced a view model in js to support multiple field property inspectors (#108) * [WIP] Proposal: Refactor Registration Scripts (#110) * migrating registration scripts to a central spot shared by all projects * adding a .gitattributes to prevent cross platform whitespace munging as well as some merge hinting * fix to always pull from current working directory, added logic to pull the csproj file from the working directory as well by file type rather than by name * introduced the most recent powershell changes into this version of the script * this could be a white space issue. * Move plugin logic into action classes (#111) * Add a method to immediately attach a debugger before any functional code has run. * Make changes so that a plugin can support multiple actions Add and throw exceptions for validating actions Convert "MySamplePlugin" to be an action/handler Refactor cancellation token and add ConnectionManager unit tests * Fix build errors from merge misses Mark refactored classes and methods with the "Obsolete" attribute for now. * Update the template to reflect the changes in the SamplePlugin Use the new BaseStreamDeckAction class Update the README with information on creating a new action * Fixed missing method that got dropped during merge * Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added Default Configuration Builder (#118) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added UUID constructor to fix #119 (#121) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Fixed some tests, added UUID constructor for #119 * Added a 'RegisterAllActions' feature to the ConnectionManager (#122) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Fixed some tests, added UUID constructor for #119 * Added a 'RegisterAllActions' feature to the ConnectionManager * Fixed configuration to use the current executing assembly (#127) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Fixed some tests, added UUID constructor for #119 * Added a 'RegisterAllActions' feature to the ConnectionManager * Updated to properly configure current folder * Release test project fix (#130) * Small Powershell Fix (#88) * commented out starting of the stream deck app - this is handled in the Debug -> Application Arguments * Fixed the Fritz.png error * restored the osx post build script and added detailed comments (#90) * Updates to the Powershell script (#98) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Prevent displaying errors in PowerShell script to the user (#93) * bugfix/Silence-non-critical-PowerShell-errors: Prevent displaying errors for operations which can expectedly fail * bugfix/Silence-non-critical-PowerShell-errors: Make the template's .ps1 file match the sample * bugfix/Update-gitignore-with-VSCode-files: Add ignorables for VSCode (#94) * Feature/sample property inspector (#95) * work in progress - sample property inspector * worked through intricacies of the deserialized dynamic payload * Updated Templates * Attempt to fix the template test (#100) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Added a no-restore directive to the testTemplate script * Released (#104) * Release (#101) * Small Powershell Fix (#88) * commented out starting of the stream deck app - this is handled in the Debug -> Application Arguments * Fixed the Fritz.png error * restored the osx post build script and added detailed comments (#90) * Updates to the Powershell script (#98) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Prevent displaying errors in PowerShell script to the user (#93) * bugfix/Silence-non-critical-PowerShell-errors: Prevent displaying errors for operations which can expectedly fail * bugfix/Silence-non-critical-PowerShell-errors: Make the template's .ps1 file match the sample * bugfix/Update-gitignore-with-VSCode-files: Add ignorables for VSCode (#94) * Feature/sample property inspector (#95) * work in progress - sample property inspector * worked through intricacies of the deserialized dynamic payload * Updated Templates * Attempt to fix the template test (#100) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Release with fix to testTemplate (#103) * Small Powershell Fix (#88) * commented out starting of the stream deck app - this is handled in the Debug -> Application Arguments * Fixed the Fritz.png error * restored the osx post build script and added detailed comments (#90) * Updates to the Powershell script (#98) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Prevent displaying errors in PowerShell script to the user (#93) * bugfix/Silence-non-critical-PowerShell-errors: Prevent displaying errors for operations which can expectedly fail * bugfix/Silence-non-critical-PowerShell-errors: Make the template's .ps1 file match the sample * bugfix/Update-gitignore-with-VSCode-files: Add ignorables for VSCode (#94) * Feature/sample property inspector (#95) * work in progress - sample property inspector * worked through intricacies of the deserialized dynamic payload * Updated Templates * Attempt to fix the template test (#100) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Added a no-restore directive to the testTemplate script * extraneous $bindir concatenation causing issues with copying of files - removed that line of code so it copies over properly (#105) * introduced a view model in js to support multiple field property inspectors (#108) * [WIP] Proposal: Refactor Registration Scripts (#110) * migrating registration scripts to a central spot shared by all projects * adding a .gitattributes to prevent cross platform whitespace munging as well as some merge hinting * fix to always pull from current working directory, added logic to pull the csproj file from the working directory as well by file type rather than by name * introduced the most recent powershell changes into this version of the script * this could be a white space issue. * Move plugin logic into action classes (#111) * Add a method to immediately attach a debugger before any functional code has run. * Make changes so that a plugin can support multiple actions Add and throw exceptions for validating actions Convert "MySamplePlugin" to be an action/handler Refactor cancellation token and add ConnectionManager unit tests * Fix build errors from merge misses Mark refactored classes and methods with the "Obsolete" attribute for now. * Update the template to reflect the changes in the SamplePlugin Use the new BaseStreamDeckAction class Update the README with information on creating a new action * Fixed missing method that got dropped during merge * Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added Default Configuration Builder (#118) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added UUID constructor to fix #119 (#121) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Fixed some tests, added UUID constructor for #119 * Added a 'RegisterAllActions' feature to the ConnectionManager (#122) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Fixed some tests, added UUID constructor for #119 * Added a 'RegisterAllActions' feature to the ConnectionManager * Fixed configuration to use the current executing assembly (#127) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Added a default configuration builder #34 Addressed logger and memory leak issues #73 #114 (#117) * Refactored to an Proxy interface to address #47 * Added remaining EventsSent to ConfigurationManager * Attempting to eliminate memory leak * Adding script to test the Plugin template * WIP * Updated to be more cross-platform friendly * Re-added cheer graffiti * Cleaning up the inner-loop build-debug-process * Addressed logger and memory leak issues #73 #114 * Fixed some tests, added UUID constructor for #119 * Added a 'RegisterAllActions' feature to the ConnectionManager * Updated to properly configure current folder * Configuring IsTestProject (#129) * Updated template to use Config * wip... * not sure why the template is doing this * getting closer * fixed attribute value retrieval defect * Fixed issues with serialization/deserialization from the property inspector * functional again (post merge) * Added missing stream deck events sent * Moved context/action dictionary into the ConnectionManager * added back in registration exceptions and updated unit tests * Start move of action management to the ActionManager class * Start some tests and refactorings for ActionManager * Implement registration and instantiation methods of ActionManager. Includes tests. * Implement registration and instantiation methods of ActionManager. Includes tests. * Add XML comments and exception for duplicate instance registration. * Add UUID attribute usage rules Make ActionManager instance for ConnectionManager injectable Finish replacement of actions dictionaries in ConnectionManager Log methods calls (with TRACE level) in ActionManager * Undo commented out project post-build events * Give ActionManager an individual named ILogger from ConnectionManager * Updated template * Fixing some issues with action instances/added unit tests to exercise them --- .gitattributes | 102 +++ .gitignore | 821 +++++++++--------- .../StreamDeckPluginTemplate.nuspec | 41 +- .../content/.template.config/template.json | 3 +- .../content/Program.cs | 62 +- .../content/README.md | 15 +- .../content/_PluginName_.cmd | 2 + .../content/_PluginName_.cs | 12 - .../content/_PluginName_Action.cs | 5 +- .../content/_StreamDeckPlugin_.csproj | 224 ++--- .../content/manifest.json | 4 +- .../content/models/CounterSettingsModel.cs | 2 +- .../property_inspector.html | 4 +- scripts/install.ps1 | 5 + scripts/install.sh | 5 + .../RegisterPluginAndStartStreamDeck.ps1 | 17 +- .../RegisterPluginAndStartStreamDeck.sh | 0 scripts/uninstall.ps1 | 2 + scripts/uninstall.sh | 2 + src/SamplePlugin/MySamplePlugin.cs | 12 - src/SamplePlugin/MySamplePluginAction.cs | 10 +- src/SamplePlugin/Program.cs | 74 +- src/SamplePlugin/SamplePlugin.cmd | 2 + src/SamplePlugin/SamplePlugin.csproj | 21 +- src/SamplePlugin/manifest.json | 2 +- .../models/CounterSettingsModel.cs | 2 +- .../property_inspector.html | 4 +- .../ConfigurationBuilder.cs | 80 ++ .../StreamDeckLib.Config.csproj | 18 + .../ActionManager_UnitTests.cs | 123 +++ .../ConnectionManager_UnitTests.cs | 128 ++- .../StreamDeckLib.Test.csproj | 3 +- src/StreamDeckLib.Test/Stubs/StubAction.cs | 43 + .../{ => Stubs}/StubProxy.cs | 1 + src/StreamDeckLib/ActionManager.cs | 319 +++++++ src/StreamDeckLib/ActionUuidAttribute.cs | 17 + src/StreamDeckLib/BaseStreamDeckAction.cs | 55 +- .../BaseStreamDeckActionWithSettingsModel.cs | 58 +- src/StreamDeckLib/BaseStreamDeckPlugin.cs | 46 - src/StreamDeckLib/ConnectionManager.cs | 129 ++- .../ConnectionManager_Actions.cs | 31 + src/StreamDeckLib/ConnectionManager_Events.cs | 13 +- .../ActionNotRegisteredException.cs | 35 + ...cateActionInstanceRegistrationException.cs | 28 + .../DuplicateActionRegistrationException.cs | 27 + .../IncompleteActionDefinitionException.cs | 23 + ...eDoesNotInheritFromBaseStreamDeckAction.cs | 41 + .../Messages/BaseStreamDeckArgs.cs | 20 +- .../Messages/GetGlobalSettingsArgs.cs | 10 +- src/StreamDeckLib/Messages/GetSettingsArgs.cs | 10 +- src/StreamDeckLib/Messages/LogMessageArgs.cs | 12 + src/StreamDeckLib/Messages/OpenUrlArgs.cs | 18 +- .../Messages/SetGlobalSettingsArgs.cs | 12 +- src/StreamDeckLib/Messages/SetStateArgs.cs | 4 +- src/StreamDeckLib/Messages/ShowAlertArgs.cs | 10 +- src/StreamDeckLib/Messages/ShowOkArgs.cs | 10 +- .../StreamDeckEventPayloadExtensions.cs | 46 +- src/StreamDeckLib/Messages/StreamDeckInfo.cs | 46 +- src/StreamDeckLib/StreamDeckLib.csproj | 3 + src/StreamDeckLib/StreamDeckProxy.cs | 2 +- src/StreamDeckToolkit.sln | 27 +- 61 files changed, 1928 insertions(+), 975 deletions(-) create mode 100644 .gitattributes create mode 100644 Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_.cmd delete mode 100644 Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_.cs create mode 100644 scripts/install.ps1 create mode 100755 scripts/install.sh rename {src/SamplePlugin => scripts/registration}/RegisterPluginAndStartStreamDeck.ps1 (85%) rename {src/SamplePlugin => scripts/registration}/RegisterPluginAndStartStreamDeck.sh (100%) create mode 100644 scripts/uninstall.ps1 create mode 100755 scripts/uninstall.sh delete mode 100644 src/SamplePlugin/MySamplePlugin.cs create mode 100644 src/SamplePlugin/SamplePlugin.cmd create mode 100644 src/StreamDeckLib.Config/ConfigurationBuilder.cs create mode 100644 src/StreamDeckLib.Config/StreamDeckLib.Config.csproj create mode 100644 src/StreamDeckLib.Test/ActionManager_UnitTests.cs create mode 100644 src/StreamDeckLib.Test/Stubs/StubAction.cs rename src/StreamDeckLib.Test/{ => Stubs}/StubProxy.cs (99%) create mode 100644 src/StreamDeckLib/ActionManager.cs create mode 100644 src/StreamDeckLib/ActionUuidAttribute.cs delete mode 100644 src/StreamDeckLib/BaseStreamDeckPlugin.cs create mode 100644 src/StreamDeckLib/ConnectionManager_Actions.cs create mode 100644 src/StreamDeckLib/Exceptions/ActionNotRegisteredException.cs create mode 100644 src/StreamDeckLib/Exceptions/DuplicateActionInstanceRegistrationException.cs create mode 100644 src/StreamDeckLib/Exceptions/DuplicateActionRegistrationException.cs create mode 100644 src/StreamDeckLib/Exceptions/IncompleteActionDefinitionException.cs create mode 100644 src/StreamDeckLib/Exceptions/TypeDoesNotInheritFromBaseStreamDeckAction.cs create mode 100644 src/StreamDeckLib/Messages/LogMessageArgs.cs diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c2ad9a4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,102 @@ +#common settings that generally should always be used with your language specific settings + +# Auto detect text files and perform LF normalization +# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ +* text=auto + +# +# The above will handle all files NOT found below +# + +# Documents +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain +*.md text +*.adoc text +*.textile text +*.mustache text +*.csv text +*.tab text +*.tsv text +*.sql text + +# Graphics +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.tif binary +*.tiff binary +*.ico binary +# SVG treated as an asset (binary) by default. If you want to treat it as text, +# comment-out the following line and uncomment the line after. +*.svg binary +#*.svg text +*.eps binary +# Auto detect text files and perform LF normalization +# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ +* text=auto + +*.cs diff=csharp + +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just comment the entries below and +# uncomment the group further below +############################################################################### + +*.sln text eol=crlf +*.csproj text eol=crlf +*.vbproj text eol=crlf +*.vcxproj text eol=crlf +*.vcproj text eol=crlf +*.dbproj text eol=crlf +*.fsproj text eol=crlf +*.lsproj text eol=crlf +*.wixproj text eol=crlf +*.modelproj text eol=crlf +*.sqlproj text eol=crlf +*.wmaproj text eol=crlf + +*.xproj text eol=crlf +*.props text eol=crlf +*.filters text eol=crlf +*.vcxitems text eol=crlf + + +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +#*.xproj merge=binary +#*.props merge=binary +#*.filters merge=binary +#*.vcxitems merge=binary diff --git a/.gitignore b/.gitignore index 8114cad..2d32f62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,409 +1,412 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ -**/Properties/launchSettings.json - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# 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/ - -# Code coverage generate by coverlet -**/coverage.json -**/coverage.cobertura.xml -**/lcov.info - -# Created by https://www.gitignore.io/api/osx,windows -# Edit at https://www.gitignore.io/?templates=osx,windows - -### OSX ### -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### Windows ### -# Windows thumbnail cache files -Thumbs.db -ehthumbs.db -ehthumbs_vista.db - -# Dump file -*.stackdump - -# Folder config file -[Dd]esktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp - -# Windows shortcuts -*.lnk - -# End of https://www.gitignore.io/api/osx,windows - -# Created by https://www.gitignore.io/api/visualstudiocode -# Edit at https://www.gitignore.io/?templates=visualstudiocode - -### VisualStudioCode ### -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -### VisualStudioCode Patch ### -# Ignore all local history of files -.history - -# End of https://www.gitignore.io/api/visualstudiocode \ No newline at end of file +## 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 + +**/content/RegisterPluginAndStartStreamDeck.sh +**/content/RegisterPluginAndStartStreamDeck.ps1 + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# 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/ + +# Code coverage generate by coverlet +**/coverage.json +**/coverage.cobertura.xml +**/lcov.info + +# Created by https://www.gitignore.io/api/osx,windows +# Edit at https://www.gitignore.io/?templates=osx,windows + +### OSX ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.gitignore.io/api/osx,windows + +# Created by https://www.gitignore.io/api/visualstudiocode +# Edit at https://www.gitignore.io/?templates=visualstudiocode + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +# End of https://www.gitignore.io/api/visualstudiocode diff --git a/Templates/StreamDeck.PluginTemplate.Csharp/StreamDeckPluginTemplate.nuspec b/Templates/StreamDeck.PluginTemplate.Csharp/StreamDeckPluginTemplate.nuspec index 804ca82..6eeede7 100644 --- a/Templates/StreamDeck.PluginTemplate.Csharp/StreamDeckPluginTemplate.nuspec +++ b/Templates/StreamDeck.PluginTemplate.Csharp/StreamDeckPluginTemplate.nuspec @@ -1,20 +1,21 @@ - - - - StreamDeckPluginTemplate - $version$ - csharpfritz - Templates for creating a plugin for the Elgato (Corsair) Stream Deck - en-US - https://github.com/FritzAndFriends/StreamDeckToolkit/ - https://github.com/FritzAndFriends/StreamDeckToolkit/blob/master/LICENSE - - dotnet templates - - - - - - - - + + + + StreamDeckPluginTemplate + $version$ + csharpfritz + Templates for creating a plugin for the Elgato (Corsair) Stream Deck + en-US + https://github.com/FritzAndFriends/StreamDeckToolkit/ + https://github.com/FritzAndFriends/StreamDeckToolkit/blob/master/LICENSE + + dotnet templates + + + + + + + + + diff --git a/Templates/StreamDeck.PluginTemplate.Csharp/content/.template.config/template.json b/Templates/StreamDeck.PluginTemplate.Csharp/content/.template.config/template.json index 142a631..108ec74 100644 --- a/Templates/StreamDeck.PluginTemplate.Csharp/content/.template.config/template.json +++ b/Templates/StreamDeck.PluginTemplate.Csharp/content/.template.config/template.json @@ -34,7 +34,6 @@ "datatype": "string", "description": "The name of the stream deck plugin.", "defaultValue": "MyPlugin", - "FileRename" : "_PluginName_", "replaces": "$(PluginName)" }, "uuid": { @@ -72,4 +71,4 @@ "continueOnError": true } ] - } \ No newline at end of file + } diff --git a/Templates/StreamDeck.PluginTemplate.Csharp/content/Program.cs b/Templates/StreamDeck.PluginTemplate.Csharp/content/Program.cs index 7b84520..9e007ea 100644 --- a/Templates/StreamDeck.PluginTemplate.Csharp/content/Program.cs +++ b/Templates/StreamDeck.PluginTemplate.Csharp/content/Program.cs @@ -5,6 +5,7 @@ using StreamDeckLib; using System; using System.IO; +using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -13,69 +14,22 @@ namespace _StreamDeckPlugin_ { - class Program + class Program { - static ILoggerFactory GetLoggerFactory() - { - var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - Directory.SetCurrentDirectory(dir); - - var configuration = new ConfigurationBuilder() - .AddJsonFile("appsettings.json") - .Build(); - - Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(configuration) - .CreateLogger(); - - var loggerFactory = new LoggerFactory() - .AddSerilog(Log.Logger); - - TopLogger = loggerFactory.CreateLogger("top"); - - TopLogger.LogInformation("Plugin started"); - - return loggerFactory; - } - - private static Microsoft.Extensions.Logging.ILogger TopLogger; static async Task Main(string[] args) { - -#if DEBUG - - Debugger.Launch(); - - while (!Debugger.IsAttached) - { - await Task.Delay(100); - } - -#endif - using (var source = new CancellationTokenSource()) + using (var config = StreamDeckLib.Config.ConfigurationBuilder.BuildDefaultConfiguration(args)) { - using (var loggerFactory = GetLoggerFactory()) - { - try - { - await ConnectionManager.Initialize(args, loggerFactory) - .SetPlugin(new $(PluginName)()) - .StartAsync(source.Token); - - Console.ReadLine(); - - } - catch (Exception ex) - { - TopLogger.LogError(ex, "Error while running the plugin"); - } - source.Cancel(); - } + await ConnectionManager.Initialize(args, config.LoggerFactory) + .RegisterAllActions(typeof(Program).Assembly) + .StartAsync(); } + } + } } diff --git a/Templates/StreamDeck.PluginTemplate.Csharp/content/README.md b/Templates/StreamDeck.PluginTemplate.Csharp/content/README.md index c4c7ebb..17c81ef 100644 --- a/Templates/StreamDeck.PluginTemplate.Csharp/content/README.md +++ b/Templates/StreamDeck.PluginTemplate.Csharp/content/README.md @@ -10,7 +10,7 @@ Within the directory from which you are reading this file, there exist a few oth * `_StreamDeckPlugin_.csproj`: The C# project file used to build the plugin * `Program.cs`: The code for the application which will be called by the [Stream Deck software][] when loading and running your plugin. -* `_PluginName_.cs`: The file in which the functionality of the plugin will be written. This file provides the proverbial guts of your plugin. +* `DefaultPluginAction.cs`: The file in which the functionality of the first (default) action for the plugin will be written. This file provides a basic implementation of an action for your plugin, following a pattern which can be repeated. ## What's Next? @@ -91,6 +91,19 @@ The **Key Icon** is the icon which is displayed on the key(s) to which is is ass Again, just as with the **Category Icon** and the **Action Image**,two separate copies of this file are needed, with the same naming rules but different sizes; a default one for a regular, non-scaled (high-DPI) display, and another for scaled display. The default icon should be 72 pixels squared (72x72px). Again, it should preferably named in a manner in which it can be easily related to either the action or state is represents, such as `actionIconButton.png` or `actionIconActive.png`. +### Can I do any more? + +Of course! First, congratulations on getting your first action for your Stream Deck plugin working! To allow your plugin to do more, you will need to create (and implement) a new Action definition. Here is how you do this: + +1. Create a new class (in a new file or an existing one), and make sure it inherits from the `BaseStreamDeckAction` class +e.g.: `internal class MyNextPluginAction : BaseStreamDeckAction` +2. Implement the required properties and methods, such as `UUID` +3. Register it with the `ConnectionManager` instance within the `Program.cs` file. Look for the `.RegisterAction(new DefaultPluginAction()` code line, copy it, and change the type `DefaultPluginAction` to your new class' name. From the example in step 1, this would look like `.RegisterAction(new MyNextPluginAction())`. +4. Add a definition for the new action in the `manifest.json` file, ensuring that the value for the `UUID` field in the manifest matches the `UUID` property of your new class. + +That's it! Repeat this process for any additional actions you wish to include and perform as part of your plugin. + + ## References Here are some helpful references for both this template and the Stream Deck: diff --git a/Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_.cmd b/Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_.cmd new file mode 100644 index 0000000..e14689b --- /dev/null +++ b/Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_.cmd @@ -0,0 +1,2 @@ +cd %appdata%\Elgato\StreamDeck\Plugins\$(UUID) +SamplePlugin.exe -break %* diff --git a/Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_.cs b/Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_.cs deleted file mode 100644 index 7ee51e9..0000000 --- a/Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_.cs +++ /dev/null @@ -1,12 +0,0 @@ -using StreamDeckLib; - -namespace _StreamDeckPlugin_ -{ - internal class $(PluginName) : BaseStreamDeckPlugin - { - public override void RegisterActionTypes() - { - this.RegisterActionType("$(UUID)", typeof($(PluginName)Action)); - } - } -} diff --git a/Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_Action.cs b/Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_Action.cs index 59bff9b..c4a2c3d 100644 --- a/Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_Action.cs +++ b/Templates/StreamDeck.PluginTemplate.Csharp/content/_PluginName_Action.cs @@ -8,8 +8,11 @@ namespace _StreamDeckPlugin_ { + [ActionUuid(Uuid="$(UUID)")] public class $(PluginName)Action : BaseStreamDeckActionWithSettingsModel { + // Cheer 342 cpayette 15/2/19 + // Cheer 100 devlead 15/2/19 // Cheer 200 kevin_downs Jan 11, 2019 // Cheer 401 cpayette Jan 15, 2019 // Cheer 2501 themikejolley Jan 15, 2019 @@ -23,8 +26,6 @@ public class $(PluginName)Action : BaseStreamDeckActionWithSettingsModel "$(UUID)"; - public override async Task OnKeyUp(StreamDeckEventPayload args) { SettingsModel.Counter++; diff --git a/Templates/StreamDeck.PluginTemplate.Csharp/content/_StreamDeckPlugin_.csproj b/Templates/StreamDeck.PluginTemplate.Csharp/content/_StreamDeckPlugin_.csproj index f2ab86c..8996986 100644 --- a/Templates/StreamDeck.PluginTemplate.Csharp/content/_StreamDeckPlugin_.csproj +++ b/Templates/StreamDeck.PluginTemplate.Csharp/content/_StreamDeckPlugin_.csproj @@ -1,105 +1,119 @@ - - - - Exe - netcoreapp2.2 - latest - - win-x64 - - osx-x64 - - win-x64;osx-x64 - OnBuildSuccess - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - Never - - - - - - - Never - - - Never - - - - + + + + Exe + netcoreapp2.2 + latest + + win-x64 + + osx-x64 + + win-x64;osx-x64 + OnBuildSuccess + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + PreserveNewest + + + + + + + Never + + + + + + + Never + + + Never + + + + + + + + + diff --git a/Templates/StreamDeck.PluginTemplate.Csharp/content/manifest.json b/Templates/StreamDeck.PluginTemplate.Csharp/content/manifest.json index 56ac8a3..6c1fa7b 100644 --- a/Templates/StreamDeck.PluginTemplate.Csharp/content/manifest.json +++ b/Templates/StreamDeck.PluginTemplate.Csharp/content/manifest.json @@ -11,8 +11,8 @@ } ], "SupportedInMultiActions": false, - "Tooltip": "", - "UUID": "$(UUID)" + "Tooltip": "The first action for the $(PluginName) Stream Deck plugin", + "UUID": "$(UUID).DefaultPluginAction" } ], "Author": "", diff --git a/Templates/StreamDeck.PluginTemplate.Csharp/content/models/CounterSettingsModel.cs b/Templates/StreamDeck.PluginTemplate.Csharp/content/models/CounterSettingsModel.cs index 0f30ba3..4095586 100644 --- a/Templates/StreamDeck.PluginTemplate.Csharp/content/models/CounterSettingsModel.cs +++ b/Templates/StreamDeck.PluginTemplate.Csharp/content/models/CounterSettingsModel.cs @@ -1,4 +1,4 @@ -namespace _StreamDeckPlugin_.models +namespace _StreamDeckPlugin_.Models { public class CounterSettingsModel { diff --git a/Templates/StreamDeck.PluginTemplate.Csharp/content/property_inspector/property_inspector.html b/Templates/StreamDeck.PluginTemplate.Csharp/content/property_inspector/property_inspector.html index e65b323..8956485 100644 --- a/Templates/StreamDeck.PluginTemplate.Csharp/content/property_inspector/property_inspector.html +++ b/Templates/StreamDeck.PluginTemplate.Csharp/content/property_inspector/property_inspector.html @@ -14,9 +14,9 @@ Elgato SDK Documentation -> https://developer.elgato.com/documentation/stream-deck/sdk/property-inspector/ --> -
+
Counter Value
- +
diff --git a/scripts/install.ps1 b/scripts/install.ps1 new file mode 100644 index 0000000..0f66cf9 --- /dev/null +++ b/scripts/install.ps1 @@ -0,0 +1,5 @@ +# Copy registration scripts to the local tempalte directory +get-childitem -path "scripts/registration/" -filter *.* -recurse | copy-item -destination "Templates/StreamDeck.PluginTemplate.Csharp/content" + +# Install the template +dotnet new -i Templates/StreamDeck.PluginTemplate.Csharp diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000..b7b8d70 --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,5 @@ +# Copy registration scripts to the local tempalte directory +cp -avf scripts/registration/. Templates/StreamDeck.PluginTemplate.Csharp/content + +# Install the template +dotnet new -i Templates/StreamDeck.PluginTemplate.Csharp diff --git a/src/SamplePlugin/RegisterPluginAndStartStreamDeck.ps1 b/scripts/registration/RegisterPluginAndStartStreamDeck.ps1 similarity index 85% rename from src/SamplePlugin/RegisterPluginAndStartStreamDeck.ps1 rename to scripts/registration/RegisterPluginAndStartStreamDeck.ps1 index e8e2340..6e2e9dd 100644 --- a/src/SamplePlugin/RegisterPluginAndStartStreamDeck.ps1 +++ b/scripts/registration/RegisterPluginAndStartStreamDeck.ps1 @@ -1,16 +1,11 @@ Write-Host "Gathering deployment items..." -Write-Host "Script root: $PSScriptRoot`n" +Write-Host "Current Working Directory: $(get-location)" -$basePath = $PSScriptRoot +$basePath = $(get-location) -if (!($PSSCriptRoot)) { - $basePath = $PWD.Path; -} - - -# Load and parse the plugin project file -$pluginProjectFile = Join-Path $basePath "SamplePlugin.csproj" +# Load and parse the plugin project file - Fully expects there to be only one csproj file in there +$pluginProjectFile = Get-ChildItem -Filter *.csproj | Select-Object -First 1 $projectContent = Get-Content $pluginProjectFile | Out-String; $projectXML = [xml]$projectContent; @@ -30,7 +25,7 @@ if ($IsMacOS) { # Make sure we actually have a directory/build to deploy If (-not (Test-Path $bindir)) { - Write-Error "The output directory `"$bindir`" was not found.`n You must first build the `"SamplePlugin.csproj`" project before calling this script."; + Write-Error "The output directory `"$bindir`" was not found.`n You must first build the project before calling this script."; exit 1; } @@ -60,6 +55,6 @@ $bindir = Join-Path $bindir "*" New-Item -Type Directory -Path $destDir -ErrorAction SilentlyContinue # | Out-Null Copy-Item -Path $bindir -Destination $destDir -Recurse - Write-Host "Deployment complete. We will NOT restart the Stream Deck desktop application here, but will from the template..." # Start-Process $streamDeckExePath +exit 0 \ No newline at end of file diff --git a/src/SamplePlugin/RegisterPluginAndStartStreamDeck.sh b/scripts/registration/RegisterPluginAndStartStreamDeck.sh similarity index 100% rename from src/SamplePlugin/RegisterPluginAndStartStreamDeck.sh rename to scripts/registration/RegisterPluginAndStartStreamDeck.sh diff --git a/scripts/uninstall.ps1 b/scripts/uninstall.ps1 new file mode 100644 index 0000000..128a00b --- /dev/null +++ b/scripts/uninstall.ps1 @@ -0,0 +1,2 @@ +#Uninstall the Template +dotnet new -u Templates/StreamDeck.PluginTemplate.Csharp diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh new file mode 100755 index 0000000..6d9cde9 --- /dev/null +++ b/scripts/uninstall.sh @@ -0,0 +1,2 @@ +#Uninstall the Template +dotnet new -u $PWD/Templates/StreamDeck.PluginTemplate.Csharp diff --git a/src/SamplePlugin/MySamplePlugin.cs b/src/SamplePlugin/MySamplePlugin.cs deleted file mode 100644 index 503a7ed..0000000 --- a/src/SamplePlugin/MySamplePlugin.cs +++ /dev/null @@ -1,12 +0,0 @@ -using StreamDeckLib; - -namespace SamplePlugin -{ - internal class MySamplePlugin : BaseStreamDeckPlugin - { - public override void RegisterActionTypes() - { - this.RegisterActionType("com.csharpfritz.samplePlugin.action", typeof(MySamplePluginAction)); - } - } -} diff --git a/src/SamplePlugin/MySamplePluginAction.cs b/src/SamplePlugin/MySamplePluginAction.cs index 20877d4..8b03973 100644 --- a/src/SamplePlugin/MySamplePluginAction.cs +++ b/src/SamplePlugin/MySamplePluginAction.cs @@ -1,15 +1,15 @@ -using SamplePlugin.models; +using SamplePlugin.Models; using StreamDeckLib; using StreamDeckLib.Messages; -using System; -using System.Collections.Generic; -using System.Text; using System.Threading.Tasks; namespace SamplePlugin { + [ActionUuid(Uuid = "com.csharpfritz.samplePlugin.action")] public class MySamplePluginAction : BaseStreamDeckActionWithSettingsModel { + // Cheer 342 cpayette 15/2/19 + // Cheer 100 devlead 15/2/19 // Cheer 200 kevin_downs Jan 11, 2019 // Cheer 401 cpayette Jan 15, 2019 // Cheer 2501 themikejolley Jan 15, 2019 @@ -22,8 +22,6 @@ public class MySamplePluginAction : BaseStreamDeckActionWithSettingsModel "com.csharpfritz.samplePlugin.action"; public override async Task OnKeyUp(StreamDeckEventPayload args) { diff --git a/src/SamplePlugin/Program.cs b/src/SamplePlugin/Program.cs index ee81671..b9c15b3 100644 --- a/src/SamplePlugin/Program.cs +++ b/src/SamplePlugin/Program.cs @@ -1,79 +1,21 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using Serilog; using StreamDeckLib; -using System; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Threading; using System.Threading.Tasks; namespace SamplePlugin { class Program { - static ILoggerFactory GetLoggerFactory() - { - var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - Directory.SetCurrentDirectory(dir); - - var configuration = new ConfigurationBuilder() - .AddJsonFile("appsettings.json") - .Build(); - - Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(configuration) - .CreateLogger(); - - var loggerFactory = new LoggerFactory() - .AddSerilog(Log.Logger); - - TopLogger = loggerFactory.CreateLogger("top"); - - TopLogger.LogInformation("Plugin started"); - - return loggerFactory; - } - - private static Microsoft.Extensions.Logging.ILogger TopLogger; - + // Cheer 200 careypayette February 14, 2019 + // Cheer 100 roberttables February 14, 2019 + // Cheer 100 careypayette February 15, 2019 + // Cheer 100 devlead 15/2/2019 static async Task Main(string[] args) { - - -#if DEBUG - - Debugger.Launch(); - - while (!Debugger.IsAttached) - { - await Task.Delay(100); - } - -#endif - using (var source = new CancellationTokenSource()) + using (var config = StreamDeckLib.Config.ConfigurationBuilder.BuildDefaultConfiguration(args)) { - using (var loggerFactory = GetLoggerFactory()) - { - try - { - - // codingbandit: I had to take out the using statement as it was causing the dispose method to be called (and disposing the socket connection) - await ConnectionManager.Initialize(args, loggerFactory) - .SetPlugin(new MySamplePlugin()) - .StartAsync(source.Token); - - Console.ReadLine(); - - } - catch (Exception ex) - { - TopLogger.LogError(ex, "Error while running the plugin"); - } - source.Cancel(); - } - + await ConnectionManager.Initialize(args, config.LoggerFactory) + .RegisterAllActions(typeof(Program).Assembly) + .StartAsync(); } } } diff --git a/src/SamplePlugin/SamplePlugin.cmd b/src/SamplePlugin/SamplePlugin.cmd new file mode 100644 index 0000000..9af9e37 --- /dev/null +++ b/src/SamplePlugin/SamplePlugin.cmd @@ -0,0 +1,2 @@ +cd %appdata%\Elgato\StreamDeck\Plugins\com.csharpfritz.samplePlugin.sdPlugin +SamplePlugin.exe -break %* diff --git a/src/SamplePlugin/SamplePlugin.csproj b/src/SamplePlugin/SamplePlugin.csproj index 9e5f383..32f25ad 100644 --- a/src/SamplePlugin/SamplePlugin.csproj +++ b/src/SamplePlugin/SamplePlugin.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.2 + netcoreapp2.1 latest win-x64 osx-x64 @@ -15,9 +15,11 @@ + + @@ -74,21 +76,14 @@ PreserveNewest - - - - - - Never - - - Never - + + PreserveNewest + - - + + diff --git a/src/SamplePlugin/manifest.json b/src/SamplePlugin/manifest.json index 7f5c73a..4e3418e 100644 --- a/src/SamplePlugin/manifest.json +++ b/src/SamplePlugin/manifest.json @@ -17,7 +17,7 @@ ], "Disabled": false, "Author": "Jeffrey T. Fritz", - "CodePathWin": "SamplePlugin.exe", + "CodePathWin": "SamplePlugin.cmd", "CodePathMac": "SamplePlugin", "PropertyInspectorPath": "property_inspector/property_inspector.html", "Description": "The Sample Plugin", diff --git a/src/SamplePlugin/models/CounterSettingsModel.cs b/src/SamplePlugin/models/CounterSettingsModel.cs index edbbad0..74e0551 100644 --- a/src/SamplePlugin/models/CounterSettingsModel.cs +++ b/src/SamplePlugin/models/CounterSettingsModel.cs @@ -1,4 +1,4 @@ -namespace SamplePlugin.models +namespace SamplePlugin.Models { public class CounterSettingsModel { diff --git a/src/SamplePlugin/property_inspector/property_inspector.html b/src/SamplePlugin/property_inspector/property_inspector.html index 8e2eaf7..87c9b5f 100644 --- a/src/SamplePlugin/property_inspector/property_inspector.html +++ b/src/SamplePlugin/property_inspector/property_inspector.html @@ -14,9 +14,9 @@ Elgato SDK Documentation -> https://developer.elgato.com/documentation/stream-deck/sdk/property-inspector/ --> -
+
Counter Value
- +
diff --git a/src/StreamDeckLib.Config/ConfigurationBuilder.cs b/src/StreamDeckLib.Config/ConfigurationBuilder.cs new file mode 100644 index 0000000..963cdcd --- /dev/null +++ b/src/StreamDeckLib.Config/ConfigurationBuilder.cs @@ -0,0 +1,80 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Serilog; +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using CONFIG = Microsoft.Extensions.Configuration; + +namespace StreamDeckLib.Config +{ + public class ConfigurationBuilder : IDisposable + { + + private ConfigurationBuilder(string[] args) { + +#if DEBUG + // This gives us our "first chance" debugging, before even parsing the command + // line args, without the need to manually edit the code to toggle the feature + // ability on or off. + + if (args.Select(arg => arg.Replace("--", "-")) + .Any(arg => arg.Equals("-break"))) + { + Console.WriteLine("Debugging has been requested. Waiting for a debugger to attach..."); + Debugger.Launch(); + + while (!Debugger.IsAttached) + { + Task.Delay(500).GetAwaiter().GetResult(); + Console.Write("."); + } + } +#endif + } + private static ConfigurationBuilder Instance; + + public static ConfigurationBuilder BuildDefaultConfiguration(string[] args) { + + var dir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + Directory.SetCurrentDirectory(dir); + + var configuration = new CONFIG.ConfigurationBuilder() + .AddJsonFile("appsettings.json") + .Build(); + + Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(configuration) + .CreateLogger(); + + Instance = new ConfigurationBuilder(args) + { + LoggerFactory = new LoggerFactory() + .AddSerilog(Log.Logger) + }; + + return Instance; + + } + + public ILoggerFactory LoggerFactory { get; private set; } + + + public void Dispose() + { + + #if DEBUG + if (Debugger.IsAttached) + { + // If a debugger is attached, give the developer a last chance to inspect + // variables, state, etc. before the process terminates. + Debugger.Break(); + } +#endif + + } + } +} diff --git a/src/StreamDeckLib.Config/StreamDeckLib.Config.csproj b/src/StreamDeckLib.Config/StreamDeckLib.Config.csproj new file mode 100644 index 0000000..2c61f0e --- /dev/null +++ b/src/StreamDeckLib.Config/StreamDeckLib.Config.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp2.1 + + + + + + + + + + + + + + diff --git a/src/StreamDeckLib.Test/ActionManager_UnitTests.cs b/src/StreamDeckLib.Test/ActionManager_UnitTests.cs new file mode 100644 index 0000000..6834f99 --- /dev/null +++ b/src/StreamDeckLib.Test/ActionManager_UnitTests.cs @@ -0,0 +1,123 @@ +using System; +using Xunit; + +namespace StreamDeckLib.Test +{ + + public class ActionManagerShould + { + + [Fact] + public void ThrowActionNotRegisteredException_WhenRetrievingAnUnregisteredAction() + { + // Arrange + using (var SUT = new ActionManager(null)) + { + // Act + + // Assert + Assert.Throws(() => SUT.GetAction("UUID1")); + + } + } + + [Fact] + public void ShowOneSingleActionRegistered_WhenRegisteringOnlyOneAction() + { + // + // Arrange + // + + var testAction = new StubAction(); + BaseStreamDeckAction returnedAction; + + // + // Act + // + using (var SUT = new ActionManager(null)) + { + + SUT.RegisterAction("UUID1"); + returnedAction = SUT.GetActionInstance("UUID1"); + } + + // + // Assert + // + Assert.NotNull(returnedAction); + + Assert.IsType(returnedAction); + } + + + + [Fact] + public void ShouldReturnTrue_WhenInquiredAboutRegistrationOfRegisteredActionUUID() + { + // + // Arrange + // + using (var SUT = new ActionManager(null)) + { + + // + // Act + // + SUT.RegisterAction("UUID1"); + + // + // Assert + // + Assert.True(SUT.IsActionRegistered("UUID1")); + + } + } + + + [Fact] + public void ShouldReturnFalse_WhenInquiredAboutRegistrationOfUnregisteredActionUUID() + { + // + // Arrange + // + using (var SUT = new ActionManager(null)) + { + + // + // Act + // + SUT.RegisterAction("UUID1"); + + // + // Assert + // + Assert.False(SUT.IsActionRegistered("UUID2")); + + } + } + + + + [Fact] + public void ShouldReturnTrue_WhenInquiredAboutRegistrationOfActionUUIDWithDifferentCasing() + { + // + // Arrange + // + using (var SUT = new ActionManager(null)) + { + + // + // Act + // + SUT.RegisterAction("UUID1"); + + // + // Assert + // + Assert.True(SUT.IsActionRegistered("uuID1")); + } + } + + } +} \ No newline at end of file diff --git a/src/StreamDeckLib.Test/ConnectionManager_UnitTests.cs b/src/StreamDeckLib.Test/ConnectionManager_UnitTests.cs index b2e2c30..254ca52 100644 --- a/src/StreamDeckLib.Test/ConnectionManager_UnitTests.cs +++ b/src/StreamDeckLib.Test/ConnectionManager_UnitTests.cs @@ -7,8 +7,9 @@ namespace StreamDeckLib.Test { - public class ConnectionManagerShould - { + + public class ConnectionManagerShould + { [Fact] public void ThrowAnArgumentException_WhenInitializedWithEmptyArgs() { @@ -23,23 +24,126 @@ public void ThrowAnArgumentException_WhenInitializedWithEmptyArgs() } [Fact] - public async Task ShouldRegisterEvent_WhenInitializedWithCorrectArgs() { - + public async Task ShouldRegisterEvent_WhenInitializedWithCorrectArgs() + { // Arrange - var stub = new StubProxy() { - InspectRegister = (e, uuid) => { - Assert.Equal(StubProxy.TEST_EVENT, e); - Assert.Equal(uuid, uuid); - } - }; + var stub = new StubProxy() + { + InspectRegister = (e, uuid) => + { + Assert.Equal(StubProxy.TEST_EVENT, e); + Assert.Equal(uuid, uuid); + } + }; // Act - await ConnectionManager.Initialize(StubProxy.ValidCommandLineArguments, null, stub) - .StartAsync(CancellationToken.None); + var tokenSource = new CancellationTokenSource(); + var task = ConnectionManager.Initialize(StubProxy.ValidCommandLineArguments, null, stub) + .StartAsync(); // Assert + Assert.Null(task.Exception); + tokenSource.Cancel(); } + [Fact] + public async Task ShouldThrowArgumentException_WhenRegisteringAnActionWithoutAUUID() + { + // + // Arrange + // + + Func action = () => ConnectionManager.Initialize(StubProxy.ValidCommandLineArguments) + .RegisterActionType("", typeof(StubAction)); + + // + // Act + // + action. + + // + // Assert + // + Should().Throw("An action must specify a non-blank or empty UUID"); + } + + [Fact] + public async Task ShouldThrowDuplicateActionRegistrationException_WhenRegisteringMultipleInstancesOfTheSameAction() + { + // + // Arrange + // + + + Func action = () => ConnectionManager.Initialize(StubProxy.ValidCommandLineArguments) + .RegisterActionType("UniqueID", typeof(StubAction)) + .RegisterActionType("UniqueID", typeof(StubAction)); + + // + // Assert + // + + //TODO: Wording? "unique UUID" is like saying "PIN number". It's "just" a test, but still syntactically incorrect. + action.Should() + .Throw("each BaseStreamDeckAction type should have its own unique UUID."); + } + + + [Fact] + public async Task ShouldNotThrowAnyExceptions_WhenRegistringMultipleUniqueActions() + { + // + // Arrange + // + + + Func action = () => ConnectionManager.Initialize(StubProxy.ValidCommandLineArguments) + .RegisterActionType("Unique_Action_ID_1", typeof(StubAction)) + .RegisterActionType("Unique_Action_ID_2", typeof(StubAction)); + + + // + // Assert + // + + //TODO: Wording? "unique UUID" is like saying "PIN number". It's "just" a test, but still syntactically incorrect. + action.Should() + .NotThrow("registering multiple unique actions is valid"); + } + + [Fact] + public async Task ShouldRegisterAllActions_WhenRegisteringAllActions() + { + + Func action = () => ConnectionManager.Initialize(StubProxy.ValidCommandLineArguments) + .RegisterAllActions(this.GetType().Assembly); + + action.Should() + .NotThrow("No problems when registering All Actions"); + + + } + + [Fact] + public async Task ShouldHaveConnectionManagerAssigned_WhenGettingAnActionInstance() + { + var cm = ConnectionManager.Initialize(StubProxy.ValidCommandLineArguments) + .RegisterActionType("Unique_Action_ID_1", typeof(StubAction)); + var action = cm.GetInstanceOfAction("FAKECONTEXT", "Unique_Action_ID_1") as StubAction; + action.GetConnectionManager().Should().NotBeNull("An action must have a connection manager assigned"); + + } + + [Fact] + public async Task ShouldHaveLoggerAssigned_WhenGettingAnActionInstance() + { + var cm = ConnectionManager.Initialize(StubProxy.ValidCommandLineArguments) + .RegisterActionType("Unique_Action_ID_1", typeof(StubAction)); + var action = cm.GetInstanceOfAction("FAKECONTEXT", "Unique_Action_ID_1") as StubAction; + action.GetLogger().Should().NotBeNull("An action must have a logger assigned"); + } + } + } diff --git a/src/StreamDeckLib.Test/StreamDeckLib.Test.csproj b/src/StreamDeckLib.Test/StreamDeckLib.Test.csproj index 68e5668..5b62745 100644 --- a/src/StreamDeckLib.Test/StreamDeckLib.Test.csproj +++ b/src/StreamDeckLib.Test/StreamDeckLib.Test.csproj @@ -1,9 +1,10 @@  - netcoreapp2.2 + netcoreapp2.1 latest false + true diff --git a/src/StreamDeckLib.Test/Stubs/StubAction.cs b/src/StreamDeckLib.Test/Stubs/StubAction.cs new file mode 100644 index 0000000..3ad2fc3 --- /dev/null +++ b/src/StreamDeckLib.Test/Stubs/StubAction.cs @@ -0,0 +1,43 @@ +using Microsoft.Extensions.Logging; + +namespace StreamDeckLib.Test +{ + [ActionUuid(Uuid = "Test UUID")] + public class StubAction : BaseStreamDeckAction + { + + public StubAction() : this("Test UUID") + { + + } + + public StubAction(string uuid) + { + this._uuid = uuid; + } + + private string _uuid; + + + public StubAction SetUUID(string uuid) + { + this._uuid = uuid; + + return this; + } + + public ConnectionManager GetConnectionManager() + { + return this.Manager; + } + + public ILogger GetLogger() + { + return this.Logger; + } + + + + } + +} diff --git a/src/StreamDeckLib.Test/StubProxy.cs b/src/StreamDeckLib.Test/Stubs/StubProxy.cs similarity index 99% rename from src/StreamDeckLib.Test/StubProxy.cs rename to src/StreamDeckLib.Test/Stubs/StubProxy.cs index 968302b..04a555b 100644 --- a/src/StreamDeckLib.Test/StubProxy.cs +++ b/src/StreamDeckLib.Test/Stubs/StubProxy.cs @@ -84,4 +84,5 @@ public Task SendStreamDeckEvent(BaseStreamDeckArgs args) } } + } diff --git a/src/StreamDeckLib/ActionManager.cs b/src/StreamDeckLib/ActionManager.cs new file mode 100644 index 0000000..0c1a616 --- /dev/null +++ b/src/StreamDeckLib/ActionManager.cs @@ -0,0 +1,319 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reflection; + +namespace StreamDeckLib +{ + + public partial class ActionManager : IDisposable + { + #region Type and instance properties + + // We will use a string equality comparer for our dictionaries which ignores case and is for invariant culture. + private static readonly IEqualityComparer _StringEqualityComparer = StringComparer.Create(CultureInfo.InvariantCulture, true); + + //string is the action UUID, type is the class type of the action + private readonly Dictionary _Actions; + + //string is the context, there will only ever be one action per context + private readonly Dictionary _ActionInstances; + + // The logger we will receive when being instantiated. Defaults to a NullLogger is none is specified. + private readonly ILogger _Logger; + + private ConnectionManager _ConnectionManager; + + #endregion + + + #region Constructors + + private ActionManager() + { + this._Actions = new Dictionary(_StringEqualityComparer); + this._ActionInstances = new Dictionary(_StringEqualityComparer); + } + + /// + /// Initializes a new instance of the class. + /// + /// An instance of a logger ( class. + public ActionManager(ConnectionManager manager, ILogger logger = null) : this() + { + this._Logger = logger ?? NullLoggerFactory.Instance.CreateLogger(nameof(ActionManager)); + this._ConnectionManager = manager; + } + + #endregion + + + #region Action registration methods + + + /// + /// Registers an action type for a given UUID. + /// + /// The instance of . + /// The UUID for the action. + /// The type to be registered for the . Must inherit from . + public ActionManager RegisterAction(string actionUUID) + where TActionType : BaseStreamDeckAction + { + this._Logger.LogTrace($"{nameof(ActionManager)}.{nameof(RegisterAction)}(string)"); + + this._Actions.Add(actionUUID, typeof(TActionType)); + return this; + } + + + /// + /// Registers an action type for a given UUID. + /// + /// The instance of . + /// The UUID for the action. + /// The type to be registered for the . Must inherit from . + /// If the does not inherit from , + /// a exception is thrown. + public ActionManager RegisterActionType(string actionUuid, Type actionType) + { + this._Logger.LogTrace($"{nameof(ActionManager)}.{nameof(RegisterActionType)}(string, Type)"); + + // Check that we've got a UUID to use for registration. + if (string.IsNullOrWhiteSpace(actionUuid)) + { + throw new IncompleteActionDefinitionException($"The UUID for the \"{actionType.Name}\" action was not specified."); + } + + if (_Actions.ContainsKey(actionUuid)) + { + throw new DuplicateActionRegistrationException(actionUuid); + } + + // Ensure that the type we're registering inherits from BaseStreamDeckAction. + if (!actionType.IsSubclassOf(typeof(BaseStreamDeckAction))) + { + throw new TypeDoesNotInheritFromBaseStreamDeckAction(actionType.Name, actionType.FullName, actionType.Assembly.FullName); + } + + this._Actions.Add(actionUuid, actionType); + return this; + } + + + /// + /// Registers all actions which are decorated with an + /// withn a given . + /// + /// The instance of . + /// The from within which actions are to be registered. + public ActionManager RegisterAllActions(Assembly actionsAssembly) + { + this._Logger.LogTrace($"{nameof(ActionManager)}.{nameof(RegisterAllActions)}(assembly)"); + + var actions = actionsAssembly.GetTypes().Where(type => Attribute.IsDefined(type, typeof(ActionUuidAttribute))); + foreach (var actionType in actions) + { + var attr = actionType.GetCustomAttributes(typeof(ActionUuidAttribute), true).FirstOrDefault() as ActionUuidAttribute; + this.RegisterActionType(attr.Uuid, actionType); + } + return this; + } + + #endregion + + + #region Action instance creation and retrieval + + /// + /// Gets an instance of an action from an action UUID. + /// + /// A new instance of an action. + /// The UUID of the action type which is requested. + /// The specific type of action to be returned. + /// If no type is found to match the , an exception + /// of type is thrown. + public TActionType GetActionInstance(string actionUUID) + where TActionType : BaseStreamDeckAction + { + this._Logger.LogTrace($"{nameof(ActionManager)}.{nameof(GetActionInstance)}(string)"); + + if (this._Actions.ContainsKey(actionUUID)) + { + var instance = Activator.CreateInstance(this._Actions[actionUUID]) as TActionType; + instance.Logger = _Logger; + instance.Manager = _ConnectionManager; + return instance; + } + + throw new ActionNotRegisteredException(actionUUID); + } + + + /// + /// Checks whether an action is registered for a given UUID. + /// + /// true, if action registered was registered, false otherwise. + /// The UUID to check + public bool IsActionRegistered(string actionUUID) + { + this._Logger.LogTrace($"{nameof(ActionManager)}.{nameof(IsActionRegistered)}(string)"); + + return this._Actions.ContainsKey(actionUUID); + } + + + /// + /// Gets a new instance of an registered with a UUID + /// of . This instance will not be stored or managed, + /// and cannot be reused. + /// + /// A new instance of the action + /// The UUID of the action type which is to be instantiated + /// + /// Throws a exception if there is no action with + /// a UUID of registered. + /// + public BaseStreamDeckAction GetAction(string actionUUID) + { + this._Logger.LogTrace($"{nameof(ActionManager)}.{nameof(GetAction)}(string)"); + + return this.CreateActionInstanceByUUID(actionUUID); + } + + + private BaseStreamDeckAction CreateActionInstanceByUUID(string actionUuid, bool throwIfNotRegistered = true) + { + this._Logger.LogTrace($"{nameof(ActionManager)}.{nameof(CreateActionInstanceByUUID)}(string, bool)"); + if (this._Actions.ContainsKey(actionUuid)) + { + var instance = Activator.CreateInstance(this._Actions[actionUuid]) as BaseStreamDeckAction; + instance.Logger = _Logger; + instance.Manager = _ConnectionManager; + return instance; + + } + + if (throwIfNotRegistered) + { + throw new ActionNotRegisteredException(actionUuid); + } + + return null; + } + + #endregion + + + #region Specific action instance creation, registration, and retrieval (by Stream Deck context) + + + /// + /// Registers the action instance. + /// + /// The action instance. + /// The key to be used when registering the action instance. + /// This is typically the value of the . + /// Action instance. + public ActionManager RegisterActionInstance(string instanceKey, BaseStreamDeckAction actionInstance) + { + this._Logger.LogTrace($"{nameof(ActionManager)}.{nameof(RegisterAction)}(string, BaseStreamDeckAction)"); + return this.RegisterActionInstanceInternal(instanceKey, actionInstance); + } + + private ActionManager RegisterActionInstanceInternal(string instanceKey, BaseStreamDeckAction actionInstance, bool throwIfInstanceIsNull = true) + { + this._Logger.LogTrace($"{nameof(ActionManager)}.{nameof(RegisterActionInstanceInternal)}(string, BaseStreamDeckAction, bool)"); + + if (null == actionInstance && (!throwIfInstanceIsNull)) + { + this._Logger.LogDebug($"The instance to register with a key of {instanceKey} was null, but prevent raising an exception was specified."); + return this; + } + + if (null == actionInstance && throwIfInstanceIsNull) + { + throw new ArgumentNullException($"Could not register an action instance with a key of \"{instanceKey}\""); + } + + this._Logger.LogDebug($"Registering an instance of {actionInstance.GetType().FullName} with a key of \"{instanceKey}\"."); + if (this._ActionInstances.ContainsKey(instanceKey)) + { + throw new DuplicateActionInstanceRegistrationException(instanceKey); + } + + this._ActionInstances.Add(instanceKey, actionInstance); + + return this; + } + + + /// + /// Gets the instance of action. + /// + /// The instance of action. + /// Context. + /// Action UUID. + internal BaseStreamDeckAction GetActionForContext(string context, string actionUuid) + { + this._Logger.LogTrace($"{nameof(ActionManager)}.{nameof(GetActionForContext)}(string, string)"); + + //see if context exists, if so, return the associated action + if (this._ActionInstances.ContainsKey(context)) + { + return this._ActionInstances[context]; + } + + //see if we have a recorded type for the action + var actionInstance = this.CreateActionInstanceByUUID(actionUuid, false); + this.RegisterActionInstanceInternal(context, actionInstance, false); + + return actionInstance; + } + + + #endregion + + + #region IDisposable Support + + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: dispose managed state (managed objects). + } + + // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. + // TODO: set large fields to null. + + disposedValue = true; + } + } + + // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. + // ~ActionManager() { + // // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + // Dispose(false); + // } + + // This code added to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + // TODO: uncomment the following line if the finalizer is overridden above. + // GC.SuppressFinalize(this); + } + + #endregion + + } +} diff --git a/src/StreamDeckLib/ActionUuidAttribute.cs b/src/StreamDeckLib/ActionUuidAttribute.cs new file mode 100644 index 0000000..a69a109 --- /dev/null +++ b/src/StreamDeckLib/ActionUuidAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace StreamDeckLib +{ + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited =false)] + public class ActionUuidAttribute : Attribute + { + + public ActionUuidAttribute(string uuid = "") + { + Uuid = uuid; + } + + public string Uuid { get; set; } + } +} diff --git a/src/StreamDeckLib/BaseStreamDeckAction.cs b/src/StreamDeckLib/BaseStreamDeckAction.cs index 9aa65e0..20b149f 100644 --- a/src/StreamDeckLib/BaseStreamDeckAction.cs +++ b/src/StreamDeckLib/BaseStreamDeckAction.cs @@ -1,38 +1,59 @@ -using StreamDeckLib.Messages; +using Microsoft.Extensions.Logging; +using StreamDeckLib.Messages; +using System.Linq; using System.Threading.Tasks; namespace StreamDeckLib { - public abstract class BaseStreamDeckAction + public abstract class BaseStreamDeckAction { - protected internal ConnectionManager Manager { get; set; } + /// + /// The with which this instance + /// of the is registered. + /// + /// The manager. + protected internal ConnectionManager Manager { get; set; } - public abstract string ActionUuid { get; } + /// + /// Gets the UUID which uniquely identifies the individual actions within a plugin. + /// + /// The UUID representing the action, which matches the value in the "manifest.json" file. + public string ActionUuid + { + get + { + return this.GetType().GetCustomAttributes(typeof(ActionUuidAttribute), true).FirstOrDefault() is ActionUuidAttribute attr && !string.IsNullOrWhiteSpace(attr.Uuid) + ? attr.Uuid + : string.Empty; + } + } - public virtual Task OnKeyDown(StreamDeckEventPayload args) => Task.CompletedTask; + public ILogger Logger { get; internal set; } - public virtual Task OnKeyUp(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnKeyDown(StreamDeckEventPayload args) => Task.CompletedTask; - public virtual Task OnWillAppear(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnKeyUp(StreamDeckEventPayload args) => Task.CompletedTask; - public virtual Task OnWillDisappear(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnWillAppear(StreamDeckEventPayload args) => Task.CompletedTask; - public virtual Task OnTitleParametersDidChange(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnWillDisappear(StreamDeckEventPayload args) => Task.CompletedTask; - public virtual Task OnDeviceDidConnect(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnTitleParametersDidChange(StreamDeckEventPayload args) => Task.CompletedTask; - public virtual Task OnDeviceDidDisconnect(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnDeviceDidConnect(StreamDeckEventPayload args) => Task.CompletedTask; - public virtual Task OnApplicationDidLaunch(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnDeviceDidDisconnect(StreamDeckEventPayload args) => Task.CompletedTask; - public virtual Task OnApplicationDidTerminate(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnApplicationDidLaunch(StreamDeckEventPayload args) => Task.CompletedTask; - public virtual Task OnDidReceiveSettings(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnApplicationDidTerminate(StreamDeckEventPayload args) => Task.CompletedTask; - public virtual Task OnDidReceiveGlobalSettings(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnDidReceiveSettings(StreamDeckEventPayload args) => Task.CompletedTask; - public virtual Task OnPropertyInspectorDidAppear(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnDidReceiveGlobalSettings(StreamDeckEventPayload args) => Task.CompletedTask; - public virtual Task OnPropertyInspectorDidDisappear(StreamDeckEventPayload args) => Task.CompletedTask; + public virtual Task OnPropertyInspectorDidDisappear(StreamDeckEventPayload args) => Task.CompletedTask; + + public virtual Task OnPropertyInspectorDidAppear(StreamDeckEventPayload args) => Task.CompletedTask; } } diff --git a/src/StreamDeckLib/BaseStreamDeckActionWithSettingsModel.cs b/src/StreamDeckLib/BaseStreamDeckActionWithSettingsModel.cs index bd26372..7a3db3a 100644 --- a/src/StreamDeckLib/BaseStreamDeckActionWithSettingsModel.cs +++ b/src/StreamDeckLib/BaseStreamDeckActionWithSettingsModel.cs @@ -1,41 +1,41 @@ -using StreamDeckLib.Messages; +using StreamDeckLib.Messages; using System; using System.Threading.Tasks; namespace StreamDeckLib { - public abstract class BaseStreamDeckActionWithSettingsModel : BaseStreamDeckAction - { - public T SettingsModel { get; } = Activator.CreateInstance(); - - public override Task OnDidReceiveSettings(StreamDeckEventPayload args) + public abstract class BaseStreamDeckActionWithSettingsModel : BaseStreamDeckAction { - SetModelProperties(args); - return Task.CompletedTask; - } + public T SettingsModel { get; } = Activator.CreateInstance(); - public override Task OnWillAppear(StreamDeckEventPayload args) - { - SetModelProperties(args); - return Task.CompletedTask; - } + public override Task OnDidReceiveSettings(StreamDeckEventPayload args) + { + SetModelProperties(args); + return Task.CompletedTask; + } - protected void SetModelProperties(StreamDeckEventPayload args) - { - var properties = typeof(T).GetProperties(); - foreach (var prop in properties) - { - if (args.payload != null && args.payload.settings != null && args.payload.settings.settingsModel != null) + public override Task OnWillAppear(StreamDeckEventPayload args) { - if (args.PayloadSettingsHasProperty(prop.Name)) - { - var value = args.GetPayloadSettingsValue(prop.Name); - var value2 = Convert.ChangeType(value, prop.PropertyType); - prop.SetValue(SettingsModel, value2); - } + SetModelProperties(args); + return Task.CompletedTask; + } + + protected void SetModelProperties(StreamDeckEventPayload args) + { + var properties = typeof(T).GetProperties(); + foreach (var prop in properties) + { + if (args.payload != null && args.payload.settings != null && args.payload.settings.settingsModel != null) + { + if (args.PayloadSettingsHasProperty(prop.Name)) + { + var value = args.GetPayloadSettingsValue(prop.Name); + var value2 = Convert.ChangeType(value, prop.PropertyType); + prop.SetValue(SettingsModel, value2); + } + } + } } - } - } - } + } } diff --git a/src/StreamDeckLib/BaseStreamDeckPlugin.cs b/src/StreamDeckLib/BaseStreamDeckPlugin.cs deleted file mode 100644 index afd4620..0000000 --- a/src/StreamDeckLib/BaseStreamDeckPlugin.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace StreamDeckLib -{ - public abstract class BaseStreamDeckPlugin - { - protected internal ConnectionManager Manager { get; set; } - //string is the action UUID, type is the class type of the action - private Dictionary _actions = new Dictionary(); - //string is the context, there will only ever be one action per context - private Dictionary _contextActions = new Dictionary(); - - public abstract void RegisterActionTypes(); - - public void RegisterActionType(string actionUuid, Type actionType) - { - _actions.Add(actionUuid, actionType); - } - - public BaseStreamDeckAction GetInstanceOfAction(string context, string actionUuid) - { - //see if context exists, if so, return the associated action - if (_contextActions.Any(x => x.Key.Equals(context))) - { - return _contextActions[context]; - } - else - { - //see if we have a recorded type for the action - if (_actions.Any(x => x.Key.Equals(actionUuid))) - { - var t = _actions[actionUuid]; - var action = Activator.CreateInstance(t) as BaseStreamDeckAction; - action.Manager = this.Manager; - _contextActions.Add(context, action); - return action; - } - - } - return null; - } - - } -} diff --git a/src/StreamDeckLib/ConnectionManager.cs b/src/StreamDeckLib/ConnectionManager.cs index 21f87d6..b428d63 100644 --- a/src/StreamDeckLib/ConnectionManager.cs +++ b/src/StreamDeckLib/ConnectionManager.cs @@ -1,9 +1,10 @@ -using McMaster.Extensions.CommandLineUtils; +using McMaster.Extensions.CommandLineUtils; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Newtonsoft.Json; using StreamDeckLib.Messages; using System; +using System.Diagnostics; using System.IO; using System.Net.WebSockets; using System.Threading; @@ -11,6 +12,7 @@ namespace StreamDeckLib { + /// /// This class manages the connection to the StreamDeck hardware /// @@ -20,28 +22,44 @@ public partial class ConnectionManager : IDisposable private string _Uuid; private string _RegisterEvent; private IStreamDeckProxy _Proxy; - private ConnectionManager() { } - public Messages.Info Info { get; private set; } + + private ConnectionManager() + { + this._ActionManager = new ActionManager(this, _Logger); + } + public Messages.Info Info { get; private set; } public static ConnectionManager Initialize(string[] commandLineArgs, - ILoggerFactory loggerFactory = null, IStreamDeckProxy streamDeckProxy = null) + ILoggerFactory loggerFactory = null, + IStreamDeckProxy streamDeckProxy = null) { - using (var app = new CommandLineApplication()) { app.HelpOption(); - var optionPort = app.Option("-port|--port ", "The port the Elgato StreamDeck software is listening on", CommandOptionType.SingleValue); - var optionPluginUUID = app.Option("-pluginUUID ", "The UUID that the Elgato StreamDeck software knows this plugin as.", CommandOptionType.SingleValue); - var optionRegisterEvent = app.Option("-registerEvent ", "The registration event", CommandOptionType.SingleValue); + var optionPort = app.Option("-port|--port ", + "The port the Elgato StreamDeck software is listening on", + CommandOptionType.SingleValue); + + var optionPluginUUID = app.Option("-pluginUUID ", + "The UUID that the Elgato StreamDeck software knows this plugin as.", + CommandOptionType.SingleValue); + + var optionRegisterEvent = app.Option("-registerEvent ", "The registration event", + CommandOptionType.SingleValue); + var optionInfo = app.Option("-info ", "Some information", CommandOptionType.SingleValue); + var optionBreak = app.Option("-break", "Attach the debugger", CommandOptionType.NoValue); + app.Parse(commandLineArgs); try { - return Initialize(optionPort.ParsedValue, optionPluginUUID.Values[0], optionRegisterEvent.Values[0], optionInfo.Values[0], loggerFactory, streamDeckProxy ?? new StreamDeckProxy()); + return Initialize(optionPort.ParsedValue, optionPluginUUID.Values[0], optionRegisterEvent.Values[0], + optionInfo.Values[0], loggerFactory, + streamDeckProxy ?? new StreamDeckProxy()); } catch { @@ -50,12 +68,16 @@ public static ConnectionManager Initialize(string[] commandLineArgs, } } - private static ConnectionManager Initialize(int port, string uuid, string registerEvent, string info, ILoggerFactory loggerFactory, IStreamDeckProxy streamDeckProxy) + private static ConnectionManager Initialize(int port, string uuid, + string registerEvent, string info, + ILoggerFactory loggerFactory, + IStreamDeckProxy streamDeckProxy, + ActionManager actionManager = null) { // TODO: Validate the info parameter var myInfo = JsonConvert.DeserializeObject(info); - _LoggerFactory = loggerFactory; + _LoggerFactory = loggerFactory ?? NullLoggerFactory.Instance; _Logger = loggerFactory?.CreateLogger("ConnectionManager") ?? NullLogger.Instance; var manager = new ConnectionManager() @@ -70,15 +92,9 @@ private static ConnectionManager Initialize(int port, string uuid, string regist return manager; } - public ConnectionManager SetPlugin(BaseStreamDeckPlugin plugin) - { - this._Plugin = plugin; - plugin.Manager = this; - return this; - } - public async Task StartAsync(CancellationToken token) { + TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; await Run(token); @@ -87,6 +103,14 @@ public async Task StartAsync(CancellationToken token) } + public async Task StartAsync() + { + + var source = new CancellationTokenSource(); + + return await this.StartAsync(source.Token); + } + private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) { throw new NotImplementedException(); @@ -97,11 +121,10 @@ private async Task Run(CancellationToken token) await _Proxy.ConnectAsync(new Uri($"ws://localhost:{_Port}"), token); await _Proxy.Register(_RegisterEvent, _Uuid); - _Plugin.RegisterActionTypes(); var keepRunning = true; - while (!token.IsCancellationRequested) + while (!token.IsCancellationRequested && keepRunning) { // Exit loop if the socket is closed or aborted switch (_Proxy.State) @@ -110,8 +133,10 @@ private async Task Run(CancellationToken token) case WebSocketState.Closed: case WebSocketState.Aborted: keepRunning = false; + break; } + if (!keepRunning) break; var jsonString = await _Proxy.GetMessageAsString(token); @@ -125,20 +150,31 @@ private async Task Run(CancellationToken token) if (msg == null) { _Logger.LogError($"Unknown message received: {jsonString}"); + + continue; + } + + if (string.IsNullOrWhiteSpace(msg.context) && string.IsNullOrWhiteSpace(msg.action)) + { + _Logger.LogInformation($"System event received: ${msg.Event}"); continue; } - var action = _Plugin.GetInstanceOfAction(msg.context, msg.action); + var action = GetInstanceOfAction(msg.context, msg.action); if (action == null) { - _Logger.LogError($"No action matching {msg.action} registered"); + _Logger.LogWarning($"The action requested (\"{msg.action}\") was not found as being registered with the plugin"); continue; } - if (!_ActionDictionary.ContainsKey(msg.Event)) + + if (!_EventDictionary.ContainsKey(msg.Event)) { _Logger.LogWarning($"Plugin does not handle the event '{msg.Event}'"); + continue; } - _ActionDictionary[msg.Event]?.Invoke(action, msg); + + _EventDictionary[msg.Event]?.Invoke(action, msg); + } catch (Exception ex) { @@ -148,6 +184,7 @@ private async Task Run(CancellationToken token) await Task.Delay(100); } + Dispose(); } @@ -171,6 +208,9 @@ public async Task SetTitleAsync(string context, string newTitle) public async Task SetImageAsync(string context, string imageLocation) { + Debug.WriteLine($"Getting Image from {new FileInfo(imageLocation).FullName} on disk"); + _Logger.LogDebug($"Getting Image from {new FileInfo(imageLocation).FullName} on disk"); + var imgString = Convert.ToBase64String(File.ReadAllBytes(imageLocation), Base64FormattingOptions.None); var args = new SetImageArgs @@ -184,7 +224,6 @@ public async Task SetImageAsync(string context, string imageLocation) }; await _Proxy.SendStreamDeckEvent(args); - } public async Task ShowAlertAsync(string context) @@ -193,6 +232,7 @@ public async Task ShowAlertAsync(string context) { context = context }; + await _Proxy.SendStreamDeckEvent(args); } @@ -202,6 +242,7 @@ public async Task ShowOkAsync(string context) { context = context }; + await _Proxy.SendStreamDeckEvent(args); } @@ -212,15 +253,7 @@ public async Task SetSettingsAsync(string context, dynamic value) context = context, payload = new { settingsModel = value } }; - await _Proxy.SendStreamDeckEvent(args); - } - public async Task GetSettingsAsync(string context) - { - var args = new GetSettingsArgs() - { - context = context - }; await _Proxy.SendStreamDeckEvent(args); } @@ -229,23 +262,14 @@ public async Task SetGlobalSettingsAsync(string context, dynamic value) var args = new SetGlobalSettingsArgs() { context = context, - payload = value + payload = new { settingsModel = value } }; - await _Proxy.SendStreamDeckEvent(args); - } - public async Task GetGobalSettingsAsync(string context) - { - var args = new GetGlobalSettingsArgs() - { - context = context - }; await _Proxy.SendStreamDeckEvent(args); } public async Task SetStateAsync(string context, int state) { - var args = new SetStateArgs { context = context, @@ -272,7 +296,6 @@ public async Task SwitchToProfileAsync(string context, string device, string pro }; await _Proxy.SendStreamDeckEvent(args); - } public async Task OpenUrlAsync(string context, string url) @@ -285,6 +308,21 @@ public async Task OpenUrlAsync(string context, string url) url = url } }; + + await _Proxy.SendStreamDeckEvent(args); + } + + + public async Task GetSettingsAsync(string context) + { + var args = new GetSettingsArgs() { context = context }; + await _Proxy.SendStreamDeckEvent(args); + } + + + public async Task GetGlobalSettingsAsync(string context) + { + var args = new GetGlobalSettingsArgs() { context = context }; await _Proxy.SendStreamDeckEvent(args); } @@ -293,7 +331,6 @@ public async Task OpenUrlAsync(string context, string url) #region IDisposable Support private bool disposedValue = false; // To detect redundant calls - private BaseStreamDeckPlugin _Plugin; private static ILoggerFactory _LoggerFactory; private static ILogger _Logger; @@ -318,6 +355,8 @@ public void Dispose() // TODO: uncomment the following line if the finalizer is overridden above. //GC.SuppressFinalize(this); } + #endregion } + } diff --git a/src/StreamDeckLib/ConnectionManager_Actions.cs b/src/StreamDeckLib/ConnectionManager_Actions.cs new file mode 100644 index 0000000..4bc4ec3 --- /dev/null +++ b/src/StreamDeckLib/ConnectionManager_Actions.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace StreamDeckLib +{ + partial class ConnectionManager + { + private ActionManager _ActionManager; + + //Cheer 100 svavablount 15/2/19 + public ConnectionManager RegisterActionType(string actionUuid, Type actionType) + { + this._ActionManager.RegisterActionType(actionUuid, actionType); + return this; + } + + public BaseStreamDeckAction GetInstanceOfAction(string context, string actionUuid) + { + return this._ActionManager.GetActionForContext(context, actionUuid); + } + + public ConnectionManager RegisterAllActions(Assembly assembly) + { + this._ActionManager.RegisterAllActions(assembly); + return this; + } + + } +} diff --git a/src/StreamDeckLib/ConnectionManager_Events.cs b/src/StreamDeckLib/ConnectionManager_Events.cs index 13c0403..c5baf98 100644 --- a/src/StreamDeckLib/ConnectionManager_Events.cs +++ b/src/StreamDeckLib/ConnectionManager_Events.cs @@ -1,4 +1,4 @@ -using StreamDeckLib.Messages; +using StreamDeckLib.Messages; using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -9,8 +9,7 @@ partial class ConnectionManager { // Cheer ramblinggeek 100 January 21, 2019 - - private static readonly Dictionary> _ActionDictionary + private static readonly Dictionary> _EventDictionary = new Dictionary>() { ["keyDown"] = (plugin, args) => plugin.OnKeyDown(args), @@ -22,11 +21,11 @@ private static readonly Dictionary plugin.OnDeviceDidDisconnect(args), ["applicationDidLaunch"] = (plugin, args) => plugin.OnApplicationDidLaunch(args), ["applicationDidTerminate"] = (plugin, args) => plugin.OnApplicationDidTerminate(args), - ["propertyInspectorDidAppear"] = (plugin, args) => plugin.OnPropertyInspectorDidAppear(args), - ["propertyInspectorDidDisappear"] = (plugin, args) => plugin.OnPropertyInspectorDidDisappear(args), ["didReceiveSettings"] = (plugin, args) => plugin.OnDidReceiveSettings(args), - ["didReceiveGlobalSettings"] = (plugin, args) => plugin.OnDidReceiveGlobalSettings(args) + ["didReceiveGlobalSettings"] = (plugin, args) => plugin.OnDidReceiveGlobalSettings(args), + ["propertyInspectorDidDisappear"] = (plugin, args) => plugin.OnPropertyInspectorDidDisappear(args), + ["propertyInspectorDidAppear"] = (plugin, args) => plugin.OnPropertyInspectorDidAppear(args) }; - } + } diff --git a/src/StreamDeckLib/Exceptions/ActionNotRegisteredException.cs b/src/StreamDeckLib/Exceptions/ActionNotRegisteredException.cs new file mode 100644 index 0000000..a7597d3 --- /dev/null +++ b/src/StreamDeckLib/Exceptions/ActionNotRegisteredException.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.Serialization; + +namespace StreamDeckLib +{ + [Serializable] + public class ActionNotRegisteredException : Exception + { + private static string GenerateErrorMessageForUUID(string uuid) => $"The action with the UUID of \"{uuid}\" was not registered with the ConnectionManager."; + + public string UUID { get; } + + public ActionNotRegisteredException() + { + } + + public ActionNotRegisteredException(string uuid) : base(GenerateErrorMessageForUUID(uuid)) + { + this.UUID = uuid; + } + + public ActionNotRegisteredException(string uuid, Exception innerException) : base(GenerateErrorMessageForUUID(uuid), innerException) + { + this.UUID = uuid; + } + + + protected ActionNotRegisteredException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + + + } + +} diff --git a/src/StreamDeckLib/Exceptions/DuplicateActionInstanceRegistrationException.cs b/src/StreamDeckLib/Exceptions/DuplicateActionInstanceRegistrationException.cs new file mode 100644 index 0000000..42b0a92 --- /dev/null +++ b/src/StreamDeckLib/Exceptions/DuplicateActionInstanceRegistrationException.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.Serialization; + +namespace StreamDeckLib +{ + [Serializable] + public class DuplicateActionInstanceRegistrationException : Exception + { + private static string GenerateErrorMessageForUUID(string key) => $"An action with a key value of \"{key}\" has already been registered."; + + public string Key { get; } + + public DuplicateActionInstanceRegistrationException(string key) : base(GenerateErrorMessageForUUID(key)) + { + this.Key = key; + } + + public DuplicateActionInstanceRegistrationException(string uuid, Exception innerException) : base(GenerateErrorMessageForUUID(uuid), innerException) + { + } + + protected DuplicateActionInstanceRegistrationException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + + +} diff --git a/src/StreamDeckLib/Exceptions/DuplicateActionRegistrationException.cs b/src/StreamDeckLib/Exceptions/DuplicateActionRegistrationException.cs new file mode 100644 index 0000000..a905789 --- /dev/null +++ b/src/StreamDeckLib/Exceptions/DuplicateActionRegistrationException.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.Serialization; + +namespace StreamDeckLib +{ + [Serializable] + public class DuplicateActionRegistrationException : Exception + { + private static string GenerateErrorMessageForUUID(string uuid) => $"An action with the UUID of \"{uuid}\" has already been registered with the ConnectionManager."; + + public string UUID { get; } + + public DuplicateActionRegistrationException(string uuid) : base(GenerateErrorMessageForUUID(uuid)) + { + this.UUID = uuid; + } + + public DuplicateActionRegistrationException(string uuid, Exception innerException) : base(GenerateErrorMessageForUUID(uuid), innerException) + { + } + + protected DuplicateActionRegistrationException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + +} diff --git a/src/StreamDeckLib/Exceptions/IncompleteActionDefinitionException.cs b/src/StreamDeckLib/Exceptions/IncompleteActionDefinitionException.cs new file mode 100644 index 0000000..5f0a18e --- /dev/null +++ b/src/StreamDeckLib/Exceptions/IncompleteActionDefinitionException.cs @@ -0,0 +1,23 @@ +using System; +using System.Runtime.Serialization; + +namespace StreamDeckLib +{ + [Serializable] + public class IncompleteActionDefinitionException : Exception + { + public IncompleteActionDefinitionException(string message) : base(message) + { + } + + public IncompleteActionDefinitionException(string message, Exception innerException) : base(message, innerException) + { + } + + protected IncompleteActionDefinitionException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + + } + +} diff --git a/src/StreamDeckLib/Exceptions/TypeDoesNotInheritFromBaseStreamDeckAction.cs b/src/StreamDeckLib/Exceptions/TypeDoesNotInheritFromBaseStreamDeckAction.cs new file mode 100644 index 0000000..7781f0b --- /dev/null +++ b/src/StreamDeckLib/Exceptions/TypeDoesNotInheritFromBaseStreamDeckAction.cs @@ -0,0 +1,41 @@ +using System; +using System.Reflection; +using System.Runtime.Serialization; + +namespace StreamDeckLib +{ + [Serializable] + public class TypeDoesNotInheritFromBaseStreamDeckAction : Exception + { + private string fullName; + private string assemblyName; + + public TypeDoesNotInheritFromBaseStreamDeckAction() + { + } + + public TypeDoesNotInheritFromBaseStreamDeckAction(string message) : base(message) + { + } + + + public TypeDoesNotInheritFromBaseStreamDeckAction(string simpleName, string fullName, string assemblyName) + : this($"The type \"{simpleName}\" (\"{fullName}\") from assembly \"{assemblyName}\" does not inherit from required base class \"{nameof(BaseStreamDeckAction)}\".") + { + + this.fullName = fullName; + + this.assemblyName = assemblyName; + + } + + + public TypeDoesNotInheritFromBaseStreamDeckAction(string message, Exception innerException) : base(message, innerException) + { + } + + protected TypeDoesNotInheritFromBaseStreamDeckAction(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/src/StreamDeckLib/Messages/BaseStreamDeckArgs.cs b/src/StreamDeckLib/Messages/BaseStreamDeckArgs.cs index d798e2e..0833ba8 100644 --- a/src/StreamDeckLib/Messages/BaseStreamDeckArgs.cs +++ b/src/StreamDeckLib/Messages/BaseStreamDeckArgs.cs @@ -1,15 +1,15 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; namespace StreamDeckLib.Messages { - public abstract class BaseStreamDeckArgs - { - [JsonProperty(PropertyName = "event")] - public abstract string Event - { - get; - } + public abstract class BaseStreamDeckArgs + { + [JsonProperty(PropertyName = "event")] + public abstract string Event + { + get; + } - public string context { get; set; } - } + public string context { get; set; } + } } diff --git a/src/StreamDeckLib/Messages/GetGlobalSettingsArgs.cs b/src/StreamDeckLib/Messages/GetGlobalSettingsArgs.cs index 4900742..0e4c617 100644 --- a/src/StreamDeckLib/Messages/GetGlobalSettingsArgs.cs +++ b/src/StreamDeckLib/Messages/GetGlobalSettingsArgs.cs @@ -1,7 +1,7 @@ -namespace StreamDeckLib.Messages +namespace StreamDeckLib.Messages { - public class GetGlobalSettingsArgs : BaseStreamDeckArgs - { - public override string Event => "getGlobalSettings"; - } + public class GetGlobalSettingsArgs : BaseStreamDeckArgs + { + public override string Event => "getGlobalSettings"; + } } diff --git a/src/StreamDeckLib/Messages/GetSettingsArgs.cs b/src/StreamDeckLib/Messages/GetSettingsArgs.cs index f54aacc..2d64395 100644 --- a/src/StreamDeckLib/Messages/GetSettingsArgs.cs +++ b/src/StreamDeckLib/Messages/GetSettingsArgs.cs @@ -1,7 +1,7 @@ -namespace StreamDeckLib.Messages +namespace StreamDeckLib.Messages { - public class GetSettingsArgs : BaseStreamDeckArgs - { - public override string Event => "getSettings"; - } + public class GetSettingsArgs : BaseStreamDeckArgs + { + public override string Event => "getSettings"; + } } diff --git a/src/StreamDeckLib/Messages/LogMessageArgs.cs b/src/StreamDeckLib/Messages/LogMessageArgs.cs new file mode 100644 index 0000000..633c349 --- /dev/null +++ b/src/StreamDeckLib/Messages/LogMessageArgs.cs @@ -0,0 +1,12 @@ +namespace StreamDeckLib.Messages +{ + public class LogMessageArgs : BaseStreamDeckArgs + { + public override string Event => "logMessage"; + public Payload payload { get; set; } + public class Payload + { + public string message { get; set; } + } + } +} diff --git a/src/StreamDeckLib/Messages/OpenUrlArgs.cs b/src/StreamDeckLib/Messages/OpenUrlArgs.cs index 9d334c9..383ebd8 100644 --- a/src/StreamDeckLib/Messages/OpenUrlArgs.cs +++ b/src/StreamDeckLib/Messages/OpenUrlArgs.cs @@ -1,12 +1,12 @@ namespace StreamDeckLib.Messages { - public class OpenUrlArgs : BaseStreamDeckArgs - { - public override string Event => "openUrl"; - public Payload payload { get; set; } - public class Payload - { - public string url { get; set; } - } - } + public class OpenUrlArgs : BaseStreamDeckArgs + { + public override string Event => "openUrl"; + public Payload payload { get; set; } + public class Payload + { + public string url { get; set; } + } + } } diff --git a/src/StreamDeckLib/Messages/SetGlobalSettingsArgs.cs b/src/StreamDeckLib/Messages/SetGlobalSettingsArgs.cs index a5ae66f..9ae2a8c 100644 --- a/src/StreamDeckLib/Messages/SetGlobalSettingsArgs.cs +++ b/src/StreamDeckLib/Messages/SetGlobalSettingsArgs.cs @@ -1,8 +1,8 @@ -namespace StreamDeckLib.Messages +namespace StreamDeckLib.Messages { - public class SetGlobalSettingsArgs : BaseStreamDeckArgs - { - public override string Event => "setGlobalSettings"; - public dynamic payload { get; set; } - } + public class SetGlobalSettingsArgs : BaseStreamDeckArgs + { + public override string Event => "setGlobalSettings"; + public dynamic payload { get; set; } + } } diff --git a/src/StreamDeckLib/Messages/SetStateArgs.cs b/src/StreamDeckLib/Messages/SetStateArgs.cs index 7d8a430..be46e28 100644 --- a/src/StreamDeckLib/Messages/SetStateArgs.cs +++ b/src/StreamDeckLib/Messages/SetStateArgs.cs @@ -1,4 +1,4 @@ -namespace StreamDeckLib.Messages +namespace StreamDeckLib.Messages { public class SetStateArgs : BaseStreamDeckArgs { @@ -6,7 +6,7 @@ public class SetStateArgs : BaseStreamDeckArgs public Payload payload { get; set; } public class Payload { - public int state{ get; set; } + public int state { get; set; } } } diff --git a/src/StreamDeckLib/Messages/ShowAlertArgs.cs b/src/StreamDeckLib/Messages/ShowAlertArgs.cs index 704b5fa..cdbd0ed 100644 --- a/src/StreamDeckLib/Messages/ShowAlertArgs.cs +++ b/src/StreamDeckLib/Messages/ShowAlertArgs.cs @@ -1,7 +1,7 @@ -namespace StreamDeckLib.Messages +namespace StreamDeckLib.Messages { - public class ShowAlertArgs : BaseStreamDeckArgs - { - public override string Event => "showAlert"; - } + public class ShowAlertArgs : BaseStreamDeckArgs + { + public override string Event => "showAlert"; + } } diff --git a/src/StreamDeckLib/Messages/ShowOkArgs.cs b/src/StreamDeckLib/Messages/ShowOkArgs.cs index a357fc9..c6669db 100644 --- a/src/StreamDeckLib/Messages/ShowOkArgs.cs +++ b/src/StreamDeckLib/Messages/ShowOkArgs.cs @@ -1,7 +1,7 @@ -namespace StreamDeckLib.Messages +namespace StreamDeckLib.Messages { - public class ShowOkArgs : BaseStreamDeckArgs - { - public override string Event => "showOk"; - } + public class ShowOkArgs : BaseStreamDeckArgs + { + public override string Event => "showOk"; + } } diff --git a/src/StreamDeckLib/Messages/StreamDeckEventPayloadExtensions.cs b/src/StreamDeckLib/Messages/StreamDeckEventPayloadExtensions.cs index e4542f9..528aa7b 100644 --- a/src/StreamDeckLib/Messages/StreamDeckEventPayloadExtensions.cs +++ b/src/StreamDeckLib/Messages/StreamDeckEventPayloadExtensions.cs @@ -1,33 +1,33 @@ -using System; +using System; using System.ComponentModel; namespace StreamDeckLib.Messages { - public static class StreamDeckEventPayloadExtensions - { - public static bool PayloadSettingsHasProperty(this StreamDeckEventPayload obj, string propertyName) + public static class StreamDeckEventPayloadExtensions { - return obj.payload.settings.settingsModel[propertyName] != null; - } + public static bool PayloadSettingsHasProperty(this StreamDeckEventPayload obj, string propertyName) + { + return obj.payload.settings.settingsModel[propertyName] != null; + } - public static T GetPayloadSettingsValue(this StreamDeckEventPayload obj, string propertyName) where T : IConvertible - { - if (obj.PayloadSettingsHasProperty(propertyName)) - { - return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(obj.payload.settings.settingsModel[propertyName].Value.ToString()); - } - return default(T); - } + public static T GetPayloadSettingsValue(this StreamDeckEventPayload obj, string propertyName) where T : IConvertible + { + if (obj.PayloadSettingsHasProperty(propertyName)) + { + return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(obj.payload.settings.settingsModel[propertyName].Value.ToString()); + } + return default(T); + } - public static object GetPayloadSettingsValue(this StreamDeckEventPayload obj, string propertyName) - { - if (obj.PayloadSettingsHasProperty(propertyName)) - { - return obj.payload.settings.settingsModel[propertyName].Value; - } - return null; - } + public static object GetPayloadSettingsValue(this StreamDeckEventPayload obj, string propertyName) + { + if (obj.PayloadSettingsHasProperty(propertyName)) + { + return obj.payload.settings.settingsModel[propertyName].Value; + } + return null; + } - } + } } diff --git a/src/StreamDeckLib/Messages/StreamDeckInfo.cs b/src/StreamDeckLib/Messages/StreamDeckInfo.cs index edc2d6d..e738fec 100644 --- a/src/StreamDeckLib/Messages/StreamDeckInfo.cs +++ b/src/StreamDeckLib/Messages/StreamDeckInfo.cs @@ -1,29 +1,29 @@ -namespace StreamDeckLib.Messages +namespace StreamDeckLib.Messages { - public class Info - { - public Application application { get; set; } - public Device[] devices { get; set; } - public int devicePixelRatio { get; set; } - - public class Application + public class Info { - public string language { get; set; } - public string platform { get; set; } - public string version { get; set; } - } + public Application application { get; set; } + public Device[] devices { get; set; } + public int devicePixelRatio { get; set; } - public class Device - { - public string id { get; set; } - public Size size { get; set; } - public int type { get; set; } - } + public class Application + { + public string language { get; set; } + public string platform { get; set; } + public string version { get; set; } + } - public class PluginRegistration - { - public string @event { get; set; } - public string uuid { get; set; } + public class Device + { + public string id { get; set; } + public Size size { get; set; } + public int type { get; set; } + } + + public class PluginRegistration + { + public string @event { get; set; } + public string uuid { get; set; } + } } - } } diff --git a/src/StreamDeckLib/StreamDeckLib.csproj b/src/StreamDeckLib/StreamDeckLib.csproj index 1a51b03..29d7cb4 100644 --- a/src/StreamDeckLib/StreamDeckLib.csproj +++ b/src/StreamDeckLib/StreamDeckLib.csproj @@ -16,4 +16,7 @@ + + + diff --git a/src/StreamDeckLib/StreamDeckProxy.cs b/src/StreamDeckLib/StreamDeckProxy.cs index a1e3e43..d270259 100644 --- a/src/StreamDeckLib/StreamDeckProxy.cs +++ b/src/StreamDeckLib/StreamDeckProxy.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using StreamDeckLib.Messages; using System; using System.Collections.Generic; diff --git a/src/StreamDeckToolkit.sln b/src/StreamDeckToolkit.sln index 7e2c7d2..1b0abd7 100644 --- a/src/StreamDeckToolkit.sln +++ b/src/StreamDeckToolkit.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.168 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28606.126 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreamDeckLib", "StreamDeckLib\StreamDeckLib.csproj", "{19F24D43-79DB-47B6-AEDA-BAEA3B2F1962}" EndProject @@ -14,6 +14,22 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreamDeckLib.Test", "StreamDeckLib.Test\StreamDeckLib.Test.csproj", "{CAD3C79B-E603-4356-B5BD-5B2E57DFD8BE}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripts", "Scripts", "{A337DDA4-B15C-43B9-AB51-04267D151BB0}" + ProjectSection(SolutionItems) = preProject + ..\scripts\install.ps1 = ..\scripts\install.ps1 + ..\scripts\install.sh = ..\scripts\install.sh + ..\scripts\uninstall.ps1 = ..\scripts\uninstall.ps1 + ..\scripts\uninstall.sh = ..\scripts\uninstall.sh + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Registration", "Registration", "{403D021A-9770-41ED-8554-34FEE375BADA}" + ProjectSection(SolutionItems) = preProject + ..\scripts\registration\RegisterPluginAndStartStreamDeck.ps1 = ..\scripts\registration\RegisterPluginAndStartStreamDeck.ps1 + ..\scripts\registration\RegisterPluginAndStartStreamDeck.sh = ..\scripts\registration\RegisterPluginAndStartStreamDeck.sh + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamDeckLib.Config", "StreamDeckLib.Config\StreamDeckLib.Config.csproj", "{32D1D35F-58ED-4BB2-B1CE-473C89757282}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -32,10 +48,17 @@ Global {CAD3C79B-E603-4356-B5BD-5B2E57DFD8BE}.Debug|Any CPU.Build.0 = Debug|Any CPU {CAD3C79B-E603-4356-B5BD-5B2E57DFD8BE}.Release|Any CPU.ActiveCfg = Release|Any CPU {CAD3C79B-E603-4356-B5BD-5B2E57DFD8BE}.Release|Any CPU.Build.0 = Release|Any CPU + {32D1D35F-58ED-4BB2-B1CE-473C89757282}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {32D1D35F-58ED-4BB2-B1CE-473C89757282}.Debug|Any CPU.Build.0 = Debug|Any CPU + {32D1D35F-58ED-4BB2-B1CE-473C89757282}.Release|Any CPU.ActiveCfg = Release|Any CPU + {32D1D35F-58ED-4BB2-B1CE-473C89757282}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {403D021A-9770-41ED-8554-34FEE375BADA} = {A337DDA4-B15C-43B9-AB51-04267D151BB0} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C5036C4A-EAB6-4A37-9D02-1E6D5E77D257} EndGlobalSection