├── .github └── FUNDING.yml ├── .gitignore ├── Installer ├── Images │ ├── LargeTile.scale-100.png │ ├── LargeTile.scale-125.png │ ├── LargeTile.scale-150.png │ ├── LargeTile.scale-200.png │ ├── LargeTile.scale-400.png │ ├── SmallTile.scale-100.png │ ├── SmallTile.scale-125.png │ ├── SmallTile.scale-150.png │ ├── SmallTile.scale-200.png │ ├── SmallTile.scale-400.png │ ├── SplashScreen.scale-100.png │ ├── SplashScreen.scale-125.png │ ├── SplashScreen.scale-150.png │ ├── SplashScreen.scale-200.png │ ├── SplashScreen.scale-400.png │ ├── Square150x150Logo.scale-100.png │ ├── Square150x150Logo.scale-125.png │ ├── Square150x150Logo.scale-150.png │ ├── Square150x150Logo.scale-200.png │ ├── Square150x150Logo.scale-400.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-16.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-24.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-256.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-32.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-48.png │ ├── Square44x44Logo.altform-unplated_targetsize-16.png │ ├── Square44x44Logo.altform-unplated_targetsize-256.png │ ├── Square44x44Logo.altform-unplated_targetsize-32.png │ ├── Square44x44Logo.altform-unplated_targetsize-48.png │ ├── Square44x44Logo.scale-100.png │ ├── Square44x44Logo.scale-125.png │ ├── Square44x44Logo.scale-150.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.scale-400.png │ ├── Square44x44Logo.targetsize-16.png │ ├── Square44x44Logo.targetsize-24.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── Square44x44Logo.targetsize-256.png │ ├── Square44x44Logo.targetsize-32.png │ ├── Square44x44Logo.targetsize-48.png │ ├── StoreLogo.scale-100.png │ ├── StoreLogo.scale-125.png │ ├── StoreLogo.scale-150.png │ ├── StoreLogo.scale-200.png │ ├── StoreLogo.scale-400.png │ ├── Wide310x150Logo.scale-100.png │ ├── Wide310x150Logo.scale-125.png │ ├── Wide310x150Logo.scale-150.png │ ├── Wide310x150Logo.scale-200.png │ └── Wide310x150Logo.scale-400.png ├── Installer.wapproj └── Package.appxmanifest ├── LICENSE ├── PRIVACY.md ├── README.md ├── Snatch.sln └── Snatch ├── App.config ├── App.xaml ├── App.xaml.cs ├── Controls ├── EmptyListView.xaml ├── EmptyListView.xaml.cs ├── Header.xaml ├── Header.xaml.cs ├── Onboarding.xaml ├── Onboarding.xaml.cs ├── ShortcutList.xaml ├── ShortcutList.xaml.cs ├── SupportSection.xaml └── SupportSection.xaml.cs ├── Extensions ├── CustomCommand.cs ├── DbClient.cs ├── DelegateCommand.cs ├── DragBehavior.cs ├── HyperlinkExtension.cs ├── NativeApi.cs ├── ProcessWatcher.cs ├── SettingsBinding.cs └── Utils.cs ├── Models └── Entry.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs ├── Settings.settings └── launchSettings.json ├── Resources ├── TrayResources.xaml ├── app-icon.ico ├── kasper-64.png ├── kasper.jpg ├── kiwi-bird-duotone.xaml └── tray-icon.ico ├── Snatch.csproj ├── Snatch.db ├── ViewModels ├── MainViewModel.cs ├── OnboardingViewModel.cs └── TrayViewModel.cs ├── Windows ├── MainWindow.xaml └── MainWindow.xaml.cs └── packages.config /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: https://buymeacoff.ee/idered 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.vspscc 94 | *.vssscc 95 | .builds 96 | *.pidb 97 | *.svclog 98 | *.scc 99 | 100 | # Chutzpah Test files 101 | _Chutzpah* 102 | 103 | # Visual C++ cache files 104 | ipch/ 105 | *.aps 106 | *.ncb 107 | *.opendb 108 | *.opensdf 109 | *.sdf 110 | *.cachefile 111 | *.VC.db 112 | *.VC.VC.opendb 113 | 114 | # Visual Studio profiler 115 | *.psess 116 | *.vsp 117 | *.vspx 118 | *.sap 119 | 120 | # Visual Studio Trace Files 121 | *.e2e 122 | 123 | # TFS 2012 Local Workspace 124 | $tf/ 125 | 126 | # Guidance Automation Toolkit 127 | *.gpState 128 | 129 | # ReSharper is a .NET coding add-in 130 | _ReSharper*/ 131 | *.[Rr]e[Ss]harper 132 | *.DotSettings.user 133 | 134 | # TeamCity is a build add-in 135 | _TeamCity* 136 | 137 | # DotCover is a Code Coverage Tool 138 | *.dotCover 139 | 140 | # AxoCover is a Code Coverage Tool 141 | .axoCover/* 142 | !.axoCover/settings.json 143 | 144 | # Coverlet is a free, cross platform Code Coverage Tool 145 | coverage*.json 146 | coverage*.xml 147 | coverage*.info 148 | 149 | # Visual Studio code coverage results 150 | *.coverage 151 | *.coveragexml 152 | 153 | # NCrunch 154 | _NCrunch_* 155 | .*crunch*.local.xml 156 | nCrunchTemp_* 157 | 158 | # MightyMoose 159 | *.mm.* 160 | AutoTest.Net/ 161 | 162 | # Web workbench (sass) 163 | .sass-cache/ 164 | 165 | # Installshield output folder 166 | [Ee]xpress/ 167 | 168 | # DocProject is a documentation generator add-in 169 | DocProject/buildhelp/ 170 | DocProject/Help/*.HxT 171 | DocProject/Help/*.HxC 172 | DocProject/Help/*.hhc 173 | DocProject/Help/*.hhk 174 | DocProject/Help/*.hhp 175 | DocProject/Help/Html2 176 | DocProject/Help/html 177 | 178 | # Click-Once directory 179 | publish/ 180 | 181 | # Publish Web Output 182 | *.[Pp]ublish.xml 183 | *.azurePubxml 184 | # Note: Comment the next line if you want to checkin your web deploy settings, 185 | # but database connection strings (with potential passwords) will be unencrypted 186 | *.pubxml 187 | *.publishproj 188 | 189 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 190 | # checkin your Azure Web App publish settings, but sensitive information contained 191 | # in these scripts will be unencrypted 192 | PublishScripts/ 193 | 194 | # NuGet Packages 195 | *.nupkg 196 | # NuGet Symbol Packages 197 | *.snupkg 198 | # The packages folder can be ignored because of Package Restore 199 | **/[Pp]ackages/* 200 | # except build/, which is used as an MSBuild target. 201 | !**/[Pp]ackages/build/ 202 | # Uncomment if necessary however generally it will be regenerated when needed 203 | #!**/[Pp]ackages/repositories.config 204 | # NuGet v3's project.json files produces more ignorable files 205 | *.nuget.props 206 | *.nuget.targets 207 | 208 | # Microsoft Azure Build Output 209 | csx/ 210 | *.build.csdef 211 | 212 | # Microsoft Azure Emulator 213 | ecf/ 214 | rcf/ 215 | 216 | # Windows Store app package directories and files 217 | AppPackages/ 218 | BundleArtifacts/ 219 | Package.StoreAssociation.xml 220 | _pkginfo.txt 221 | *.appx 222 | *.appxbundle 223 | *.appxupload 224 | 225 | # Visual Studio cache files 226 | # files ending in .cache can be ignored 227 | *.[Cc]ache 228 | # but keep track of directories ending in .cache 229 | !?*.[Cc]ache/ 230 | 231 | # Others 232 | ClientBin/ 233 | ~$* 234 | *~ 235 | *.dbmdl 236 | *.dbproj.schemaview 237 | *.jfm 238 | *.pfx 239 | *.publishsettings 240 | orleans.codegen.cs 241 | 242 | # Including strong name files can present a security risk 243 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 244 | #*.snk 245 | 246 | # Since there are multiple workflows, uncomment next line to ignore bower_components 247 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 248 | #bower_components/ 249 | 250 | # RIA/Silverlight projects 251 | Generated_Code/ 252 | 253 | # Backup & report files from converting an old project file 254 | # to a newer Visual Studio version. Backup files are not needed, 255 | # because we have git ;-) 256 | _UpgradeReport_Files/ 257 | Backup*/ 258 | UpgradeLog*.XML 259 | UpgradeLog*.htm 260 | ServiceFabricBackup/ 261 | *.rptproj.bak 262 | 263 | # SQL Server files 264 | *.mdf 265 | *.ldf 266 | *.ndf 267 | 268 | # Business Intelligence projects 269 | *.rdl.data 270 | *.bim.layout 271 | *.bim_*.settings 272 | *.rptproj.rsuser 273 | *- [Bb]ackup.rdl 274 | *- [Bb]ackup ([0-9]).rdl 275 | *- [Bb]ackup ([0-9][0-9]).rdl 276 | 277 | # Microsoft Fakes 278 | FakesAssemblies/ 279 | 280 | # GhostDoc plugin setting file 281 | *.GhostDoc.xml 282 | 283 | # Node.js Tools for Visual Studio 284 | .ntvs_analysis.dat 285 | node_modules/ 286 | 287 | # Visual Studio 6 build log 288 | *.plg 289 | 290 | # Visual Studio 6 workspace options file 291 | *.opt 292 | 293 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 294 | *.vbw 295 | 296 | # Visual Studio LightSwitch build output 297 | **/*.HTMLClient/GeneratedArtifacts 298 | **/*.DesktopClient/GeneratedArtifacts 299 | **/*.DesktopClient/ModelManifest.xml 300 | **/*.Server/GeneratedArtifacts 301 | **/*.Server/ModelManifest.xml 302 | _Pvt_Extensions 303 | 304 | # Paket dependency manager 305 | .paket/paket.exe 306 | paket-files/ 307 | 308 | # FAKE - F# Make 309 | .fake/ 310 | 311 | # CodeRush personal settings 312 | .cr/personal 313 | 314 | # Python Tools for Visual Studio (PTVS) 315 | __pycache__/ 316 | *.pyc 317 | 318 | # Cake - Uncomment if you are using it 319 | # tools/** 320 | # !tools/packages.config 321 | 322 | # Tabs Studio 323 | *.tss 324 | 325 | # Telerik's JustMock configuration file 326 | *.jmconfig 327 | 328 | # BizTalk build output 329 | *.btp.cs 330 | *.btm.cs 331 | *.odx.cs 332 | *.xsd.cs 333 | 334 | # OpenCover UI analysis results 335 | OpenCover/ 336 | 337 | # Azure Stream Analytics local run output 338 | ASALocalRun/ 339 | 340 | # MSBuild Binary and Structured Log 341 | *.binlog 342 | 343 | # NVidia Nsight GPU debugger configuration file 344 | *.nvuser 345 | 346 | # MFractors (Xamarin productivity tool) working folder 347 | .mfractor/ 348 | 349 | # Local History for Visual Studio 350 | .localhistory/ 351 | 352 | # BeatPulse healthcheck temp database 353 | healthchecksdb 354 | 355 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 356 | MigrationBackup/ 357 | 358 | # Ionide (cross platform F# VS Code tools) working folder 359 | .ionide/ 360 | 361 | # Fody - auto-generated XML schema 362 | FodyWeavers.xsd 363 | -------------------------------------------------------------------------------- /Installer/Images/LargeTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/LargeTile.scale-100.png -------------------------------------------------------------------------------- /Installer/Images/LargeTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/LargeTile.scale-125.png -------------------------------------------------------------------------------- /Installer/Images/LargeTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/LargeTile.scale-150.png -------------------------------------------------------------------------------- /Installer/Images/LargeTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/LargeTile.scale-200.png -------------------------------------------------------------------------------- /Installer/Images/LargeTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/LargeTile.scale-400.png -------------------------------------------------------------------------------- /Installer/Images/SmallTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/SmallTile.scale-100.png -------------------------------------------------------------------------------- /Installer/Images/SmallTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/SmallTile.scale-125.png -------------------------------------------------------------------------------- /Installer/Images/SmallTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/SmallTile.scale-150.png -------------------------------------------------------------------------------- /Installer/Images/SmallTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/SmallTile.scale-200.png -------------------------------------------------------------------------------- /Installer/Images/SmallTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/SmallTile.scale-400.png -------------------------------------------------------------------------------- /Installer/Images/SplashScreen.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/SplashScreen.scale-100.png -------------------------------------------------------------------------------- /Installer/Images/SplashScreen.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/SplashScreen.scale-125.png -------------------------------------------------------------------------------- /Installer/Images/SplashScreen.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/SplashScreen.scale-150.png -------------------------------------------------------------------------------- /Installer/Images/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /Installer/Images/SplashScreen.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/SplashScreen.scale-400.png -------------------------------------------------------------------------------- /Installer/Images/Square150x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square150x150Logo.scale-100.png -------------------------------------------------------------------------------- /Installer/Images/Square150x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square150x150Logo.scale-125.png -------------------------------------------------------------------------------- /Installer/Images/Square150x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square150x150Logo.scale-150.png -------------------------------------------------------------------------------- /Installer/Images/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /Installer/Images/Square150x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square150x150Logo.scale-400.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.altform-lightunplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.altform-lightunplated_targetsize-16.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.altform-lightunplated_targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.altform-lightunplated_targetsize-24.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.altform-lightunplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.altform-lightunplated_targetsize-256.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.altform-lightunplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.altform-lightunplated_targetsize-32.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.altform-lightunplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.altform-lightunplated_targetsize-48.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.altform-unplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.altform-unplated_targetsize-16.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.altform-unplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.altform-unplated_targetsize-256.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.altform-unplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.altform-unplated_targetsize-32.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.altform-unplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.altform-unplated_targetsize-48.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.scale-100.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.scale-125.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.scale-150.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.scale-400.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.targetsize-16.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.targetsize-24.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.targetsize-256.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.targetsize-32.png -------------------------------------------------------------------------------- /Installer/Images/Square44x44Logo.targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Square44x44Logo.targetsize-48.png -------------------------------------------------------------------------------- /Installer/Images/StoreLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/StoreLogo.scale-100.png -------------------------------------------------------------------------------- /Installer/Images/StoreLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/StoreLogo.scale-125.png -------------------------------------------------------------------------------- /Installer/Images/StoreLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/StoreLogo.scale-150.png -------------------------------------------------------------------------------- /Installer/Images/StoreLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/StoreLogo.scale-200.png -------------------------------------------------------------------------------- /Installer/Images/StoreLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/StoreLogo.scale-400.png -------------------------------------------------------------------------------- /Installer/Images/Wide310x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Wide310x150Logo.scale-100.png -------------------------------------------------------------------------------- /Installer/Images/Wide310x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Wide310x150Logo.scale-125.png -------------------------------------------------------------------------------- /Installer/Images/Wide310x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Wide310x150Logo.scale-150.png -------------------------------------------------------------------------------- /Installer/Images/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /Installer/Images/Wide310x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Installer/Images/Wide310x150Logo.scale-400.png -------------------------------------------------------------------------------- /Installer/Installer.wapproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15.0 5 | 6 | 7 | 8 | Debug 9 | x86 10 | 11 | 12 | Release 13 | x86 14 | 15 | 16 | Debug 17 | x64 18 | 19 | 20 | Release 21 | x64 22 | 23 | 24 | Debug 25 | ARM 26 | 27 | 28 | Release 29 | ARM 30 | 31 | 32 | Debug 33 | ARM64 34 | 35 | 36 | Release 37 | ARM64 38 | 39 | 40 | Debug 41 | AnyCPU 42 | 43 | 44 | Release 45 | AnyCPU 46 | 47 | 48 | 49 | $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\ 50 | 51 | 52 | 53 | 7944eb10-b04e-44ca-a86d-6795ae222a9c 54 | 10.0.19041.0 55 | 10.0.17763.0 56 | en-US 57 | True 58 | ..\Snatch\Snatch.csproj 59 | 0240416728BAEBDB8BEEA24248A44151BEFEF91E 60 | False 61 | SHA256 62 | True 63 | True 64 | x86|x64 65 | 0 66 | 67 | 68 | Always 69 | 70 | 71 | Always 72 | 73 | 74 | Always 75 | 76 | 77 | Always 78 | 79 | 80 | Always 81 | 82 | 83 | Always 84 | 85 | 86 | Always 87 | 88 | 89 | Always 90 | 91 | 92 | Always 93 | 94 | 95 | Always 96 | 97 | 98 | 99 | Designer 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /Installer/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 9 | 10 | 14 | 15 | 16 | Snatch - Clipboard manager 17 | Kasper Mikiewicz 18 | Images\StoreLogo.png 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Kasper Mikiewicz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PRIVACY.md: -------------------------------------------------------------------------------- 1 | # Privacy 2 | 3 | Snatch will never copy, sell, track, upload or observe your data in any way. You always retain complete ownership of your data and in no way will this application ever do anything with your data other than to copy it to and from your personal clipboard. 4 | 5 | Data is stored in `X:\Users\USERNAME\AppData\Local\Snatch` directory. 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Snatch - Clipboard manager for Windows 2 | 3 |

4 | mit license 5 | platform windows 6 | 7 | twitter 8 | 9 |

10 | 11 |

12 | demo 13 |

14 | 15 | --- 16 | 17 | You can download Snatch from [Microsoft Store](https://www.microsoft.com/store/apps/9P53HFV0H21X). I hope you will enjoy it! 18 | 19 | Btw you can follow me on Twitter for updates or code tips 20 | 21 | 22 | twitter 23 | 24 | -------------------------------------------------------------------------------- /Snatch.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30503.244 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Snatch", "Snatch\Snatch.csproj", "{2F943BD5-49D7-40C5-9486-57A7F0E7AB32}" 7 | EndProject 8 | Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "Installer", "Installer\Installer.wapproj", "{7944EB10-B04E-44CA-A86D-6795AE222A9C}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {2F943BD5-49D7-40C5-9486-57A7F0E7AB32}.Debug|x64.ActiveCfg = Debug|x64 19 | {2F943BD5-49D7-40C5-9486-57A7F0E7AB32}.Debug|x64.Build.0 = Debug|x64 20 | {2F943BD5-49D7-40C5-9486-57A7F0E7AB32}.Debug|x86.ActiveCfg = Debug|x86 21 | {2F943BD5-49D7-40C5-9486-57A7F0E7AB32}.Debug|x86.Build.0 = Debug|x86 22 | {2F943BD5-49D7-40C5-9486-57A7F0E7AB32}.Release|x64.ActiveCfg = Release|x64 23 | {2F943BD5-49D7-40C5-9486-57A7F0E7AB32}.Release|x64.Build.0 = Release|x64 24 | {2F943BD5-49D7-40C5-9486-57A7F0E7AB32}.Release|x86.ActiveCfg = Release|x86 25 | {2F943BD5-49D7-40C5-9486-57A7F0E7AB32}.Release|x86.Build.0 = Release|x86 26 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Debug|x64.ActiveCfg = Debug|x64 27 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Debug|x64.Build.0 = Debug|x64 28 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Debug|x64.Deploy.0 = Debug|x64 29 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Debug|x86.ActiveCfg = Debug|x86 30 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Debug|x86.Build.0 = Debug|x86 31 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Debug|x86.Deploy.0 = Debug|x86 32 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Release|x64.ActiveCfg = Release|x64 33 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Release|x64.Build.0 = Release|x64 34 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Release|x64.Deploy.0 = Release|x64 35 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Release|x86.ActiveCfg = Release|x86 36 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Release|x86.Build.0 = Release|x86 37 | {7944EB10-B04E-44CA-A86D-6795AE222A9C}.Release|x86.Deploy.0 = Release|x86 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | GlobalSection(ExtensibilityGlobals) = postSolution 43 | SolutionGuid = {C5C589BD-6286-42EC-99D1-1B59DEBAC234} 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /Snatch/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Snatch/App.xaml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 132 | 133 | 134 | 135 | 139 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 168 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /Snatch/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using Hardcodet.Wpf.TaskbarNotification; 3 | 4 | namespace Snatch 5 | { 6 | public partial class App : Application 7 | { 8 | private TaskbarIcon trayIcon; 9 | 10 | private App() 11 | { 12 | Deactivated += Application_Deactivated; 13 | } 14 | 15 | protected override void OnStartup(StartupEventArgs e) 16 | { 17 | base.OnStartup(e); 18 | 19 | trayIcon = (TaskbarIcon)FindResource("TrayIcon"); 20 | } 21 | 22 | protected override void OnExit(ExitEventArgs e) 23 | { 24 | trayIcon.Dispose(); 25 | base.OnExit(e); 26 | } 27 | 28 | private void Application_Deactivated(object sender, System.EventArgs e) 29 | { 30 | Application.Current.MainWindow.Visibility = Visibility.Hidden; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Snatch/Controls/EmptyListView.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 18 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 33 | 34 | 35 | 36 | 37 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 57 | It's empty here, 58 | 59 | 60 | 66 | copy something to get started. 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /Snatch/Controls/EmptyListView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace Snatch.Controls 4 | { 5 | public partial class EmptyListView : UserControl 6 | { 7 | public EmptyListView() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Snatch/Controls/Header.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 68 | Snatch 69 | 70 | 71 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Snatch/Controls/Header.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Snatch.Controls 17 | { 18 | public partial class Header : UserControl 19 | { 20 | public Header() 21 | { 22 | InitializeComponent(); 23 | Application.Current.MainWindow.Activated += HandleWindowActivated; 24 | } 25 | 26 | private void HandleWindowActivated(object sender, EventArgs e) 27 | { 28 | QueryInput.Focus(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Snatch/Controls/Onboarding.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 23 | 24 | 33 | 34 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | Snatch Quickstart 56 | 57 | 61 | To summon Snatch, press the following shortcut: 62 | 63 | 67 | 68 | Ctrl 69 | 70 | 78 | 79 | 80 | 81 | Shift 82 | 83 | 91 | 92 | 93 | 94 | V 95 | 96 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 116 | Good, remember that shortcut 117 | 118 | 123 | You can use it anywhere to show or hide Snatch. Press it again to hide this tutorial. 124 | 125 | 129 | 130 | Ctrl 131 | 132 | 135 | 136 | 137 | 138 | Shift 139 | 140 | 143 | 144 | 145 | 146 | V 147 | 148 | 151 | 152 | 153 | 154 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /Snatch/Controls/Onboarding.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Windows.Controls; 3 | using System.Windows.Input; 4 | 5 | namespace Snatch.Controls 6 | { 7 | public partial class Onboarding : UserControl 8 | { 9 | public Onboarding() 10 | { 11 | InitializeComponent(); 12 | } 13 | 14 | private void Button_Click(object sender, System.Windows.RoutedEventArgs e) 15 | { 16 | Snatch.Properties.Settings.Default.OnboardingStep = 0; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Snatch/Controls/ShortcutList.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 39 | 40 | 41 | 42 | 50 | 51 | 52 | 56 | Essential Keyboard Shortcuts 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 71 | Clear 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Ctrl 82 | 83 | 84 | 88 | 89 | Shift 90 | 91 | 92 | 96 | 97 | L 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 115 | Pin/Unpin 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | Ctrl 125 | 126 | 127 | 131 | 132 | P 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 149 | Quit 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | Ctrl 159 | 160 | 161 | 165 | 166 | Q 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 183 | Pin/Unpin all 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | Ctrl 194 | 195 | 196 | 200 | 201 | Shift 202 | 203 | 204 | 208 | 209 | P 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 226 | Remove entry 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | Ctrl 236 | 237 | 238 | 242 | 243 | Del 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 260 | Toggle help 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | Ctrl 270 | 271 | 272 | 276 | 277 | / 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 294 | Toggle Snatch 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | Ctrl 305 | 306 | 307 | 311 | 312 | Shift 313 | 314 | 315 | 319 | 320 | V 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | -------------------------------------------------------------------------------- /Snatch/Controls/ShortcutList.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Snatch.Controls 17 | { 18 | /// 19 | /// Interaction logic for ShortcutList.xaml 20 | /// 21 | public partial class ShortcutList : UserControl 22 | { 23 | public ShortcutList() 24 | { 25 | InitializeComponent(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Snatch/Controls/SupportSection.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 19 | 20 | 28 | 29 | 30 | 31 | 37 | 42 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 58 | Hi there, 59 | 60 | 65 | I hope that you find Snatch useful. If you would like to support my work, you can buy me a coffee or share a tweet. Thanks! 66 | 67 | 68 | 69 | 73 | 77 | 78 | 82 | 90 | Buy a coffee 91 | 92 | 93 | 94 | 95 | 103 | 104 | 105 | 106 | 110 | 111 | 115 | 123 | Share a tweet 124 | 125 | 126 | 127 | 128 | 136 | 137 | 138 | 139 | 140 | 146 | Dismiss 147 | 148 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /Snatch/Controls/SupportSection.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | using System.Windows.Input; 3 | using Snatch.Properties; 4 | 5 | namespace Snatch.Controls 6 | { 7 | public partial class SupportSection : UserControl 8 | { 9 | public SupportSection() 10 | { 11 | InitializeComponent(); 12 | } 13 | 14 | private void HideDonationSection(object sender, MouseButtonEventArgs e) 15 | { 16 | Settings.Default.ShowDonateInfo = false; 17 | Settings.Default.HasClosedDonateInfo = true; 18 | Settings.Default.Save(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Snatch/Extensions/CustomCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Input; 3 | 4 | namespace Snatch 5 | { 6 | public class CustomCommand : ICommand 7 | { 8 | public event EventHandler Executed; 9 | 10 | public bool CanExecute(object parameter) 11 | { 12 | return true; 13 | } 14 | 15 | public void Execute(object parameter) 16 | { 17 | Executed?.Invoke(this, parameter); 18 | } 19 | 20 | public event EventHandler CanExecuteChanged; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Snatch/Extensions/DbClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using Microsoft.EntityFrameworkCore; 5 | 6 | namespace Snatch 7 | { 8 | public class DbClient : DbContext 9 | { 10 | public DbSet Entries { get; set; } 11 | 12 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 13 | { 14 | string localPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); 15 | string fullPath = $"{localPath}\\Snatch"; 16 | string destination = $"{fullPath}\\Snatch.db"; 17 | 18 | Debug.WriteLine($"destination: {destination}"); 19 | 20 | if (!Directory.Exists(fullPath)) 21 | { 22 | Directory.CreateDirectory(fullPath); 23 | } 24 | 25 | if (!File.Exists(destination)) 26 | { 27 | string location = System.Reflection.Assembly.GetExecutingAssembly().Location; 28 | int index = location.LastIndexOf("\\"); 29 | string source = $"{location.Substring(0, index)}\\Snatch.db"; 30 | Debug.WriteLine($"source: {source}"); 31 | File.Copy(source, destination); 32 | } 33 | 34 | optionsBuilder.UseSqlite($"Data Source={destination}"); 35 | base.OnConfiguring(optionsBuilder); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Snatch/Extensions/DelegateCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Input; 3 | 4 | namespace Snatch { 5 | public class DelegateCommand : ICommand 6 | { 7 | public Action CommandAction { get; set; } 8 | public Func CanExecuteFunc { get; set; } 9 | 10 | public void Execute(object parameter) 11 | { 12 | CommandAction(); 13 | } 14 | 15 | public bool CanExecute(object parameter) 16 | { 17 | return CanExecuteFunc == null || CanExecuteFunc(); 18 | } 19 | 20 | public event EventHandler CanExecuteChanged 21 | { 22 | add { CommandManager.RequerySuggested += value; } 23 | remove { CommandManager.RequerySuggested -= value; } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Snatch/Extensions/DragBehavior.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Input; 3 | using System.Windows.Media; 4 | 5 | namespace Snatch 6 | { 7 | public class DragBehavior 8 | { 9 | public static readonly DependencyProperty EnableDragProperty = DependencyProperty.RegisterAttached( 10 | "EnableDrag", 11 | typeof(bool), 12 | typeof(DragBehavior), 13 | new PropertyMetadata(default(bool), OnLoaded)); 14 | 15 | private static void OnLoaded(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) 16 | { 17 | UIElement uiElement = dependencyObject as UIElement; 18 | if (uiElement == null || (dependencyPropertyChangedEventArgs.NewValue is bool) == false) 19 | { 20 | return; 21 | } 22 | if ((bool)dependencyPropertyChangedEventArgs.NewValue == true) 23 | { 24 | uiElement.MouseMove += UIElementOnMouseMove; 25 | } 26 | else 27 | { 28 | uiElement.MouseMove -= UIElementOnMouseMove; 29 | } 30 | 31 | } 32 | 33 | private static void UIElementOnMouseMove(object sender, MouseEventArgs mouseEventArgs) 34 | { 35 | UIElement uiElement = sender as UIElement; 36 | if (uiElement != null) 37 | { 38 | if (mouseEventArgs.LeftButton == MouseButtonState.Pressed) 39 | { 40 | DependencyObject parent = uiElement; 41 | int avoidInfiniteLoop = 0; 42 | // Search up the visual tree to find the first parent window. 43 | while ((parent is Window) == false) 44 | { 45 | parent = VisualTreeHelper.GetParent(parent); 46 | avoidInfiniteLoop++; 47 | if (avoidInfiniteLoop == 1000) 48 | { 49 | // Something is wrong - we could not find the parent window. 50 | return; 51 | } 52 | } 53 | Window window = parent as Window; 54 | window.DragMove(); 55 | } 56 | } 57 | } 58 | 59 | public static void SetEnableDrag(DependencyObject element, bool value) 60 | { 61 | element.SetValue(EnableDragProperty, value); 62 | } 63 | 64 | public static bool GetEnableDrag(DependencyObject element) 65 | { 66 | return (bool)element.GetValue(EnableDragProperty); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Snatch/Extensions/HyperlinkExtension.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace Snatch 4 | { 5 | public static class HyperlinkExtension 6 | { 7 | public static bool GetIsExternal(DependencyObject obj) 8 | { 9 | return (bool)obj.GetValue(IsExternalProperty); 10 | } 11 | 12 | public static void SetIsExternal(DependencyObject obj, bool value) 13 | { 14 | obj.SetValue(IsExternalProperty, value); 15 | } 16 | public static readonly DependencyProperty IsExternalProperty = 17 | DependencyProperty.RegisterAttached("IsExternal", typeof(bool), typeof(HyperlinkExtension), new UIPropertyMetadata(false, OnIsExternalChanged)); 18 | 19 | private static void OnIsExternalChanged(object sender, DependencyPropertyChangedEventArgs args) 20 | { 21 | System.Windows.Documents.Hyperlink hyperlink = sender as System.Windows.Documents.Hyperlink; 22 | 23 | if ((bool)args.NewValue) 24 | { 25 | hyperlink.RequestNavigate += Hyperlink_RequestNavigate; 26 | } 27 | else 28 | { 29 | hyperlink.RequestNavigate -= Hyperlink_RequestNavigate; 30 | } 31 | } 32 | 33 | private static void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) 34 | { 35 | System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(e.Uri.AbsoluteUri)); 36 | e.Handled = true; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Snatch/Extensions/NativeApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Timers; 4 | 5 | 6 | namespace Snatch 7 | { 8 | public enum ShowWindowEnum 9 | { 10 | Hide = 0, 11 | ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3, 12 | Maximize = 3, ShowNormalNoActivate = 4, Show = 5, 13 | Minimize = 6, ShowMinNoActivate = 7, ShowNoActivate = 8, 14 | Restore = 9, ShowDefault = 10, ForceMinimized = 11 15 | }; 16 | 17 | public static class NativeApi 18 | { 19 | [DllImport("user32.dll")] 20 | public static extern IntPtr GetForegroundWindow(); 21 | 22 | [DllImport("user32.dll")] 23 | [return: MarshalAs(UnmanagedType.Bool)] 24 | public static extern bool ShowWindow(IntPtr hWnd, ShowWindowEnum flags); 25 | 26 | [DllImport("user32.dll")] 27 | public static extern int SetForegroundWindow(IntPtr hwnd); 28 | 29 | [DllImport("user32.dll")] 30 | public static extern IntPtr GetActiveWindow(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Snatch/Extensions/ProcessWatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Timers; 3 | 4 | namespace Snatch 5 | { 6 | public static class ProcessWatcher 7 | { 8 | public static void StartWatch() 9 | { 10 | _timer = new Timer(100); 11 | _timer.Elapsed += new ElapsedEventHandler(timer_Elapsed); 12 | _timer.Start(); 13 | } 14 | 15 | static void timer_Elapsed(object sender, ElapsedEventArgs e) 16 | { 17 | SetLastActive(); 18 | } 19 | 20 | public static IntPtr LastHandle 21 | { 22 | get 23 | { 24 | return _previousToLastHandle; 25 | } 26 | } 27 | 28 | public static void BringMainWindowToFront() 29 | { 30 | //// check if the window is hidden / minimized 31 | if (LastHandle == IntPtr.Zero) 32 | { 33 | // the window is hidden so try to restore it before setting focus. 34 | NativeApi.ShowWindow(LastHandle, ShowWindowEnum.Restore); 35 | } 36 | 37 | // set user the focus to the window 38 | NativeApi.SetForegroundWindow(LastHandle); 39 | } 40 | 41 | private static void SetLastActive() 42 | { 43 | IntPtr currentHandle = NativeApi.GetForegroundWindow(); 44 | if (currentHandle != _previousHandle) 45 | { 46 | _previousToLastHandle = _previousHandle; 47 | _previousHandle = currentHandle; 48 | } 49 | } 50 | 51 | private static Timer _timer; 52 | private static IntPtr _previousHandle = IntPtr.Zero; 53 | private static IntPtr _previousToLastHandle = IntPtr.Zero; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Snatch/Extensions/SettingsBinding.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Data; 2 | 3 | namespace Snatch 4 | { 5 | public class SettingBindingExtension : Binding 6 | { 7 | public SettingBindingExtension() 8 | { 9 | Initialize(); 10 | } 11 | 12 | public SettingBindingExtension(string path) 13 | : base(path) 14 | { 15 | Initialize(); 16 | } 17 | 18 | private void Initialize() 19 | { 20 | this.Source = Properties.Settings.Default; 21 | this.Mode = BindingMode.TwoWay; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Snatch/Extensions/Utils.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Snatch 4 | { 5 | class Utils 6 | { 7 | public static void RemoveAll(IList iList, IEnumerable itemsToRemove) 8 | { 9 | HashSet set = new HashSet(itemsToRemove); 10 | List list = iList as List; 11 | 12 | if (list == null) 13 | { 14 | int i = 0; 15 | while (i < iList.Count) 16 | { 17 | if (set.Contains(iList[i])) 18 | { 19 | iList.RemoveAt(i); 20 | } 21 | else 22 | { 23 | i++; 24 | } 25 | } 26 | } 27 | else 28 | { 29 | list.RemoveAll(set.Contains); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Snatch/Models/Entry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | using System.Runtime.CompilerServices; 5 | using System.Text.RegularExpressions; 6 | 7 | namespace Snatch 8 | { 9 | [Table("entry")] 10 | public class Entry : INotifyPropertyChanged 11 | { 12 | public event PropertyChangedEventHandler PropertyChanged; 13 | private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") 14 | { 15 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 16 | } 17 | 18 | 19 | private int _id; 20 | public int Id { 21 | get 22 | { 23 | return _id; 24 | } 25 | set 26 | { 27 | _id = value; 28 | NotifyPropertyChanged(); 29 | } 30 | } 31 | 32 | private string _content = String.Empty; 33 | public string Content 34 | { 35 | get 36 | { 37 | return _content; 38 | } 39 | 40 | set 41 | { 42 | if (value != _content) 43 | { 44 | _content = value; 45 | NotifyPropertyChanged(); 46 | } 47 | } 48 | } 49 | 50 | private bool _isPinned = false; 51 | public bool IsPinned 52 | { 53 | get 54 | { 55 | return _isPinned; 56 | } 57 | 58 | set 59 | { 60 | if (value != _isPinned) 61 | { 62 | _isPinned = value; 63 | NotifyPropertyChanged(); 64 | } 65 | } 66 | } 67 | 68 | private bool _isVisible = true; 69 | [NotMapped] 70 | public bool IsVisible 71 | { 72 | get 73 | { 74 | return _isVisible; 75 | } 76 | 77 | set 78 | { 79 | if (value != _isVisible) 80 | { 81 | _isVisible = value; 82 | NotifyPropertyChanged(); 83 | } 84 | } 85 | } 86 | 87 | public string DisplayName 88 | { 89 | get 90 | { 91 | Regex regex = new Regex("[ ]{2,}", RegexOptions.None); 92 | string withoutNewline = this.Content.Replace("\r\n", "\n").Replace("\n", " "); 93 | 94 | return regex.Replace(withoutNewline, " ").TrimStart(); 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Snatch/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("Snatch")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("Snatch")] 15 | [assembly: AssemblyCopyright("Copyright © 2020")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /Snatch/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Snatch.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Snatch.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Snatch/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /Snatch/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Snatch.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.7.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.UserScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("True")] 29 | public bool ShowShortcuts { 30 | get { 31 | return ((bool)(this["ShowShortcuts"])); 32 | } 33 | set { 34 | this["ShowShortcuts"] = value; 35 | } 36 | } 37 | 38 | [global::System.Configuration.UserScopedSettingAttribute()] 39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 40 | [global::System.Configuration.DefaultSettingValueAttribute("True")] 41 | public bool SyncClipboard { 42 | get { 43 | return ((bool)(this["SyncClipboard"])); 44 | } 45 | set { 46 | this["SyncClipboard"] = value; 47 | } 48 | } 49 | 50 | [global::System.Configuration.UserScopedSettingAttribute()] 51 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 52 | [global::System.Configuration.DefaultSettingValueAttribute("0")] 53 | public int ToggleCount { 54 | get { 55 | return ((int)(this["ToggleCount"])); 56 | } 57 | set { 58 | this["ToggleCount"] = value; 59 | } 60 | } 61 | 62 | [global::System.Configuration.UserScopedSettingAttribute()] 63 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 64 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 65 | public bool HasClosedDonateInfo { 66 | get { 67 | return ((bool)(this["HasClosedDonateInfo"])); 68 | } 69 | set { 70 | this["HasClosedDonateInfo"] = value; 71 | } 72 | } 73 | 74 | [global::System.Configuration.UserScopedSettingAttribute()] 75 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 76 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 77 | public bool ShowDonateInfo { 78 | get { 79 | return ((bool)(this["ShowDonateInfo"])); 80 | } 81 | set { 82 | this["ShowDonateInfo"] = value; 83 | } 84 | } 85 | 86 | [global::System.Configuration.UserScopedSettingAttribute()] 87 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 88 | [global::System.Configuration.DefaultSettingValueAttribute("0")] 89 | public int CopyCount { 90 | get { 91 | return ((int)(this["CopyCount"])); 92 | } 93 | set { 94 | this["CopyCount"] = value; 95 | } 96 | } 97 | 98 | [global::System.Configuration.UserScopedSettingAttribute()] 99 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 100 | [global::System.Configuration.DefaultSettingValueAttribute("True")] 101 | public bool ShowOnboarding { 102 | get { 103 | return ((bool)(this["ShowOnboarding"])); 104 | } 105 | set { 106 | this["ShowOnboarding"] = value; 107 | } 108 | } 109 | 110 | [global::System.Configuration.UserScopedSettingAttribute()] 111 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 112 | [global::System.Configuration.DefaultSettingValueAttribute("0")] 113 | public byte OnboardingStep { 114 | get { 115 | return ((byte)(this["OnboardingStep"])); 116 | } 117 | set { 118 | this["OnboardingStep"] = value; 119 | } 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Snatch/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | True 7 | 8 | 9 | True 10 | 11 | 12 | 0 13 | 14 | 15 | False 16 | 17 | 18 | False 19 | 20 | 21 | 0 22 | 23 | 24 | True 25 | 26 | 27 | 0 28 | 29 | 30 | -------------------------------------------------------------------------------- /Snatch/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Snatch": { 4 | "commandName": "Project" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /Snatch/Resources/TrayResources.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Snatch/Resources/app-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Snatch/Resources/app-icon.ico -------------------------------------------------------------------------------- /Snatch/Resources/kasper-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Snatch/Resources/kasper-64.png -------------------------------------------------------------------------------- /Snatch/Resources/kasper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Snatch/Resources/kasper.jpg -------------------------------------------------------------------------------- /Snatch/Resources/kiwi-bird-duotone.xaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Snatch/Resources/tray-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Snatch/Resources/tray-icon.ico -------------------------------------------------------------------------------- /Snatch/Snatch.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {2F943BD5-49D7-40C5-9486-57A7F0E7AB32} 8 | WinExe 9 | Snatch 10 | Snatch 11 | v4.8 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | true 17 | 18 | 19 | 20 | 21 | AnyCPU 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE 36 | prompt 37 | 4 38 | 39 | 40 | true 41 | bin\x64\Debug\ 42 | DEBUG;TRACE 43 | full 44 | x64 45 | 7.3 46 | prompt 47 | MinimumRecommendedRules.ruleset 48 | true 49 | 50 | 51 | bin\x64\Release\ 52 | TRACE 53 | true 54 | pdbonly 55 | x64 56 | 7.3 57 | prompt 58 | MinimumRecommendedRules.ruleset 59 | true 60 | 61 | 62 | true 63 | bin\x86\Debug\ 64 | DEBUG;TRACE 65 | full 66 | x86 67 | 7.3 68 | prompt 69 | MinimumRecommendedRules.ruleset 70 | true 71 | 72 | 73 | bin\x86\Release\ 74 | TRACE 75 | true 76 | pdbonly 77 | x86 78 | 7.3 79 | prompt 80 | MinimumRecommendedRules.ruleset 81 | true 82 | 83 | 84 | 85 | ..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll 86 | 87 | 88 | ..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.1\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll 89 | 90 | 91 | ..\packages\Microsoft.Bcl.HashCode.1.1.0\lib\net461\Microsoft.Bcl.HashCode.dll 92 | 93 | 94 | ..\packages\Microsoft.Data.Sqlite.Core.3.1.8\lib\netstandard2.0\Microsoft.Data.Sqlite.dll 95 | 96 | 97 | ..\packages\Microsoft.DotNet.PlatformAbstractions.3.1.6\lib\net45\Microsoft.DotNet.PlatformAbstractions.dll 98 | 99 | 100 | ..\packages\Microsoft.EntityFrameworkCore.3.1.8\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll 101 | 102 | 103 | ..\packages\Microsoft.EntityFrameworkCore.Abstractions.3.1.8\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Abstractions.dll 104 | 105 | 106 | ..\packages\Microsoft.EntityFrameworkCore.Relational.3.1.8\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll 107 | 108 | 109 | ..\packages\Microsoft.EntityFrameworkCore.Sqlite.Core.3.1.8\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Sqlite.dll 110 | 111 | 112 | ..\packages\Microsoft.Extensions.Caching.Abstractions.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll 113 | 114 | 115 | ..\packages\Microsoft.Extensions.Caching.Memory.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll 116 | 117 | 118 | ..\packages\Microsoft.Extensions.Configuration.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll 119 | 120 | 121 | ..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll 122 | 123 | 124 | ..\packages\Microsoft.Extensions.Configuration.Binder.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll 125 | 126 | 127 | ..\packages\Microsoft.Extensions.DependencyInjection.3.1.8\lib\net461\Microsoft.Extensions.DependencyInjection.dll 128 | 129 | 130 | ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.8\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll 131 | 132 | 133 | ..\packages\Microsoft.Extensions.DependencyModel.3.1.6\lib\net451\Microsoft.Extensions.DependencyModel.dll 134 | 135 | 136 | ..\packages\Microsoft.Extensions.Logging.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Logging.dll 137 | 138 | 139 | ..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll 140 | 141 | 142 | ..\packages\Microsoft.Extensions.Options.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Options.dll 143 | 144 | 145 | ..\packages\Microsoft.Extensions.Primitives.3.1.8\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll 146 | 147 | 148 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 149 | 150 | 151 | ..\packages\NHotkey.2.1.0\lib\net45\NHotkey.dll 152 | 153 | 154 | ..\packages\NHotkey.Wpf.2.1.0\lib\net45\NHotkey.Wpf.dll 155 | 156 | 157 | ..\packages\SharpClipboard.3.5.2\lib\net20\SharpClipboard.dll 158 | 159 | 160 | ..\packages\SQLitePCLRaw.bundle_e_sqlite3.2.0.2\lib\net461\SQLitePCLRaw.batteries_v2.dll 161 | 162 | 163 | ..\packages\SQLitePCLRaw.core.2.0.2\lib\netstandard2.0\SQLitePCLRaw.core.dll 164 | 165 | 166 | ..\packages\SQLitePCLRaw.bundle_e_sqlite3.2.0.2\lib\net461\SQLitePCLRaw.nativelibrary.dll 167 | 168 | 169 | ..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.2\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll 170 | 171 | 172 | 173 | ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll 174 | 175 | 176 | ..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll 177 | 178 | 179 | ..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll 180 | 181 | 182 | 183 | 184 | 185 | ..\packages\System.Diagnostics.DiagnosticSource.4.7.1\lib\net46\System.Diagnostics.DiagnosticSource.dll 186 | 187 | 188 | 189 | ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll 190 | 191 | 192 | 193 | ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll 194 | 195 | 196 | ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll 197 | 198 | 199 | ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.0.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll 200 | True 201 | True 202 | 203 | 204 | ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 4.0 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | MSBuild:Compile 223 | Designer 224 | 225 | 226 | 227 | 228 | 229 | 230 | MainWindow.xaml 231 | 232 | 233 | MSBuild:Compile 234 | Designer 235 | 236 | 237 | MSBuild:Compile 238 | Designer 239 | 240 | 241 | MSBuild:Compile 242 | Designer 243 | 244 | 245 | MSBuild:Compile 246 | Designer 247 | 248 | 249 | MSBuild:Compile 250 | Designer 251 | 252 | 253 | App.xaml 254 | Code 255 | 256 | 257 | EmptyListView.xaml 258 | 259 | 260 | Header.xaml 261 | 262 | 263 | Onboarding.xaml 264 | 265 | 266 | ShortcutList.xaml 267 | 268 | 269 | SupportSection.xaml 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | MSBuild:Compile 282 | Designer 283 | 284 | 285 | MSBuild:Compile 286 | Designer 287 | 288 | 289 | MSBuild:Compile 290 | Designer 291 | 292 | 293 | 294 | 295 | Code 296 | 297 | 298 | True 299 | True 300 | Resources.resx 301 | 302 | 303 | True 304 | Settings.settings 305 | True 306 | 307 | 308 | ResXFileCodeGenerator 309 | Resources.Designer.cs 310 | 311 | 312 | 313 | SettingsSingleFileGenerator 314 | Settings.Designer.cs 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 331 | 332 | 333 | 334 | -------------------------------------------------------------------------------- /Snatch/Snatch.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Idered/snatch/8b991d675db6876ebf0304c0589d6fbe7fcc445b/Snatch/Snatch.db -------------------------------------------------------------------------------- /Snatch/ViewModels/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace Snatch 4 | { 5 | public class MainViewModel: INotifyPropertyChanged 6 | { 7 | public event PropertyChangedEventHandler PropertyChanged; 8 | private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") 9 | { 10 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 11 | } 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Snatch/ViewModels/OnboardingViewModel.cs: -------------------------------------------------------------------------------- 1 | 2 | using System.Windows.Input; 3 | 4 | namespace Snatch 5 | { 6 | public class OnboardingViewModel: System.ComponentModel.INotifyPropertyChanged 7 | { 8 | public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; 9 | private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") 10 | { 11 | PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); 12 | } 13 | 14 | 15 | private bool isPressingCtrl = false; 16 | public bool IsPressingCtrl 17 | { 18 | get { return isPressingCtrl; } 19 | set 20 | { 21 | if (value != isPressingCtrl) 22 | { 23 | isPressingCtrl = value; 24 | NotifyPropertyChanged(); 25 | } 26 | } 27 | } 28 | 29 | 30 | private bool isPressingShift = false; 31 | public bool IsPressingShift 32 | { 33 | get { return isPressingShift; } 34 | set 35 | { 36 | if (value != isPressingShift) 37 | { 38 | isPressingShift = value; 39 | NotifyPropertyChanged(); 40 | } 41 | } 42 | } 43 | 44 | 45 | private bool isPressingV = false; 46 | public bool IsPressingV 47 | { 48 | get { return isPressingV; } 49 | set 50 | { 51 | if (value != isPressingV) 52 | { 53 | isPressingV = value; 54 | NotifyPropertyChanged(); 55 | } 56 | } 57 | } 58 | public OnboardingViewModel() 59 | { 60 | System.Windows.Application.Current.MainWindow.PreviewKeyUp += HandleWindowKeyUp; 61 | System.Windows.Application.Current.MainWindow.PreviewKeyDown += HandleWindowKeyDown; 62 | } 63 | 64 | private void HandleWindowKeyDown(object sender, KeyEventArgs e) 65 | { 66 | if (e.Key == Key.LeftCtrl) 67 | { 68 | IsPressingCtrl = true; 69 | } 70 | if (e.Key == Key.LeftShift) 71 | { 72 | IsPressingShift = true; 73 | } 74 | if (e.Key == Key.V) 75 | { 76 | IsPressingV = true; 77 | } 78 | } 79 | 80 | private void HandleWindowKeyUp(object sender, KeyEventArgs e) 81 | { 82 | if (e.Key == Key.LeftCtrl) 83 | { 84 | IsPressingCtrl = false; 85 | } 86 | if (e.Key == Key.LeftShift) 87 | { 88 | IsPressingShift = false; 89 | } 90 | if (e.Key == Key.V) 91 | { 92 | IsPressingV = false; 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Snatch/ViewModels/TrayViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Input; 3 | 4 | namespace Snatch 5 | { 6 | public class TrayViewModel 7 | { 8 | public ICommand ShowApplicationCommand 9 | { 10 | get 11 | { 12 | return new DelegateCommand() 13 | { 14 | CommandAction = () => 15 | { 16 | Application.Current.MainWindow.Show(); 17 | Application.Current.MainWindow.Activate(); 18 | } 19 | }; 20 | } 21 | } 22 | 23 | public ICommand ExitApplicationCommand 24 | { 25 | get 26 | { 27 | return new DelegateCommand() 28 | { 29 | CommandAction = () => Application.Current.Shutdown() 30 | }; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Snatch/Windows/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 75 | 76 | 145 | 146 | 147 | 148 | 149 | 155 | 156 | 162 | 163 | 164 | 165 | 169 | 170 | 171 | 172 | 173 | 184 | 185 | 186 | 187 | 188 | 189 | 200 | 201 | 202 | 203 | 214 | 215 | 216 | 217 | 218 | 225 | 226 | 227 | 252 | 253 | 254 | 255 | 256 | 257 | 263 | 264 | 265 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | -------------------------------------------------------------------------------- /Snatch/Windows/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using System.Windows.Controls; 6 | using System.Windows.Input; 7 | using NHotkey; 8 | using NHotkey.Wpf; 9 | using WK.Libraries.SharpClipboardNS; 10 | using System.ComponentModel; 11 | using System.Collections.Generic; 12 | using System.Configuration; 13 | using Snatch.Properties; 14 | using System.Diagnostics; 15 | 16 | namespace Snatch 17 | { 18 | public partial class MainWindow : Window, INotifyPropertyChanged 19 | { 20 | public event PropertyChangedEventHandler PropertyChanged; 21 | private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") 22 | { 23 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 24 | } 25 | 26 | private bool ClipboardInitialized = false; 27 | private readonly SharpClipboard clipboard = new SharpClipboard(); 28 | private readonly DbClient db = new DbClient(); 29 | 30 | public MainWindow() 31 | { 32 | this.DataContext = this; 33 | 34 | LoadEntries(); 35 | InitializeComponent(); 36 | RegisterHotkey(); 37 | 38 | clipboard.ClipboardChanged += ClipboardChanged; 39 | ProcessWatcher.StartWatch(); 40 | 41 | if (Settings.Default.ShowOnboarding) 42 | { 43 | this.Visibility = Visibility.Visible; 44 | } 45 | 46 | HeaderRef.QueryInput.TextChanged += QueryInput_TextChanged; 47 | HeaderRef.QueryInput.PreviewKeyDown += QueryInput_PreviewKeyDown; 48 | Activated += HandleWindowActivated; 49 | } 50 | 51 | private void LoadEntries() 52 | { 53 | this.Entries = new ObservableCollection(db.Entries.ToList()); 54 | this.HasVisibleEntries = this.Entries.Count() > 0; 55 | } 56 | 57 | private void RegisterHotkey() 58 | { 59 | KeyGesture ToggleGesture = new KeyGesture(Key.V, ModifierKeys.Control | ModifierKeys.Shift); 60 | HotkeyManager.Current.AddOrReplace("Toggle", ToggleGesture, HandleToggle); 61 | } 62 | 63 | private ObservableCollection _entries = new ObservableCollection(); 64 | public ObservableCollection Entries 65 | { 66 | get 67 | { 68 | return _entries; 69 | } 70 | 71 | set 72 | { 73 | if (value != _entries) 74 | { 75 | _entries = value; 76 | NotifyPropertyChanged(); 77 | } 78 | } 79 | } 80 | 81 | private bool _hasVisibleEntries = true; 82 | public bool HasVisibleEntries 83 | { 84 | get 85 | { 86 | return _hasVisibleEntries; 87 | } 88 | 89 | set 90 | { 91 | if (value != _hasVisibleEntries) 92 | { 93 | _hasVisibleEntries = value; 94 | NotifyPropertyChanged(); 95 | } 96 | } 97 | } 98 | 99 | private void HandleToggle(object sender, HotkeyEventArgs e) 100 | { 101 | if (Settings.Default.OnboardingStep == 0) 102 | { 103 | Settings.Default.OnboardingStep += 1; 104 | Activate(); 105 | HeaderRef.QueryInput.Focus(); 106 | return; 107 | } 108 | if (Settings.Default.OnboardingStep == 1) 109 | { 110 | Settings.Default.OnboardingStep += 1; 111 | Settings.Default.ShowOnboarding = false; 112 | Settings.Default.Save(); 113 | Activate(); 114 | HeaderRef.QueryInput.Focus(); 115 | return; 116 | } 117 | if (this.Visibility == Visibility.Visible) 118 | { 119 | this.Visibility = Visibility.Hidden; 120 | } 121 | else 122 | { 123 | this.Visibility = Visibility.Visible; 124 | Activate(); 125 | HeaderRef.QueryInput.Focus(); 126 | Settings.Default.ToggleCount += 1; 127 | if (Settings.Default.ToggleCount >= 50 && Settings.Default.HasClosedDonateInfo == false) 128 | { 129 | Settings.Default.ShowDonateInfo = true; 130 | } 131 | Settings.Default.Save(); 132 | } 133 | } 134 | 135 | private void ClipboardChanged(object sender, SharpClipboard.ClipboardChangedEventArgs e) 136 | { 137 | if (ClipboardInitialized == false) 138 | { 139 | ClipboardInitialized = true; 140 | return; 141 | } 142 | 143 | if (e.ContentType == SharpClipboard.ContentTypes.Text) 144 | { 145 | bool alreadyExists = this.Entries.Where((item) => item.Content == clipboard.ClipboardText).Any(); 146 | 147 | if (clipboard.ClipboardText.Length > 0 && !alreadyExists) 148 | { 149 | Entry entry = new Entry() { Content = clipboard.ClipboardText }; 150 | db.Add(entry); 151 | this.Entries.Insert(0, entry); 152 | this.uiItems.SelectedIndex = 0; 153 | db.SaveChanges(); 154 | } 155 | } 156 | } 157 | 158 | private void OnItemMouseDown(object sender, MouseButtonEventArgs e) 159 | { 160 | HandleSelectedItem(sender); 161 | } 162 | 163 | private void HandleSelectedItem(object sender) 164 | { 165 | ListView view = sender as ListView; 166 | Entry selected = view.SelectedItem as Entry; 167 | 168 | if (selected != null && selected.IsVisible) 169 | { 170 | Settings.Default.CopyCount += 1; 171 | Settings.Default.Save(); 172 | clipboard.ClipboardChanged -= ClipboardChanged; 173 | Clipboard.SetText(selected.Content); 174 | clipboard.ClipboardChanged += ClipboardChanged; 175 | ProcessWatcher.BringMainWindowToFront(); 176 | System.Windows.Forms.SendKeys.SendWait("^v"); 177 | this.Visibility = Visibility.Hidden; 178 | } 179 | } 180 | 181 | public void QuitKeybinding(object sender, object e) 182 | { 183 | Application.Current.Shutdown(); 184 | } 185 | 186 | public void CloseWindowKeybinding(object sender, object e) 187 | { 188 | this.Visibility = Visibility.Hidden; 189 | } 190 | 191 | public void TogglePinAllKeybinding(object sender, object e) 192 | { 193 | if (!this.Entries.Any()) 194 | { 195 | return; 196 | } 197 | 198 | Entry first = this.Entries.First(); 199 | bool synced = this.Entries.Where(item => item.IsPinned == first.IsPinned).Count() == this.Entries.Count; 200 | bool isPinned = !synced || !first.IsPinned; 201 | 202 | if (first != null) 203 | { 204 | foreach (Entry item in this.Entries) 205 | { 206 | item.IsPinned = isPinned; 207 | db.Entries.Update(item); 208 | } 209 | 210 | db.SaveChanges(); 211 | } 212 | } 213 | 214 | 215 | public void ToggleCheatsheetKeybinding(object sender, object e) 216 | { 217 | Settings.Default.ShowShortcuts = !Settings.Default.ShowShortcuts; 218 | Settings.Default.Save(); 219 | } 220 | 221 | public void PinKeybinding(object sender, object e) 222 | { 223 | Entry entry = uiItems.SelectedItem as Entry; 224 | if (entry == null) 225 | { 226 | return; 227 | } 228 | 229 | entry.IsPinned = !entry.IsPinned; 230 | db.Entries.Update(entry); 231 | db.SaveChanges(); 232 | } 233 | 234 | private void ClearList() 235 | { 236 | List entriesToRemove = this.Entries.Where(item => item.IsPinned == false).ToList(); 237 | Utils.RemoveAll(this.Entries, entriesToRemove); 238 | db.Entries.RemoveRange(entriesToRemove); 239 | db.SaveChanges(); 240 | uiItems.SelectedIndex = 0; 241 | } 242 | 243 | public void ClearKeybinding(object sender, object e) 244 | { 245 | ClearList(); 246 | } 247 | 248 | private void QueryInput_TextChanged(object sender, TextChangedEventArgs e) 249 | { 250 | int visibleCount = 0; 251 | 252 | foreach (Entry entry in this.Entries) 253 | { 254 | if (HeaderRef.QueryInput.Text.Trim() == "") 255 | { 256 | visibleCount++; 257 | entry.IsVisible = true; 258 | continue; 259 | } 260 | entry.IsVisible = entry.Content.IndexOf(HeaderRef.QueryInput.Text, StringComparison.OrdinalIgnoreCase) >= 0; 261 | visibleCount = entry.IsVisible ? visibleCount + 1 : visibleCount; 262 | } 263 | 264 | this.HasVisibleEntries = visibleCount > 0; 265 | 266 | if (this.uiItems.SelectedItem == null && this.Entries.Count() > 0) 267 | { 268 | this.uiItems.SelectedIndex = 0; 269 | this.uiItems.ScrollIntoView(this.uiItems.SelectedItem); 270 | } 271 | } 272 | 273 | private void QueryInput_PreviewKeyDown(object sender, KeyEventArgs e) 274 | { 275 | if (this.Entries.Count() == 0) 276 | { 277 | return; 278 | } 279 | 280 | Entry selected = uiItems.SelectedItem as Entry; 281 | IList visibleEntries = this.Entries.Where(item => item.IsVisible == true).ToList(); 282 | int selectedVisibleIndex = visibleEntries.IndexOf(selected); 283 | 284 | switch (e.Key) 285 | { 286 | case Key.Delete: 287 | if (Keyboard.IsKeyDown(Key.LeftCtrl) && selected != null) 288 | { 289 | int lastIndex = selectedVisibleIndex; 290 | db.Entries.Remove(selected); 291 | db.SaveChangesAsync(); 292 | this.Entries.RemoveAt(uiItems.SelectedIndex); 293 | 294 | visibleEntries = this.Entries.Where(item => item.IsVisible == true).ToList(); 295 | 296 | if (visibleEntries.Count() > 0) 297 | { 298 | uiItems.SelectedItem = visibleEntries.ElementAt(Math.Min(lastIndex, visibleEntries.Count() - 1)); 299 | uiItems.ScrollIntoView(uiItems.SelectedItem); 300 | } 301 | } 302 | break; 303 | case Key.PageDown: 304 | uiItems.SelectedItem = visibleEntries.ElementAt(Math.Min(selectedVisibleIndex + 7, visibleEntries.Count() - 1)); 305 | uiItems.ScrollIntoView(uiItems.SelectedItem); 306 | break; 307 | case Key.PageUp: 308 | uiItems.SelectedItem = visibleEntries.ElementAt(Math.Max(selectedVisibleIndex - 7, 0)); 309 | uiItems.ScrollIntoView(uiItems.SelectedItem); 310 | break; 311 | case Key.Down: 312 | uiItems.SelectedItem = visibleEntries.ElementAt((selectedVisibleIndex + 1) % visibleEntries.Count()); 313 | uiItems.ScrollIntoView(uiItems.SelectedItem); 314 | break; 315 | case Key.Up: 316 | int v = (selectedVisibleIndex - 1); 317 | uiItems.SelectedItem = visibleEntries.ElementAt(v < 0 ? visibleEntries.Count() - 1 : v); ; 318 | uiItems.ScrollIntoView(uiItems.SelectedItem); 319 | break; 320 | case Key.Enter: 321 | HandleSelectedItem(uiItems); 322 | break; 323 | default: 324 | break; 325 | } 326 | } 327 | 328 | private void HandleWindowActivated(object sender, EventArgs e) 329 | { 330 | if (this.Entries.Count() == 0) 331 | { 332 | return; 333 | } 334 | 335 | if (uiItems.SelectedItem == null) 336 | { 337 | uiItems.SelectedIndex = 0; 338 | } 339 | 340 | uiItems.ScrollIntoView(uiItems.SelectedItem); 341 | } 342 | } 343 | } 344 | -------------------------------------------------------------------------------- /Snatch/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | --------------------------------------------------------------------------------