Merge pull request #1829 from Flow-Launcher/dev

Release 1.12.0 | Plugin 3.1.0
This commit is contained in:
Jeremy Wu 2023-01-24 17:59:34 +11:00 committed by GitHub
commit 1acfd3404a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
224 changed files with 2743 additions and 808 deletions

View file

@ -41,25 +41,26 @@ body:
- type: input
attributes:
label: Flow Launcher Version
description: Go to "Settings" => "About".
value: v1.8.3
description: Go to "Settings" => "About". If you are using a prerelease version please append the build number.
placeholder: "Example: 1.11.0"
validations:
required: true
- type: input
attributes:
label: Windows Build Number
description: Run "ver" at CMD (command prompt).
value: 10.0.19043.1288
description: Run "ver" at CMD (command prompt) or go to Windows Settings -> Systems -> About.
placeholder: "Example: 10.0.19043.1288"
validations:
required: true
- type: textarea
id: logs
attributes:
label: Error Log
description: >
Log file place:
- The latest version place: `%AppData%\FlowLauncher\Logs\<version>\<date>.txt`
- For portable mode: `%LocalAppData%\FlowLauncher\<App-Version>\UserData\Logs\<version>\<date>.txt`
From flow type 'open log location' and find log file with the corresponding date containing the error info.
value: >
<details>

17
.github/actions/spelling/README.md vendored Normal file
View file

@ -0,0 +1,17 @@
# check-spelling/check-spelling configuration
File | Purpose | Format | Info
-|-|-|-
[dictionary.txt](dictionary.txt) | Replacement dictionary (creating this file will override the default dictionary) | one word per line | [dictionary](https://github.com/check-spelling/check-spelling/wiki/Configuration#dictionary)
[allow.txt](allow.txt) | Add words to the dictionary | one word per line (only letters and `'`s allowed) | [allow](https://github.com/check-spelling/check-spelling/wiki/Configuration#allow)
[reject.txt](reject.txt) | Remove words from the dictionary (after allow) | grep pattern matching whole dictionary words | [reject](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-reject)
[excludes.txt](excludes.txt) | Files to ignore entirely | perl regular expression | [excludes](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-excludes)
[only.txt](only.txt) | Only check matching files (applied after excludes) | perl regular expression | [only](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-only)
[patterns.txt](patterns.txt) | Patterns to ignore from checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
[candidate.patterns](candidate.patterns) | Patterns that might be worth adding to [patterns.txt](patterns.txt) | perl regular expression with optional comment block introductions (all matches will be suggested) | [candidates](https://github.com/check-spelling/check-spelling/wiki/Feature:-Suggest-patterns)
[line_forbidden.patterns](line_forbidden.patterns) | Patterns to flag in checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
[expect.txt](expect.txt) | Expected words that aren't in the dictionary | one word per line (sorted, alphabetically) | [expect](https://github.com/check-spelling/check-spelling/wiki/Configuration#expect)
[advice.md](advice.md) | Supplement for GitHub comment when unrecognized words are found | GitHub Markdown | [advice](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice)
Note: you can replace any of these files with a directory by the same name (minus the suffix)
and then include multiple files inside that directory (with that suffix) to merge multiple files together.

25
.github/actions/spelling/advice.md vendored Normal file
View file

@ -0,0 +1,25 @@
<!-- See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice --> <!-- markdownlint-disable MD033 MD041 -->
<details><summary>If the flagged items are :exploding_head: false positives</summary>
If items relate to a ...
* binary file (or some other file you wouldn't want to check at all).
Please add a file path to the `excludes.txt` file matching the containing file.
File paths are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files.
`^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
../tree/HEAD/README.md) (on whichever branch you're using).
* well-formed pattern.
If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it,
try adding it to the `patterns.txt` file.
Patterns are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.
Note that patterns can't match multiline strings.
</details>

4
.github/actions/spelling/allow.txt vendored Normal file
View file

@ -0,0 +1,4 @@
github
https
ssh
ubuntu

View file

@ -0,0 +1,522 @@
# marker to ignore all code on line
^.*/\* #no-spell-check-line \*/.*$
# marker for ignoring a comment to the end of the line
// #no-spell-check.*$
# patch hunk comments
^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .*
# git index header
index [0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
# cid urls
(['"])cid:.*?\g{-1}
# data url in parens
\(data:[^)]*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\)
# data url in quotes
([`'"])data:.*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
# data url
data:[-a-zA-Z=;:/0-9+]*,\S*
# mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
# magnet urls
magnet:[?=:\w]+
# magnet urls
"magnet:[^"]+"
# obs:
"obs:[^"]*"
# The `\b` here means a break, it's the fancy way to handle urls, but it makes things harder to read
# In this examples content, I'm using a number of different ways to match things to show various approaches
# asciinema
\basciinema\.org/a/[0-9a-zA-Z]+
# apple
\bdeveloper\.apple\.com/[-\w?=/]+
# Apple music
\bembed\.music\.apple\.com/fr/playlist/usr-share/[-\w.]+
# appveyor api
\bci\.appveyor\.com/api/projects/status/[0-9a-z]+
# appveyor project
\bci\.appveyor\.com/project/(?:[^/\s"]*/){2}builds?/\d+/job/[0-9a-z]+
# Amazon
# Amazon
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)
# AWS S3
\b\w*\.s3[^.]*\.amazonaws\.com/[-\w/&#%_?:=]*
# AWS execute-api
\b[0-9a-z]{10}\.execute-api\.[-0-9a-z]+\.amazonaws\.com\b
# AWS ELB
\b\w+\.[-0-9a-z]+\.elb\.amazonaws\.com\b
# AWS SNS
\bsns\.[-0-9a-z]+.amazonaws\.com/[-\w/&#%_?:=]*
# AWS VPC
vpc-\w+
# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there
# YouTube url
\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]*
# YouTube music
\bmusic\.youtube\.com/youtubei/v1/browse(?:[?&]\w+=[-a-zA-Z0-9?&=_]*)
# YouTube tag
<\s*youtube\s+id=['"][-a-zA-Z0-9?_]*['"]
# YouTube image
\bimg\.youtube\.com/vi/[-a-zA-Z0-9?&=_]*
# Google Accounts
\baccounts.google.com/[-_/?=.:;+%&0-9a-zA-Z]*
# Google Analytics
\bgoogle-analytics\.com/collect.[-0-9a-zA-Z?%=&_.~]*
# Google APIs
\bgoogleapis\.(?:com|dev)/[a-z]+/(?:v\d+/|)[a-z]+/[-@:./?=\w+|&]+
# Google Storage
\b[-a-zA-Z0-9.]*\bstorage\d*\.googleapis\.com(?:/\S*|)
# Google Calendar
\bcalendar\.google\.com/calendar(?:/u/\d+|)/embed\?src=[@./?=\w&%]+
\w+\@group\.calendar\.google\.com\b
# Google DataStudio
\bdatastudio\.google\.com/(?:(?:c/|)u/\d+/|)(?:embed/|)(?:open|reporting|datasources|s)/[-0-9a-zA-Z]+(?:/page/[-0-9a-zA-Z]+|)
# The leading `/` here is as opposed to the `\b` above
# ... a short way to match `https://` or `http://` since most urls have one of those prefixes
# Google Docs
/docs\.google\.com/[a-z]+/(?:ccc\?key=\w+|(?:u/\d+|d/(?:e/|)[0-9a-zA-Z_-]+/)?(?:edit\?[-\w=#.]*|/\?[\w=&]*|))
# Google Drive
\bdrive\.google\.com/(?:file/d/|open)[-0-9a-zA-Z_?=]*
# Google Groups
\bgroups\.google\.com/(?:(?:forum/#!|d/)(?:msg|topics?|searchin)|a)/[^/\s"]+/[-a-zA-Z0-9$]+(?:/[-a-zA-Z0-9]+)*
# Google Maps
\bmaps\.google\.com/maps\?[\w&;=]*
# Google themes
themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
# Google CDN
\bclients2\.google(?:usercontent|)\.com[-0-9a-zA-Z/.]*
# Goo.gl
/goo\.gl/[a-zA-Z0-9]+
# Google Chrome Store
\bchrome\.google\.com/webstore/detail/[-\w]*(?:/\w*|)
# Google Books
\bgoogle\.(?:\w{2,4})/books(?:/\w+)*\?[-\w\d=&#.]*
# Google Fonts
\bfonts\.(?:googleapis|gstatic)\.com/[-/?=:;+&0-9a-zA-Z]*
# Google Forms
\bforms\.gle/\w+
# Google Scholar
\bscholar\.google\.com/citations\?user=[A-Za-z0-9_]+
# Google Colab Research Drive
\bcolab\.research\.google\.com/drive/[-0-9a-zA-Z_?=]*
# GitHub SHAs (api)
\bapi.github\.com/repos(?:/[^/\s"]+){3}/[0-9a-f]+\b
# GitHub SHAs (markdown)
(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|)
# GitHub SHAs
\bgithub\.com(?:/[^/\s"]+){2}[@#][0-9a-f]+\b
# GitHub wiki
\bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b
# githubusercontent
/[-a-z0-9]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]*
# githubassets
\bgithubassets.com/[0-9a-f]+(?:[-/\w.]+)
# gist github
\bgist\.github\.com/[^/\s"]+/[0-9a-f]+
# git.io
\bgit\.io/[0-9a-zA-Z]+
# GitHub JSON
"node_id": "[-a-zA-Z=;:/0-9+]*"
# Contributor
\[[^\]]+\]\(https://github\.com/[^/\s"]+\)
# GHSA
GHSA(?:-[0-9a-z]{4}){3}
# GitLab commit
\bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b
# GitLab merge requests
\bgitlab\.[^/\s"]*/\S+/\S+/-/merge_requests/\d+/diffs#[0-9a-f]{40}\b
# GitLab uploads
\bgitlab\.[^/\s"]*/uploads/[-a-zA-Z=;:/0-9+]*
# GitLab commits
\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b
# binanace
accounts.binance.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
# bitbucket diff
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}diff(?:stat|)(?:/[^/\s"]+){2}:[0-9a-f]+
# bitbucket repositories commits
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
# bitbucket commits
\bbitbucket\.org/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
# bit.ly
\bbit\.ly/\w+
# bitrise
\bapp\.bitrise\.io/app/[0-9a-f]*/[\w.?=&]*
# bootstrapcdn.com
\bbootstrapcdn\.com/[-./\w]+
# cdn.cloudflare.com
\bcdnjs\.cloudflare\.com/[./\w]+
# circleci
\bcircleci\.com/gh(?:/[^/\s"]+){1,5}.[a-z]+\?[-0-9a-zA-Z=&]+
# gitter
\bgitter\.im(?:/[^/\s"]+){2}\?at=[0-9a-f]+
# gravatar
\bgravatar\.com/avatar/[0-9a-f]+
# ibm
[a-z.]*ibm\.com/[-_#=:%!?~.\\/\d\w]*
# imgur
\bimgur\.com/[^.]+
# Internet Archive
\barchive\.org/web/\d+/(?:[-\w.?,'/\\+&%$#_:]*)
# discord
/discord(?:app\.com|\.gg)/(?:invite/)?[a-zA-Z0-9]{7,}
# Disqus
\bdisqus\.com/[-\w/%.()!?&=_]*
# medium link
\blink\.medium\.com/[a-zA-Z0-9]+
# medium
\bmedium\.com/\@?[^/\s"]+/[-\w]+
# microsoft
\b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]*
# powerbi
\bapp\.powerbi\.com/reportEmbed/[^"' ]*
# vs devops
\bvisualstudio.com(?::443|)/[-\w/?=%&.]*
# microsoft store
\bmicrosoft\.com/store/apps/\w+
# mvnrepository.com
\bmvnrepository\.com/[-0-9a-z./]+
# now.sh
/[0-9a-z-.]+\.now\.sh\b
# oracle
\bdocs\.oracle\.com/[-0-9a-zA-Z./_?#&=]*
# chromatic.com
/\S+.chromatic.com\S*[")]
# codacy
\bapi\.codacy\.com/project/badge/Grade/[0-9a-f]+
# compai
\bcompai\.pub/v1/png/[0-9a-f]+
# mailgun api
\.api\.mailgun\.net/v3/domains/[0-9a-z]+\.mailgun.org/messages/[0-9a-zA-Z=@]*
# mailgun
\b[0-9a-z]+.mailgun.org
# /message-id/
/message-id/[-\w@./%]+
# Reddit
\breddit\.com/r/[/\w_]*
# requestb.in
\brequestb\.in/[0-9a-z]+
# sched
\b[a-z0-9]+\.sched\.com\b
# Slack url
slack://[a-zA-Z0-9?&=]+
# Slack
\bslack\.com/[-0-9a-zA-Z/_~?&=.]*
# Slack edge
\bslack-edge\.com/[-a-zA-Z0-9?&=%./]+
# Slack images
\bslack-imgs\.com/[-a-zA-Z0-9?&=%.]+
# shields.io
\bshields\.io/[-\w/%?=&.:+;,]*
# stackexchange -- https://stackexchange.com/feeds/sites
\b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/)
# Sentry
[0-9a-f]{32}\@o\d+\.ingest\.sentry\.io\b
# Twitter markdown
\[\@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\)
# Twitter hashtag
\btwitter\.com/hashtag/[\w?_=&]*
# Twitter status
\btwitter\.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)
# Twitter profile images
\btwimg\.com/profile_images/[_\w./]*
# Twitter media
\btwimg\.com/media/[-_\w./?=]*
# Twitter link shortened
\bt\.co/\w+
# facebook
\bfburl\.com/[0-9a-z_]+
# facebook CDN
\bfbcdn\.net/[\w/.,]*
# facebook watch
\bfb\.watch/[0-9A-Za-z]+
# dropbox
\bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+
# ipfs protocol
ipfs://[0-9a-z]*
# ipfs url
/ipfs/[0-9a-z]*
# w3
\bw3\.org/[-0-9a-zA-Z/#.]+
# loom
\bloom\.com/embed/[0-9a-f]+
# regex101
\bregex101\.com/r/[^/\s"]+/\d+
# figma
\bfigma\.com/file(?:/[0-9a-zA-Z]+/)+
# freecodecamp.org
\bfreecodecamp\.org/[-\w/.]+
# image.tmdb.org
\bimage\.tmdb\.org/[/\w.]+
# mermaid
\bmermaid\.ink/img/[-\w]+|\bmermaid-js\.github\.io/mermaid-live-editor/#/edit/[-\w]+
# Wikipedia
\ben\.wikipedia\.org/wiki/[-\w%.#]+
# gitweb
[^"\s]+/gitweb/\S+;h=[0-9a-f]+
# HyperKitty lists
/archives/list/[^@/]+\@[^/\s"]*/message/[^/\s"]*/
# lists
/thread\.html/[^"\s]+
# list-management
\blist-manage\.com/subscribe(?:[?&](?:u|id)=[0-9a-f]+)+
# kubectl.kubernetes.io/last-applied-configuration
"kubectl.kubernetes.io/last-applied-configuration": ".*"
# pgp
\bgnupg\.net/pks/lookup[?&=0-9a-zA-Z]*
# Spotify
\bopen\.spotify\.com/embed/playlist/\w+
# Mastodon
\bmastodon\.[-a-z.]*/(?:media/|\@)[?&=0-9a-zA-Z_]*
# scastie
\bscastie\.scala-lang\.org/[^/]+/\w+
# images.unsplash.com
\bimages\.unsplash\.com/(?:(?:flagged|reserve)/|)[-\w./%?=%&.;]+
# pastebin
\bpastebin\.com/[\w/]+
# heroku
\b\w+\.heroku\.com/source/archive/\w+
# quip
\b\w+\.quip\.com/\w+(?:(?:#|/issues/)\w+)?
# badgen.net
\bbadgen\.net/badge/[^")\]'\s]+
# statuspage.io
\w+\.statuspage\.io\b
# media.giphy.com
\bmedia\.giphy\.com/media/[^/]+/[\w.?&=]+
# tinyurl
\btinyurl\.com/\w+
# getopts
\bgetopts\s+(?:"[^"]+"|'[^']+')
# ANSI color codes
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
# URL escaped characters
\%[0-9A-F][A-F]
# IPv6
\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b
# c99 hex digits (not the full format, just one I've seen)
0x[0-9a-fA-F](?:\.[0-9a-fA-F]*|)[pP]
# Punycode
\bxn--[-0-9a-z]+
# sha
sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
# sha-... -- uses a fancy capture
(['"]|&quot;)[0-9a-f]{40,}\g{-1}
# hex runs
\b[0-9a-fA-F]{16,}\b
# hex in url queries
=[0-9a-fA-F]*?(?:[A-F]{3,}|[a-f]{3,})[0-9a-fA-F]*?&
# ssh
(?:ssh-\S+|-nistp256) [-a-zA-Z=;:/0-9+]{12,}
# PGP
\b(?:[0-9A-F]{4} ){9}[0-9A-F]{4}\b
# GPG keys
\b(?:[0-9A-F]{4} ){5}(?: [0-9A-F]{4}){5}\b
# Well known gpg keys
.well-known/openpgpkey/[\w./]+
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
# integrity
integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}"
# https://www.gnu.org/software/groff/manual/groff.html
# man troff content
\\f[BCIPR]
# '
\\\(aq
# .desktop mime types
^MimeTypes?=.*$
# .desktop localized entries
^[A-Z][a-z]+\[[a-z]+\]=.*$
# Localized .desktop content
Name\[[^\]]+\]=.*
# IServiceProvider
\bI(?=(?:[A-Z][a-z]{2,})+\b)
# crypt
"\$2[ayb]\$.{56}"
# scrypt / argon
\$(?:scrypt|argon\d+[di]*)\$\S+
# Input to GitHub JSON
content: "[-a-zA-Z=;:/0-9+]*="
# Python stringprefix / binaryprefix
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
(?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
# Regular expressions for (P|p)assword
\([A-Z]\|[a-z]\)[a-z]+
# JavaScript regular expressions
# javascript test regex
/.*/[gim]*\.test\(
# javascript match regex
\.match\(/[^/\s"]*/[gim]*\s*
# javascript match regex
\.match\(/\\[b].*?/[gim]*\s*\)(?:;|$)
# javascript regex
^\s*/\\[b].*/[gim]*\s*(?:\)(?:;|$)|,$)
# javascript replace regex
\.replace\(/[^/\s"]*/[gim]*\s*,
# Go regular expressions
regexp?\.MustCompile\(`[^`]*`\)
# sed regular expressions
sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2}
# go install
go install(?:\s+[a-z]+\.[-@\w/.]+)+
# kubernetes pod status lists
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+
# kubectl - pods in CrashLoopBackOff
\w+-[0-9a-f]+-\w+\s+\d+/\d+\s+CrashLoopBackOff\s+
# kubernetes object suffix
-[0-9a-f]{10}-\w{5}\s
# posthog secrets
posthog\.init\((['"])phc_[^"',]+\g{-1},
# xcode
# xcodeproject scenes
(?:Controller|ID|id)="\w{3}-\w{2}-\w{3}"
# xcode api botches
customObjectInstantitationMethod
# font awesome classes
\.fa-[-a-z0-9]+
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
## Operation "substitution (s///)" returns its argument for non-Unicode code point 0x1C19AE (the code point will vary).
## You could manually change `(?i)X...` to use `[Xx]...`
## or you could add the files to your `excludes` file (a version after 0.0.19 should identify the file path)
# Lorem
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
# Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
# French
# This corpus only had capital letters, but you probably want lowercase ones as well.
\b[LN]'+[a-z]{2,}\b
# latex
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
# the negative lookahead here is to allow catching 'templatesz' as a misspelling
# but to otherwise recognize a Windows path with \templates\foo.template or similar:
\\(?:necessary|r(?:eport|esolve[dr]?|esult)|t(?:arget|emplates?))(?![a-z])
# ignore long runs of a single character:
\b([A-Za-z])\g{-1}{3,}\b
# Note that the next example is no longer necessary if you are using
# to match a string starting with a `#`, use a character-class:
[#]backwards
# version suffix <word>v#
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
# Compiler flags (Scala)
(?:^|[\t ,>"'`=(])-J-[DPWXY](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags
(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags (linker)
,-B
# curl arguments
\b(?:\\n|)curl(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
# set arguments
\bset(?:\s+-[abefimouxE]{1,2})*\s+-[abefimouxE]{3,}(?:\s+-[abefimouxE]+)*
# tar arguments
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long...
\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b
# macOS temp folders
/var/folders/\w\w/[+\w]+/(?:T|-Caches-)/

73
.github/actions/spelling/excludes.txt vendored Normal file
View file

@ -0,0 +1,73 @@
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-excludes
(?:^|/)(?i)COPYRIGHT
(?:^|/)(?i)LICEN[CS]E
(?:^|/)3rdparty/
(?:^|/)go\.sum$
(?:^|/)package(?:-lock|)\.json$
(?:^|/)vendor/
\.a$
\.ai$
\.avi$
\.bmp$
\.bz2$
\.class$
\.crt$
\.dll$
\.docx?$
\.drawio$
\.DS_Store$
\.eot$
\.exe$
\.gif$
\.gitattributes$
\.gitignore$
\.graffle$
\.gz$
\.icns$
\.ico$
\.jar$
\.jks$
\.jpe?g$
\.key$
\.lib$
\.lock$
\.map$
\.min\..
\.mod$
\.mp[34]$
\.o$
\.ocf$
\.otf$
\.pdf$
\.pem$
\.png$
\.psd$
\.pyc$
\.s$
\.svgz?$
\.tar$
\.tiff?$
\.ttf$
\.wav$
\.webm$
\.webp$
\.woff2?$
\.xlsx?$
\.zip$
^\.github/actions/spelling/
^\Q.github/workflows/spelling.yml\E$
# Custom
(?:^|/)Languages/(?!en\.xaml)
Scripts/
\.resx$
^\QPlugins/Flow.Launcher.Plugin.WindowsSettings/WindowsSettings.json\E$
^\QPlugins/Flow.Launcher.Plugin.WebSearch/setting.json\E$
(?:^|/)FodyWeavers\.xml
.editorconfig
ignore$
\.ps1$
\.yml$
\.sln$
\.csproj$
\.DotSettings$
\.targets$

90
.github/actions/spelling/expect.txt vendored Normal file
View file

@ -0,0 +1,90 @@
crowdin
DWM
workflows
wpf
actionkeyword
stackoverflow
Wox
flowlauncher
Fody
stackoverflow
IContext
IShell
IPlugin
appveyor
netflix
youtube
appdata
Prioritise
Segoe
Google
Customise
UWP
uwp
Bokmal
Bokm
uninstallation
uninstalling
voidtools
fullscreen
hotkeys
totalcmd
lnk
amazonaws
mscorlib
pythonw
dotnet
winget
jjw24
wolframalpha
gmail
duckduckgo
facebook
findicon
baidu
pls
websearch
qianlifeng
userdata
srchadmin
EWX
dlgtext
CMD
appref-ms
appref
TSource
runas
dpi
popup
ptr
pluginindicator
TobiasSekan
Img
img
resx
bak
tmp
directx
mvvm
dlg
ddd
dddd
clearlogfolder
ACCENT_ENABLE_TRANSPARENTGRADIENT
ACCENT_ENABLE_BLURBEHIND
WCA_ACCENT_POLICY
HGlobal
dopusrt
firefox
msedge
svgc
ime
zindex
txb
btn
otf
searchplugin
Noresult
wpftk
mkv
flac

View file

@ -0,0 +1,62 @@
# reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere
# \bm_data\b
# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test,
# you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want
# to use this:
#\bfit\(
# s.b. GitHub
#\bGithub\b
# s.b. GitLab
\bGitlab\b
# s.b. JavaScript
\bJavascript\b
# s.b. Microsoft
\bMicroSoft\b
# s.b. another
\ban[- ]other\b
# s.b. greater than
\bgreater then\b
# s.b. into
\sin to\s
# s.b. opt-in
\sopt in\s
# s.b. less than
\bless then\b
# s.b. otherwise
\bother[- ]wise\b
# s.b. nonexistent
\bnon existing\b
\b[Nn]o[nt][- ]existent\b
# s.b. preexisting
[Pp]re[- ]existing
# s.b. preempt
[Pp]re[- ]empt\b
# s.b. preemptively
[Pp]re[- ]emptively
# s.b. reentrancy
[Rr]e[- ]entrancy
# s.b. reentrant
[Rr]e[- ]entrant
# s.b. workaround(s)
\bwork[- ]arounds?\b
# Reject duplicate words
\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s

117
.github/actions/spelling/patterns.txt vendored Normal file
View file

@ -0,0 +1,117 @@
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
# Questionably acceptable forms of `in to`
# Personally, I prefer `log into`, but people object
# https://www.tprteaching.com/log-into-log-in-to-login/
\b[Ll]og in to\b
# acceptable duplicates
# ls directory listings
[-bcdlpsw](?:[-r][-w][-sx]){3}\s+\d+\s+(\S+)\s+\g{-1}\s+\d+\s+
# C types and repeated CSS values
\s(center|div|inherit|long|LONG|none|normal|solid|thin|transparent|very)(?: \g{-1})+\s
# go templates
\s(\w+)\s+\g{-1}\s+\`(?:graphql|json|yaml):
# javadoc / .net
(?:[\\@](?:groupname|param)|(?:public|private)(?:\s+static|\s+readonly)*)\s+(\w+)\s+\g{-1}\s
# Commit message -- Signed-off-by and friends
^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$
# Autogenerated revert commit message
^This reverts commit [0-9a-f]{40}\.$
# ignore long runs of a single character:
\b([A-Za-z])\g{-1}{3,}\b
# Automatically suggested patterns
# hit-count: 360 file-count: 108
# IServiceProvider
\bI(?=(?:[A-Z][a-z]{2,})+\b)
# hit-count: 297 file-count: 18
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hit-count: 138 file-count: 27
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
# hit-count: 93 file-count: 28
# hex runs
\b[0-9a-fA-F]{16,}\b
# hit-count: 52 file-count: 3
# githubusercontent
/[-a-z0-9]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]*
/[-a-z0-9]+\.github\.com/[-a-zA-Z0-9?&=_\/.]*
# hit-count: 24 file-count: 12
# GitHub SHAs (markdown)
(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|)
# hit-count: 11 file-count: 10
# stackexchange -- https://stackexchange.com/feeds/sites
\b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/)
# hit-count: 11 file-count: 8
# microsoft
\b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]*
# hit-count: 2 file-count: 2
# Twitter status
\btwitter\.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)
# hit-count: 2 file-count: 1
# discord
/discord(?:app\.com|\.gg)/(?:invite/)?[a-zA-Z0-9]{7,}
# hit-count: 1 file-count: 1
# appveyor api
\bci\.appveyor\.com/api/projects/status/[0-9a-z]+
# hit-count: 1 file-count: 1
# gist github
\bgist\.github\.com/[^/\s"]+/[0-9a-f]+
# Automatically suggested patterns
# hit-count: 21 file-count: 21
# w3
\bw3\.org/[-0-9a-zA-Z/#.]+
# hit-count: 6 file-count: 1
# shields.io
\bshields\.io/[-\w/%?=&.:+;,]*
# hit-count: 3 file-count: 2
# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there
# YouTube url
\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]*
# hit-count: 2 file-count: 2
# Google Maps
\bmaps\.google\.com/maps\?[\w&;=]*
# hit-count: 2 file-count: 2
# Contributor
\[[^\]]+\]\(https://github\.com/[^/\s"]+\)
# hit-count: 2 file-count: 1
# URL escaped characters
\%[0-9A-F][A-F]
# hit-count: 1 file-count: 1
# Compiler flags
(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Localization keys
#x:Key="[^"]+"
#{DynamicResource [^"]+}
# html tag
<\w+[^>]*>
</\w+[^>]*>
#http/https
(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]

10
.github/actions/spelling/reject.txt vendored Normal file
View file

@ -0,0 +1,10 @@
^attache$
benefitting
occurences?
^dependan.*
^oer$
Sorce
^[Ss]pae.*
^untill$
^untilling$
^wether.*

160
.github/workflows/spelling.yml vendored Normal file
View file

@ -0,0 +1,160 @@
name: Check Spelling
# Comment management is handled through a secondary job, for details see:
# https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions
#
# `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment
# (in odd cases, it might actually run just to collapse a comment, but that's fairly rare)
# it needs `contents: write` in order to add a comment.
#
# `jobs.comment-pr` runs when a pull_request is made to a repository and the `jobs.spelling` job needs to make a comment
# or collapse a comment (in the case where it had previously made a comment and now no longer needs to show a comment)
# it needs `pull-requests: write` in order to manipulate those comments.
# Updating pull request branches is managed via comment handling.
# For details, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-expect-list
#
# These elements work together to make it happen:
#
# `on.issue_comment`
# This event listens to comments by users asking to update the metadata.
#
# `jobs.update`
# This job runs in response to an issue_comment and will push a new commit
# to update the spelling metadata.
#
# `with.experimental_apply_changes_via_bot`
# Tells the action to support and generate messages that enable it
# to make a commit to update the spelling metadata.
#
# `with.ssh_key`
# In order to trigger workflows when the commit is made, you can provide a
# secret (typically, a write-enabled github deploy key).
#
# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key
on:
# push:
# branches:
# - '**'
# - '!l10n_dev'
# tags-ignore:
# - "**"
pull_request_target:
branches:
- '**'
# - '!l10n_dev'
tags-ignore:
- "**"
types:
- 'opened'
- 'reopened'
- 'synchronize'
# issue_comment:
# types:
# - 'created'
jobs:
spelling:
name: Check Spelling
permissions:
contents: read
pull-requests: read
actions: read
security-events: write
outputs:
followup: ${{ steps.spelling.outputs.followup }}
runs-on: ubuntu-latest
if: (contains(github.event_name, 'pull_request') && github.head_ref != 'l10n_dev')
concurrency:
group: spelling-${{ github.event.pull_request.number || github.ref }}
# note: If you use only_check_changed_files, you do not want cancel-in-progress
cancel-in-progress: false
steps:
- name: check-spelling
id: spelling
uses: check-spelling/check-spelling@main
with:
suppress_push_for_open_pull_request: 1
checkout: true
check_file_names: 1
spell_check_this: check-spelling/spell-check-this@main
post_comment: 0
use_magic_file: 1
experimental_apply_changes_via_bot: 1
use_sarif: 0 # to show in pr page
extra_dictionary_limit: 10
check_commit_messages: commits title description
only_check_changed_files: 1
check_extra_dictionaries: ''
quit_without_error: true
extra_dictionaries:
cspell:software-terms/src/software-terms.txt
cspell:win32/src/win32.txt
cspell:php/php.txt
cspell:filetypes/filetypes.txt
cspell:csharp/csharp.txt
cspell:dotnet/dotnet.txt
cspell:python/src/python/python-lib.txt
cspell:aws/aws.txt
cspell:companies/src/companies.txt
warnings:
binary-file,deprecated-feature,large-file,limited-references,noisy-file,non-alpha-in-dictionary,unexpected-line-ending,whitespace-in-dictionary,minified-file,unsupported-configuration,unrecognized-spelling,no-newline-at-eof
# comment-push:
# name: Report (Push)
# # If your workflow isn't running on push, you can remove this job
# runs-on: ubuntu-latest
# needs: spelling
# permissions:
# contents: write
# if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
# steps:
# - name: comment
# uses: check-spelling/check-spelling@main
# with:
# checkout: true
# spell_check_this: check-spelling/spell-check-this@main
# task: ${{ needs.spelling.outputs.followup }}
comment-pr:
name: Report (PR)
# If you workflow isn't running on pull_request*, you can remove this job
runs-on: ubuntu-latest
needs: spelling
permissions:
pull-requests: write
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
steps:
- name: comment
uses: check-spelling/check-spelling@main
with:
checkout: true
spell_check_this: check-spelling/spell-check-this@main
task: ${{ needs.spelling.outputs.followup }}
experimental_apply_changes_via_bot: 1
# update:
# name: Update PR
# permissions:
# contents: write
# pull-requests: write
# actions: read
# runs-on: ubuntu-latest
# if: ${{
# github.event_name == 'issue_comment' &&
# github.event.issue.pull_request &&
# contains(github.event.comment.body, '@check-spelling-bot apply')
# }}
# concurrency:
# group: spelling-update-${{ github.event.issue.number }}
# cancel-in-progress: false
# steps:
# - name: apply spelling updates
# uses: check-spelling/check-spelling@main
# with:
# experimental_apply_changes_via_bot: 1
# checkout: true
# ssh_key: "${{ secrets.CHECK_SPELLING }}"

View file

@ -13,7 +13,7 @@ jobs:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v4
- uses: actions/stale@v7
with:
stale-issue-message: 'This issue is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
days-before-stale: 45

View file

@ -47,7 +47,7 @@ namespace Flow.Launcher.Core.Configuration
}
catch (Exception e)
{
Log.Exception("|Portable.DisablePortableMode|Error occured while disabling portable mode", e);
Log.Exception("|Portable.DisablePortableMode|Error occurred while disabling portable mode", e);
}
}
@ -71,7 +71,7 @@ namespace Flow.Launcher.Core.Configuration
}
catch (Exception e)
{
Log.Exception("|Portable.EnablePortableMode|Error occured while enabling portable mode", e);
Log.Exception("|Portable.EnablePortableMode|Error occurred while enabling portable mode", e);
}
}
@ -187,7 +187,7 @@ namespace Flow.Launcher.Core.Configuration
if (roamingLocationExists && portableLocationExists)
{
MessageBox.Show(string.Format("Flow Launcher detected your user data exists both in {0} and " +
"{1}. {2}{2}Please delete {1} in order to proceed. No changes have occured.",
"{1}. {2}{2}Please delete {1} in order to proceed. No changes have occurred.",
DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
return false;

View file

@ -259,9 +259,16 @@ namespace Flow.Launcher.Core.Plugin
await using var registeredEvent = token.Register(() =>
{
if (!process.HasExited)
process.Kill();
sourceBuffer.Dispose();
try
{
if (!process.HasExited)
process.Kill();
sourceBuffer.Dispose();
}
catch (Exception e)
{
Log.Exception("|JsonRPCPlugin.ExecuteAsync|Exception when kill process", e);
}
});
try
@ -288,7 +295,7 @@ namespace Flow.Launcher.Core.Plugin
}
sourceBuffer.Seek(0, SeekOrigin.Begin);
return sourceBuffer;
}
@ -376,7 +383,8 @@ namespace Flow.Launcher.Core.Plugin
sep.SetResourceReference(Separator.BackgroundProperty, "Color03B"); /* for theme change */
var panel = new StackPanel
{
Orientation = Orientation.Vertical, VerticalAlignment = VerticalAlignment.Center,
Orientation = Orientation.Vertical,
VerticalAlignment = VerticalAlignment.Center,
Margin = settingLabelPanelMargin
};
RowDefinition gridRow = new RowDefinition();
@ -390,8 +398,10 @@ namespace Flow.Launcher.Core.Plugin
};
var desc = new TextBlock()
{
Text = attribute.Description, FontSize = 12,
VerticalAlignment = VerticalAlignment.Center,Margin = settingDescMargin,
Text = attribute.Description,
FontSize = 12,
VerticalAlignment = VerticalAlignment.Center,
Margin = settingDescMargin,
TextWrapping = TextWrapping.WrapWithOverflow
};
desc.SetResourceReference(TextBlock.ForegroundProperty, "Color04B");
@ -405,7 +415,7 @@ namespace Flow.Launcher.Core.Plugin
panel.Children.Add(name);
panel.Children.Add(desc);
}
Grid.SetColumn(panel, 0);
Grid.SetRow(panel, rowCount);
@ -420,20 +430,20 @@ namespace Flow.Launcher.Core.Plugin
{
Text = attribute.Description.Replace("\\r\\n", "\r\n"),
Margin = settingTextBlockMargin,
Padding = new Thickness(0,0,0,0),
Padding = new Thickness(0, 0, 0, 0),
HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
TextAlignment = TextAlignment.Left,
TextWrapping = TextWrapping.Wrap
};
Grid.SetColumn(contentControl, 0);
Grid.SetColumnSpan(contentControl, 2);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
Grid.SetColumn(contentControl, 0);
Grid.SetColumnSpan(contentControl, 2);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
}
case "input":
{
@ -449,50 +459,49 @@ namespace Flow.Launcher.Core.Plugin
Settings[attribute.Name] = textBox.Text;
};
contentControl = textBox;
Grid.SetColumn(contentControl, 1);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
Grid.SetColumn(contentControl, 1);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
}
case "inputWithFileBtn":
{
var textBox = new TextBox()
{
var textBox = new TextBox()
{
Margin = new Thickness(10, 0, 0, 0),
Text = Settings[attribute.Name] as string ?? string.Empty,
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
ToolTip = attribute.Description
};
textBox.TextChanged += (_, _) =>
{
Settings[attribute.Name] = textBox.Text;
};
var Btn = new System.Windows.Controls.Button()
{
Margin = new Thickness(10,0,0,0),
Content = "Browse"
};
var dockPanel = new DockPanel()
{
Margin = settingControlMargin
};
DockPanel.SetDock(Btn, Dock.Right);
dockPanel.Children.Add(Btn);
dockPanel.Children.Add(textBox);
contentControl = dockPanel;
Grid.SetColumn(contentControl, 1);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
}
Margin = new Thickness(10, 0, 0, 0),
Text = Settings[attribute.Name] as string ?? string.Empty,
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
ToolTip = attribute.Description
};
textBox.TextChanged += (_, _) =>
{
Settings[attribute.Name] = textBox.Text;
};
var Btn = new System.Windows.Controls.Button()
{
Margin = new Thickness(10, 0, 0, 0), Content = "Browse"
};
var dockPanel = new DockPanel()
{
Margin = settingControlMargin
};
DockPanel.SetDock(Btn, Dock.Right);
dockPanel.Children.Add(Btn);
dockPanel.Children.Add(textBox);
contentControl = dockPanel;
Grid.SetColumn(contentControl, 1);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
}
case "textarea":
{
var textBox = new TextBox()
@ -511,14 +520,14 @@ namespace Flow.Launcher.Core.Plugin
Settings[attribute.Name] = ((TextBox)sender).Text;
};
contentControl = textBox;
Grid.SetColumn(contentControl, 1);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
Grid.SetColumn(contentControl, 1);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
}
case "passwordBox":
{
@ -535,14 +544,14 @@ namespace Flow.Launcher.Core.Plugin
Settings[attribute.Name] = ((PasswordBox)sender).Password;
};
contentControl = passwordBox;
Grid.SetColumn(contentControl, 1);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
Grid.SetColumn(contentControl, 1);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
}
case "dropdown":
{
@ -559,14 +568,14 @@ namespace Flow.Launcher.Core.Plugin
Settings[attribute.Name] = (string)((System.Windows.Controls.ComboBox)sender).SelectedItem;
};
contentControl = comboBox;
Grid.SetColumn(contentControl, 1);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
Grid.SetColumn(contentControl, 1);
Grid.SetRow(contentControl, rowCount);
if (rowCount != 0)
mainPanel.Children.Add(sep);
Grid.SetRow(sep, rowCount);
Grid.SetColumn(sep, 0);
Grid.SetColumnSpan(sep, 2);
break;
}
case "checkbox":
var checkBox = new CheckBox
@ -592,13 +601,11 @@ namespace Flow.Launcher.Core.Plugin
case "hyperlink":
var hyperlink = new Hyperlink
{
ToolTip = attribute.Description,
NavigateUri = attribute.url
ToolTip = attribute.Description, NavigateUri = attribute.url
};
var linkbtn = new System.Windows.Controls.Button
{
HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
Margin = settingControlMargin
HorizontalAlignment = System.Windows.HorizontalAlignment.Right, Margin = settingControlMargin
};
linkbtn.Content = attribute.urlLabel;
@ -619,7 +626,7 @@ namespace Flow.Launcher.Core.Plugin
mainPanel.Children.Add(panel);
mainPanel.Children.Add(contentControl);
rowCount++;
}
return settingWindow;
}

View file

@ -36,7 +36,7 @@ namespace Flow.Launcher.Core.Resource
{
_themeDirectories.Add(DirectoryPath);
_themeDirectories.Add(UserDirectoryPath);
MakesureThemeDirectoriesExist();
MakeSureThemeDirectoriesExist();
var dicts = Application.Current.Resources.MergedDictionaries;
_oldResource = dicts.First(d =>
@ -55,20 +55,17 @@ namespace Flow.Launcher.Core.Resource
_oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath);
}
private void MakesureThemeDirectoriesExist()
private void MakeSureThemeDirectoriesExist()
{
foreach (string dir in _themeDirectories)
foreach (var dir in _themeDirectories.Where(dir => !Directory.Exists(dir)))
{
if (!Directory.Exists(dir))
try
{
try
{
Directory.CreateDirectory(dir);
}
catch (Exception e)
{
Log.Exception($"|Theme.MakesureThemeDirectoriesExist|Exception when create directory <{dir}>", e);
}
Directory.CreateDirectory(dir);
}
catch (Exception e)
{
Log.Exception($"|Theme.MakesureThemeDirectoriesExist|Exception when create directory <{dir}>", e);
}
}
}
@ -82,13 +79,14 @@ namespace Flow.Launcher.Core.Resource
{
if (string.IsNullOrEmpty(path))
throw new DirectoryNotFoundException("Theme path can't be found <{path}>");
Settings.Theme = theme;
// reload all resources even if the theme itself hasn't changed in order to pickup changes
// to things like fonts
UpdateResourceDictionary(GetResourceDictionary());
UpdateResourceDictionary(GetResourceDictionary(theme));
Settings.Theme = theme;
//always allow re-loading default theme, in case of failure of switching to a new theme from default theme
if (_oldTheme != theme || theme == defaultTheme)
{
@ -134,9 +132,9 @@ namespace Flow.Launcher.Core.Resource
_oldResource = dictionaryToUpdate;
}
private ResourceDictionary CurrentThemeResourceDictionary()
private ResourceDictionary GetThemeResourceDictionary(string theme)
{
var uri = GetThemePath(Settings.Theme);
var uri = GetThemePath(theme);
var dict = new ResourceDictionary
{
Source = new Uri(uri, UriKind.Absolute)
@ -145,10 +143,12 @@ namespace Flow.Launcher.Core.Resource
return dict;
}
public ResourceDictionary GetResourceDictionary()
private ResourceDictionary CurrentThemeResourceDictionary() => GetThemeResourceDictionary(Settings.Theme);
public ResourceDictionary GetResourceDictionary(string theme)
{
var dict = CurrentThemeResourceDictionary();
var dict = GetThemeResourceDictionary(theme);
if (dict["QueryBoxStyle"] is Style queryBoxStyle &&
dict["QuerySuggestionBoxStyle"] is Style querySuggestionBoxStyle)
{
@ -200,6 +200,11 @@ namespace Flow.Launcher.Core.Resource
return dict;
}
private ResourceDictionary GetCurrentResourceDictionary( )
{
return GetResourceDictionary(Settings.Theme);
}
public List<string> LoadAvailableThemes()
{
List<string> themes = new List<string>();
@ -229,7 +234,7 @@ namespace Flow.Launcher.Core.Resource
public void AddDropShadowEffectToCurrentTheme()
{
var dict = GetResourceDictionary();
var dict = GetCurrentResourceDictionary();
var windowBorderStyle = dict["WindowBorderStyle"] as Style;
@ -273,7 +278,7 @@ namespace Flow.Launcher.Core.Resource
public void RemoveDropShadowEffectFromCurrentTheme()
{
var dict = CurrentThemeResourceDictionary();
var dict = GetCurrentResourceDictionary();
var windowBorderStyle = dict["WindowBorderStyle"] as Style;
var effectSetter = windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.EffectProperty) as Setter;

View file

@ -33,7 +33,7 @@ namespace Flow.Launcher.Core
public async Task UpdateAppAsync(IPublicAPI api, bool silentUpdate = true)
{
await UpdateLock.WaitAsync();
await UpdateLock.WaitAsync().ConfigureAwait(false);
try
{
if (!silentUpdate)
@ -88,9 +88,13 @@ namespace Flow.Launcher.Core
UpdateManager.RestartApp(Constant.ApplicationFileName);
}
}
catch (Exception e) when (e is HttpRequestException or WebException or SocketException || e.InnerException is TimeoutException)
catch (Exception e)
{
Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e);
if ((e is HttpRequestException or WebException or SocketException || e.InnerException is TimeoutException))
Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e);
else
Log.Exception($"|Updater.UpdateApp|Error Occurred", e);
if (!silentUpdate)
api.ShowMsg(api.GetTranslation("update_flowlauncher_fail"),
api.GetTranslation("update_flowlauncher_check_connection"));

View file

@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
namespace Flow.Launcher.Infrastructure
{
public static class FileExplorerHelper
{
/// <summary>
/// Gets the path of the file explorer that is currently in the foreground
/// </summary>
public static string GetActiveExplorerPath()
{
var explorerWindow = GetActiveExplorer();
string locationUrl = explorerWindow?.LocationURL;
return !string.IsNullOrEmpty(locationUrl) ? new Uri(locationUrl).LocalPath + "\\" : null;
}
/// <summary>
/// Gets the file explorer that is currently in the foreground
/// </summary>
private static dynamic GetActiveExplorer()
{
Type type = Type.GetTypeFromProgID("Shell.Application");
if (type == null) return null;
dynamic shell = Activator.CreateInstance(type);
if (shell == null)
{
return null;
}
var explorerWindows = new List<dynamic>();
var openWindows = shell.Windows();
for (int i = 0; i < openWindows.Count; i++)
{
var window = openWindows.Item(i);
if (window == null) continue;
// find the desired window and make sure that it is indeed a file explorer
// we don't want the Internet Explorer or the classic control panel
// ToLower() is needed, because Windows can report the path as "C:\\Windows\\Explorer.EXE"
if (Path.GetFileName((string)window.FullName)?.ToLower() == "explorer.exe")
{
explorerWindows.Add(window);
}
}
if (explorerWindows.Count == 0) return null;
var zOrders = GetZOrder(explorerWindows);
return explorerWindows.Zip(zOrders).MinBy(x => x.Second).First;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
/// <summary>
/// Gets the z-order for one or more windows atomically with respect to each other. In Windows, smaller z-order is higher. If the window is not top level, the z order is returned as -1.
/// </summary>
private static IEnumerable<int> GetZOrder(List<dynamic> hWnds)
{
var z = new int[hWnds.Count];
for (var i = 0; i < hWnds.Count; i++) z[i] = -1;
var index = 0;
var numRemaining = hWnds.Count;
EnumWindows((wnd, _) =>
{
var searchIndex = hWnds.FindIndex(x => x.HWND == wnd.ToInt32());
if (searchIndex != -1)
{
z[searchIndex] = index;
numRemaining--;
if (numRemaining == 0) return false;
}
index++;
return true;
}, IntPtr.Zero);
return z;
}
}
}

View file

@ -1,4 +1,6 @@
using System;
#nullable enable
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text.Json;
@ -16,7 +18,7 @@ namespace Flow.Launcher.Infrastructure
/// <summary>
/// http://www.yinwang.org/blog-cn/2015/11/21/programming-philosophy
/// </summary>
public static T NonNull<T>(this T obj)
public static T NonNull<T>(this T? obj)
{
if (obj == null)
{

View file

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
using System.Windows.Navigation;
namespace Flow.Launcher.Infrastructure.Hotkey
{
@ -11,10 +12,10 @@ namespace Flow.Launcher.Infrastructure.Hotkey
public bool Shift { get; set; }
public bool Win { get; set; }
public bool Ctrl { get; set; }
public Key CharKey { get; set; }
public Key CharKey { get; set; } = Key.None;
Dictionary<Key, string> specialSymbolDictionary = new Dictionary<Key, string>
private static readonly Dictionary<Key, string> specialSymbolDictionary = new Dictionary<Key, string>
{
{Key.Space, "Space"},
{Key.Oem3, "~"}
@ -27,19 +28,19 @@ namespace Flow.Launcher.Infrastructure.Hotkey
ModifierKeys modifierKeys = ModifierKeys.None;
if (Alt)
{
modifierKeys = ModifierKeys.Alt;
modifierKeys |= ModifierKeys.Alt;
}
if (Shift)
{
modifierKeys = modifierKeys | ModifierKeys.Shift;
modifierKeys |= ModifierKeys.Shift;
}
if (Win)
{
modifierKeys = modifierKeys | ModifierKeys.Windows;
modifierKeys |= ModifierKeys.Windows;
}
if (Ctrl)
{
modifierKeys = modifierKeys | ModifierKeys.Control;
modifierKeys |= ModifierKeys.Control;
}
return modifierKeys;
}
@ -86,7 +87,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey
Ctrl = true;
keys.Remove("Ctrl");
}
if (keys.Count > 0)
if (keys.Count == 1)
{
string charKey = keys[0];
KeyValuePair<Key, string>? specialSymbolPair = specialSymbolDictionary.FirstOrDefault(pair => pair.Value == charKey);
@ -110,36 +111,75 @@ namespace Flow.Launcher.Infrastructure.Hotkey
public override string ToString()
{
string text = string.Empty;
List<string> keys = new List<string>();
if (Ctrl)
{
text += "Ctrl + ";
keys.Add("Ctrl");
}
if (Alt)
{
text += "Alt + ";
keys.Add("Alt");
}
if (Shift)
{
text += "Shift + ";
keys.Add("Shift");
}
if (Win)
{
text += "Win + ";
keys.Add("Win");
}
if (CharKey != Key.None)
{
text += specialSymbolDictionary.ContainsKey(CharKey)
keys.Add(specialSymbolDictionary.ContainsKey(CharKey)
? specialSymbolDictionary[CharKey]
: CharKey.ToString();
}
else if (!string.IsNullOrEmpty(text))
{
text = text.Remove(text.Length - 3);
: CharKey.ToString());
}
return string.Join(" + ", keys);
}
return text;
public bool Validate()
{
switch (CharKey)
{
case Key.LeftAlt:
case Key.RightAlt:
case Key.LeftCtrl:
case Key.RightCtrl:
case Key.LeftShift:
case Key.RightShift:
case Key.LWin:
case Key.RWin:
return false;
default:
if (ModifierKeys == ModifierKeys.None)
{
return !((CharKey >= Key.A && CharKey <= Key.Z) ||
(CharKey >= Key.D0 && CharKey <= Key.D9) ||
(CharKey >= Key.NumPad0 && CharKey <= Key.NumPad9));
}
else
{
return CharKey != Key.None;
}
}
}
public override bool Equals(object obj)
{
if (obj is HotkeyModel other)
{
return ModifierKeys == other.ModifierKeys && CharKey == other.CharKey;
}
else
{
return false;
}
}
public override int GetHashCode()
{
return HashCode.Combine(ModifierKeys, CharKey);
}
}
}

View file

@ -1,4 +1,5 @@
using System;
#nullable enable
using System;
using System.Globalization;
using System.IO;
using System.Text.Json;
@ -11,62 +12,73 @@ namespace Flow.Launcher.Infrastructure.Storage
/// </summary>
public class JsonStorage<T> where T : new()
{
protected T _data;
protected T? Data;
// need a new directory name
public const string DirectoryName = "Settings";
public const string FileSuffix = ".json";
public string FilePath { get; set; }
public string DirectoryPath { get; set; }
protected string FilePath { get; init; } = null!;
private string TempFilePath => $"{FilePath}.tmp";
private string BackupFilePath => $"{FilePath}.bak";
protected string DirectoryPath { get; init; } = null!;
public T Load()
{
string? serialized = null;
if (File.Exists(FilePath))
{
var serialized = File.ReadAllText(FilePath);
if (!string.IsNullOrWhiteSpace(serialized))
serialized = File.ReadAllText(FilePath);
}
if (!string.IsNullOrEmpty(serialized))
{
try
{
Deserialize(serialized);
Data = JsonSerializer.Deserialize<T>(serialized)?? TryLoadBackup() ?? LoadDefault();
}
else
catch (JsonException)
{
LoadDefault();
Data = TryLoadBackup() ?? LoadDefault();
}
}
else
{
LoadDefault();
Data = TryLoadBackup() ?? LoadDefault();
}
return _data.NonNull();
return Data.NonNull();
}
private void Deserialize(string serialized)
{
try
{
_data = JsonSerializer.Deserialize<T>(serialized);
}
catch (JsonException e)
{
LoadDefault();
Log.Exception($"|JsonStorage.Deserialize|Deserialize error for json <{FilePath}>", e);
}
if (_data == null)
{
LoadDefault();
}
}
private void LoadDefault()
private T LoadDefault()
{
if (File.Exists(FilePath))
{
BackupOriginFile();
}
_data = new T();
Save();
return new T();
}
private T? TryLoadBackup()
{
if (!File.Exists(BackupFilePath))
return default;
try
{
var data = JsonSerializer.Deserialize<T>(File.ReadAllText(BackupFilePath));
if (data != null)
{
Log.Info($"|JsonStorage.Load|Failed to load settings.json, {BackupFilePath} restored successfully");
File.Replace(BackupFilePath, FilePath, null);
return data;
}
return default;
}
catch (JsonException)
{
return default;
}
}
private void BackupOriginFile()
@ -82,13 +94,14 @@ namespace Flow.Launcher.Infrastructure.Storage
public void Save()
{
string serialized = JsonSerializer.Serialize(_data, new JsonSerializerOptions() { WriteIndented = true });
string serialized = JsonSerializer.Serialize(Data, new JsonSerializerOptions
{
WriteIndented = true
});
File.WriteAllText(FilePath, serialized);
File.WriteAllText(TempFilePath, serialized);
File.Replace(TempFilePath, FilePath, BackupFilePath);
File.Delete(TempFilePath);
}
}
[Obsolete("Deprecated as of Flow Launcher v1.8.0, on 2021.06.21. " +
"This is used only for Everything plugin v1.4.9 or below backwards compatibility")]
public class JsonStrorage<T> : JsonStorage<T> where T : new() { }
}

View file

@ -18,7 +18,7 @@ namespace Flow.Launcher.Infrastructure.Storage
public PluginJsonStorage(T data) : this()
{
_data = data;
Data = data;
}
}
}

View file

@ -13,6 +13,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public class Settings : BaseModel
{
private string language = "en";
private string _theme = Constant.DefaultTheme;
public string Hotkey { get; set; } = $"{KeyConstant.Alt} + {KeyConstant.Space}";
public string OpenResultModifiers { get; set; } = KeyConstant.Alt;
public string ColorScheme { get; set; } = "System";
@ -29,7 +30,18 @@ namespace Flow.Launcher.Infrastructure.UserSettings
OnPropertyChanged();
}
}
public string Theme { get; set; } = Constant.DefaultTheme;
public string Theme
{
get => _theme;
set
{
if (value == _theme)
return;
_theme = value;
OnPropertyChanged();
OnPropertyChanged(nameof(MaxResultsToShow));
}
}
public bool UseDropShadowEffect { get; set; } = false;
public string QueryBoxFont { get; set; } = FontFamily.GenericSansSerif.Name;
public string QueryBoxFontStyle { get; set; }
@ -192,8 +204,10 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public ObservableCollection<CustomShortcutModel> CustomShortcuts { get; set; } = new ObservableCollection<CustomShortcutModel>();
[JsonIgnore]
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new ObservableCollection<BuiltinShortcutModel>() {
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText)
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new()
{
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText),
new BuiltinShortcutModel("{active_explorer_path}", "shortcut_active_explorer_path", FileExplorerHelper.GetActiveExplorerPath)
};
public bool DontPromptUpdateMsg { get; set; }
@ -212,7 +226,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
}
}
public bool LeaveCmdOpen { get; set; }
public bool HideWhenDeactive { get; set; } = true;
public bool HideWhenDeactivated { get; set; } = true;
public SearchWindowPositions SearchWindowPosition { get; set; } = SearchWindowPositions.MouseScreenCenter;
public bool IgnoreHotkeysOnFullscreen { get; set; }

View file

@ -14,10 +14,10 @@
</PropertyGroup>
<PropertyGroup>
<Version>3.0.1</Version>
<PackageVersion>3.0.1</PackageVersion>
<AssemblyVersion>3.0.1</AssemblyVersion>
<FileVersion>3.0.1</FileVersion>
<Version>3.1.0</Version>
<PackageVersion>3.1.0</PackageVersion>
<AssemblyVersion>3.1.0</AssemblyVersion>
<FileVersion>3.1.0</FileVersion>
<PackageId>Flow.Launcher.Plugin</PackageId>
<Authors>Flow-Launcher</Authors>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
@ -66,7 +66,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="JetBrains.Annotations" Version="2021.2.0" />
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" />
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
</ItemGroup>

View file

@ -242,7 +242,7 @@ namespace Flow.Launcher.Plugin
/// </summary>
public string PreviewImagePath { get; set; }
/// <summary>
/// Determines if the preview image should occupy the full width of the preveiw panel.
/// Determines if the preview image should occupy the full width of the preview panel.
/// </summary>
public bool IsMedia { get; set; }
public string Description { get; set; }

View file

@ -1,7 +1,9 @@
using System;
using System.Diagnostics;
using System.IO;
#pragma warning disable IDE0005
using System.Windows;
#pragma warning restore IDE0005
namespace Flow.Launcher.Plugin.SharedCommands
{
@ -206,22 +208,16 @@ namespace Flow.Launcher.Plugin.SharedCommands
///</summary>
public static string GetPreviousExistingDirectory(Func<string, bool> locationExists, string path)
{
var previousDirectoryPath = "";
var index = path.LastIndexOf('\\');
if (index > 0 && index < (path.Length - 1))
{
previousDirectoryPath = path.Substring(0, index + 1);
if (!locationExists(previousDirectoryPath))
{
return "";
}
string previousDirectoryPath = path.Substring(0, index + 1);
return locationExists(previousDirectoryPath) ? previousDirectoryPath : "";
}
else
{
return "";
}
return previousDirectoryPath;
}
///<summary>
@ -241,5 +237,33 @@ namespace Flow.Launcher.Plugin.SharedCommands
return path;
}
/// <summary>
/// Returns if <paramref name="parentPath"/> contains <paramref name="subPath"/>.
/// From https://stackoverflow.com/a/66877016
/// </summary>
/// <param name="parentPath">Parent path</param>
/// <param name="subPath">Sub path</param>
/// <param name="allowEqual">If <see langword="true"/>, when <paramref name="parentPath"/> and <paramref name="subPath"/> are equal, returns <see langword="true"/></param>
/// <returns></returns>
public static bool PathContains(string parentPath, string subPath, bool allowEqual = false)
{
var rel = Path.GetRelativePath(parentPath.EnsureTrailingSlash(), subPath);
return (rel != "." || allowEqual)
&& rel != ".."
&& !rel.StartsWith("../")
&& !rel.StartsWith(@"..\")
&& !Path.IsPathRooted(rel);
}
/// <summary>
/// Returns path ended with "\"
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string EnsureTrailingSlash(this string path)
{
return path.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
}
}
}

View file

@ -0,0 +1,53 @@
using Flow.Launcher.Plugin.SharedCommands;
using NUnit.Framework;
namespace Flow.Launcher.Test
{
[TestFixture]
public class FilesFoldersTest
{
// Testcases from https://stackoverflow.com/a/31941905/20703207
// Disk
[TestCase(@"c:", @"c:\foo", true)]
[TestCase(@"c:\", @"c:\foo", true)]
// Slash
[TestCase(@"c:\foo\bar\", @"c:\foo\", false)]
[TestCase(@"c:\foo\bar", @"c:\foo\", false)]
[TestCase(@"c:\foo", @"c:\foo\bar", true)]
[TestCase(@"c:\foo\", @"c:\foo\bar", true)]
// File
[TestCase(@"c:\foo", @"c:\foo\a.txt", true)]
[TestCase(@"c:\foo", @"c:/foo/a.txt", true)]
[TestCase(@"c:\FOO\a.txt", @"c:\foo", false)]
[TestCase(@"c:\foo\a.txt", @"c:\foo\", false)]
[TestCase(@"c:\foobar\a.txt", @"c:\foo", false)]
[TestCase(@"c:\foobar\a.txt", @"c:\foo\", false)]
[TestCase(@"c:\foo\", @"c:\foo.txt", false)]
// Prefix
[TestCase(@"c:\foo", @"c:\foobar", false)]
[TestCase(@"C:\Program", @"C:\Program Files\", false)]
[TestCase(@"c:\foobar", @"c:\foo\a.txt", false)]
[TestCase(@"c:\foobar\", @"c:\foo\a.txt", false)]
// Edge case
[TestCase(@"c:\foo", @"c:\foo\..\bar\baz", false)]
[TestCase(@"c:\bar", @"c:\foo\..\bar\baz", true)]
[TestCase(@"c:\barr", @"c:\foo\..\bar\baz", false)]
// Equality
[TestCase(@"c:\foo", @"c:\foo", false)]
[TestCase(@"c:\foo\", @"c:\foo", false)]
[TestCase(@"c:\foo", @"c:\foo\", false)]
public void GivenTwoPaths_WhenCheckPathContains_ThenShouldBeExpectedResult(string parentPath, string path, bool expectedResult)
{
Assert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path));
}
[TestCase(@"c:\foo", @"c:\foo", true)]
[TestCase(@"c:\foo\", @"c:\foo", true)]
[TestCase(@"c:\foo", @"c:\foo\", true)]
public void GivenTwoPathsAreTheSame_WhenCheckPathContains_ThenShouldBeTrue(string parentPath, string path, bool expectedResult)
{
Assert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path, true));
}
}
}

View file

@ -48,9 +48,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="nunit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1">
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View file

@ -7,9 +7,11 @@ using Flow.Launcher.Plugin.SharedCommands;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using static Flow.Launcher.Plugin.Explorer.Search.SearchManager;
namespace Flow.Launcher.Test.Plugins
{
@ -176,7 +178,7 @@ namespace Flow.Launcher.Test.Plugins
var searchManager = new SearchManager(new Settings(), new PluginInitContext());
// When
var result = SearchManager.IsFileContentSearch(query.ActionKeyword);
var result = searchManager.IsFileContentSearch(query.ActionKeyword);
// Then
Assert.IsTrue(result,
@ -193,6 +195,7 @@ namespace Flow.Launcher.Test.Plugins
[TestCase(@"c:\>*", true)]
[TestCase(@"c:\>", true)]
[TestCase(@"c:\SomeLocation\SomeOtherLocation\>", true)]
[TestCase(@"c:\SomeLocation\SomeOtherLocation", true)]
public void WhenGivenQuerySearchString_ThenShouldIndicateIfIsLocationPathString(string querySearchString, bool expectedResult)
{
// When, Given
@ -393,5 +396,68 @@ namespace Flow.Launcher.Test.Plugins
// Then
Assert.AreEqual(result, expectedResult);
}
[TestCase(@"c:\foo", @"c:\foo", true)]
[TestCase(@"C:\Foo\", @"c:\foo\", true)]
[TestCase(@"c:\foo", @"c:\foo\", false)]
public void GivenTwoPaths_WhenCompared_ThenShouldBeExpectedSameOrDifferent(string path1, string path2, bool expectedResult)
{
// Given
var comparator = PathEqualityComparator.Instance;
var result1 = new Result
{
Title = Path.GetFileName(path1),
SubTitle = path1
};
var result2 = new Result
{
Title = Path.GetFileName(path2),
SubTitle = path2
};
// When, Then
Assert.AreEqual(expectedResult, comparator.Equals(result1, result2));
}
[TestCase(@"c:\foo\", @"c:\foo\")]
[TestCase(@"C:\Foo\", @"c:\foo\")]
public void GivenTwoPaths_WhenComparedHasCode_ThenShouldBeSame(string path1, string path2)
{
// Given
var comparator = PathEqualityComparator.Instance;
var result1 = new Result
{
Title = Path.GetFileName(path1),
SubTitle = path1
};
var result2 = new Result
{
Title = Path.GetFileName(path2),
SubTitle = path2
};
var hash1 = comparator.GetHashCode(result1);
var hash2 = comparator.GetHashCode(result2);
// When, Then
Assert.IsTrue(hash1 == hash2);
}
[TestCase(@"%appdata%", true)]
[TestCase(@"%appdata%\123", true)]
[TestCase(@"c:\foo %appdata%\", false)]
[TestCase(@"c:\users\%USERNAME%\downloads", true)]
[TestCase(@"c:\downloads", false)]
[TestCase(@"%", false)]
[TestCase(@"%%", false)]
[TestCase(@"%bla%blabla%", false)]
public void GivenPath_WhenHavingEnvironmentVariableOrNot_ThenShouldBeExpected(string path, bool expectedResult)
{
// When
var result = EnvironmentVariables.HasEnvironmentVar(path);
// Then
Assert.AreEqual(result, expectedResult);
}
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
@ -84,14 +85,14 @@ namespace Flow.Launcher
Current.MainWindow = window;
Current.MainWindow.Title = Constant.FlowLauncher;
HotKeyMapper.Initialize(_mainVM);
// happlebao todo temp fix for instance code logic
// todo temp fix for instance code logic
// load plugin before change language, because plugin language also needs be changed
InternationalizationManager.Instance.Settings = _settings;
InternationalizationManager.Instance.ChangeLanguage(_settings.Language);
// main windows needs initialized before theme change because of blur settigns
// main windows needs initialized before theme change because of blur settings
ThemeManager.Instance.Settings = _settings;
ThemeManager.Instance.ChangeTheme(_settings.Theme);
@ -130,20 +131,17 @@ namespace Flow.Launcher
//[Conditional("RELEASE")]
private void AutoUpdates()
{
Task.Run(async () =>
_ = Task.Run(async () =>
{
if (_settings.AutoUpdates)
{
// check udpate every 5 hours
var timer = new Timer(1000 * 60 * 60 * 5);
timer.Elapsed += async (s, e) =>
{
await _updater.UpdateAppAsync(API);
};
timer.Start();
// check updates on startup
// check update every 5 hours
var timer = new PeriodicTimer(TimeSpan.FromHours(5));
await _updater.UpdateAppAsync(API);
while (await timer.WaitForNextTickAsync())
// check updates on startup
await _updater.UpdateAppAsync(API);
}
});
}

View file

@ -0,0 +1,25 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Flow.Launcher.Converters
{
public class DiameterToCenterPointConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double d)
{
return new Point(d / 2, d / 2);
}
return new Point(0, 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

View file

@ -0,0 +1,27 @@
using System;
using System.Globalization;
using System.Windows.Data;
using Windows.Devices.PointOfService;
namespace Flow.Launcher.Converters
{
public class IconRadiusConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length != 2)
throw new ArgumentException("IconRadiusConverter must have 2 parameters");
return values[1] switch
{
true => (double)values[0] / 2,
false => (double)values[0],
_ => throw new ArgumentException("The second argument should be boolean", nameof(values))
};
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

View file

@ -90,7 +90,7 @@
</PackageReference>
<PackageReference Include="InputSimulator" Version="1.0.4" />
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
<PackageReference Include="ModernWpfUI" Version="0.9.4" />
<PackageReference Include="ModernWpfUI" Version="0.9.6" />
<PackageReference Include="NHotkey.Wpf" Version="2.1.0" />
<PackageReference Include="NuGet.CommandLine" Version="6.3.1">
<PrivateAssets>all</PrivateAssets>

View file

@ -48,6 +48,7 @@
Margin="0,0,18,0"
VerticalContentAlignment="Center"
input:InputMethod.IsInputMethodEnabled="False"
GotFocus="tbHotkey_GotFocus"
LostFocus="tbHotkey_LostFocus"
PreviewKeyDown="TbHotkey_OnPreviewKeyDown"
TabIndex="100" />

View file

@ -9,16 +9,11 @@ using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Plugin;
using System.Threading;
using System.Windows.Interop;
namespace Flow.Launcher
{
public partial class HotkeyControl : UserControl
{
private Brush tbMsgForegroundColorOriginal;
private string tbMsgTextOriginal;
public HotkeyModel CurrentHotkey { get; private set; }
public bool CurrentHotkeyAvailable { get; private set; }
@ -29,8 +24,6 @@ namespace Flow.Launcher
public HotkeyControl()
{
InitializeComponent();
tbMsgTextOriginal = tbMsg.Text;
tbMsgForegroundColorOriginal = tbMsg.Foreground;
}
private CancellationTokenSource hotkeyUpdateSource;
@ -55,9 +48,7 @@ namespace Flow.Launcher
specialKeyState.CtrlPressed,
key);
var hotkeyString = hotkeyModel.ToString();
if (hotkeyString == tbHotkey.Text)
if (hotkeyModel.Equals(CurrentHotkey))
{
return;
}
@ -72,33 +63,32 @@ namespace Flow.Launcher
public async Task SetHotkeyAsync(HotkeyModel keyModel, bool triggerValidate = true)
{
CurrentHotkey = keyModel;
tbHotkey.Text = CurrentHotkey.ToString();
tbHotkey.Text = keyModel.ToString();
tbHotkey.Select(tbHotkey.Text.Length, 0);
if (triggerValidate)
{
CurrentHotkeyAvailable = CheckHotkeyAvailability();
if (!CurrentHotkeyAvailable)
{
tbMsg.Foreground = new SolidColorBrush(Colors.Red);
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("hotkeyUnavailable");
}
else
{
tbMsg.Foreground = new SolidColorBrush(Colors.Green);
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("success");
}
tbMsg.Visibility = Visibility.Visible;
bool hotkeyAvailable = CheckHotkeyAvailability(keyModel);
CurrentHotkeyAvailable = hotkeyAvailable;
SetMessage(hotkeyAvailable);
OnHotkeyChanged();
var token = hotkeyUpdateSource.Token;
await Task.Delay(500, token);
if (token.IsCancellationRequested)
return;
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(this), null);
Keyboard.ClearFocus();
if (CurrentHotkeyAvailable)
{
CurrentHotkey = keyModel;
// To trigger LostFocus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(this), null);
Keyboard.ClearFocus();
}
}
else
{
CurrentHotkey = keyModel;
}
}
@ -107,14 +97,40 @@ namespace Flow.Launcher
return SetHotkeyAsync(new HotkeyModel(keyStr), triggerValidate);
}
private bool CheckHotkeyAvailability() => HotKeyMapper.CheckAvailability(CurrentHotkey);
private static bool CheckHotkeyAvailability(HotkeyModel hotkey) => hotkey.Validate() && HotKeyMapper.CheckAvailability(hotkey);
public new bool IsFocused => tbHotkey.IsFocused;
private void tbHotkey_LostFocus(object sender, RoutedEventArgs e)
{
tbMsg.Text = tbMsgTextOriginal;
tbHotkey.Text = CurrentHotkey.ToString();
tbHotkey.Select(tbHotkey.Text.Length, 0);
}
private void tbHotkey_GotFocus(object sender, RoutedEventArgs e)
{
ResetMessage();
}
private void ResetMessage()
{
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("flowlauncherPressHotkey");
tbMsg.SetResourceReference(TextBox.ForegroundProperty, "Color05B");
}
private void SetMessage(bool hotkeyAvailable)
{
if (!hotkeyAvailable)
{
tbMsg.Foreground = new SolidColorBrush(Colors.Red);
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("hotkeyUnavailable");
}
else
{
tbMsg.Foreground = new SolidColorBrush(Colors.Green);
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("success");
}
tbMsg.Visibility = Visibility.Visible;
}
}
}

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">Om</system:String>
<system:String x:Key="website">Website</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Version</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Tilpasset søgegenvejstast</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Vis</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Genvejstast er utilgængelig, vælg venligst en ny genvejstast</system:String>
<system:String x:Key="invalidPluginHotkey">Ugyldig plugin genvejstast</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">Über</system:String>
<system:String x:Key="website">Webseite</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Dokumentation</system:String>
<system:String x:Key="version">Version</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Benutzerdefinierte Abfrage Tastenkombination</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Vorschau</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Tastenkombination ist nicht verfügbar, bitte wähle eine andere Tastenkombination</system:String>
<system:String x:Key="invalidPluginHotkey">Ungültige Plugin Tastenkombination</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -176,6 +176,7 @@
<system:String x:Key="deleteCustomHotkeyWarning">Are you sure you want to delete {0} plugin hotkey?</system:String>
<system:String x:Key="deleteCustomShortcutWarning">Are you sure you want to delete shortcut: {0} with expansion {1}?</system:String>
<system:String x:Key="shortcut_clipboard_description">Get text from clipboard.</system:String>
<system:String x:Key="shortcut_active_explorer_path">Get path from active explorer.</system:String>
<system:String x:Key="queryWindowShadowEffect">Query window shadow effect</system:String>
<system:String x:Key="shadowEffectCPUUsage">Shadow effect has a substantial usage of GPU. Not recommended if your computer performance is limited.</system:String>
<system:String x:Key="windowWidthSize">Window Width Size</system:String>
@ -203,7 +204,7 @@
<!-- Setting About -->
<system:String x:Key="about">About</system:String>
<system:String x:Key="website">Website</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Version</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -264,7 +265,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Custom Query Hotkey</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Preview</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Hotkey is unavailable, please select a new hotkey</system:String>
<system:String x:Key="invalidPluginHotkey">Invalid plugin hotkey</system:String>
@ -338,7 +339,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Atajo de teclado de consulta personalizada</system:String>
<system:String x:Key="customeQueryHotkeyTips">Pulse el atajo de teclado personalizado para abrir Flow Laucher y realizar automáticamente la consulta especificada.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Pulse el atajo de teclado personalizado para abrir Flow Launcher y realizar automáticamente la consulta especificada.</system:String>
<system:String x:Key="preview">Vista previa</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">El atajo de teclado no está disponible, por favor seleccione uno nuevo</system:String>
<system:String x:Key="invalidPluginHotkey">Atajo de teclado de complemento no válido</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">À propos</system:String>
<system:String x:Key="website">Website</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Version</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -261,7 +261,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Requêtes personnalisées</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Prévisualiser</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Raccourci indisponible. Veuillez en choisir un autre.</system:String>
<system:String x:Key="invalidPluginHotkey">Raccourci invalide</system:String>
@ -335,7 +335,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">Informazioni</system:String>
<system:String x:Key="website">Sito web</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Documentazione</system:String>
<system:String x:Key="version">Versione</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Tasti scelta rapida per ricerche personalizzate</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Anteprima</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Tasto di scelta rapida non disponibile, per favore scegli un nuovo tasto di scelta rapida</system:String>
<system:String x:Key="invalidPluginHotkey">Tasto di scelta rapida plugin non valido</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Indietro / Menu contestuale</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Navigazione tra le voci</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Apri il menu di scelta rapida</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Apri la cartella Contaning</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Apri cartella superiore</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Esegui come amministratore</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Cronologia Query</system:String>
<system:String x:Key="HotkeyESCDesc">Torna al risultato nel menu contestuale</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">Flow Launcherについて</system:String>
<system:String x:Key="website">ウェブサイト</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">バージョン</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle"></system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">プレビュー</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">ホットキーは使用できません。新しいホットキーを選択してください</system:String>
<system:String x:Key="invalidPluginHotkey">プラグインホットキーは無効です</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">정보</system:String>
<system:String x:Key="website">웹사이트</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">문서</system:String>
<system:String x:Key="version">버전</system:String>
<system:String x:Key="icons">아이콘</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">사용자지정 쿼리 단축키</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">미리보기</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">단축키를 사용할 수 없습니다. 다른 단축키를 입력하세요.</system:String>
<system:String x:Key="invalidPluginHotkey">플러그인 단축키가 유효하지 않습니다.</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">About</system:String>
<system:String x:Key="website">Website</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Version</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Custom Query Hotkey</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Preview</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Hotkey is unavailable, please select a new hotkey</system:String>
<system:String x:Key="invalidPluginHotkey">Invalid plugin hotkey</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">About</system:String>
<system:String x:Key="website">Website</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Versie</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Custom Query Sneltoets</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Voorbeeld</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Sneltoets is niet beschikbaar, selecteer een nieuwe sneltoets</system:String>
<system:String x:Key="invalidPluginHotkey">Ongeldige plugin sneltoets</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">O programie</system:String>
<system:String x:Key="website">Website</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Wersja</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Skrót klawiszowy niestandardowych zapyta</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Podgląd</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Skrót klawiszowy jest niedostępny, musisz podać inny skrót klawiszowy</system:String>
<system:String x:Key="invalidPluginHotkey">Niepoprawny skrót klawiszowy</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">Sobre</system:String>
<system:String x:Key="website">Website</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Versão</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Atalho de Consulta Personalizada</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Prévia</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Atalho indisponível, escolha outro</system:String>
<system:String x:Key="invalidPluginHotkey">Atalho de plugin inválido</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -335,7 +335,7 @@ Queira por favor mover a pasta do seu perfil de {0} para {1}
<system:String x:Key="HotkeyUpDownDesc">Recuar/Menu de contexto</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Navegação nos itens</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Abrir menu de contexto</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Abrir pasta</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Abrir pasta do resultado</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Executar como administrador</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Histórico de consultas</system:String>
<system:String x:Key="HotkeyESCDesc">Voltar aos resultados no menu de contexto</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">О Flow Launcher</system:String>
<system:String x:Key="website">Website</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Версия</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Задаваемые горячие клавиши для запросов</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Предпросмотр</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Горячая клавиша недоступна. Пожалуйста, задайте новую</system:String>
<system:String x:Key="invalidPluginHotkey">Недействительная горячая клавиша плагина</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">O aplikácii</system:String>
<system:String x:Key="website">Webstránka</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Dokumentácia</system:String>
<system:String x:Key="version">Verzia</system:String>
<system:String x:Key="icons">Ikony</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Klávesová skratka vlastného vyhľadávania</system:String>
<system:String x:Key="customeQueryHotkeyTips">Stlačením vlastnej klávesovej skratky otvoríte Flow Laucher a automaticky vložíte zadaný dotaz.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Stlačením vlastnej klávesovej skratky otvoríte Flow Launcher a automaticky vložíte zadaný dotaz.</system:String>
<system:String x:Key="preview">Náhľad</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Klávesová skratka je nedostupná, prosím, zadajte novú skratku</system:String>
<system:String x:Key="invalidPluginHotkey">Neplatná klávesová skratka pluginu</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">O Flow Launcher-u</system:String>
<system:String x:Key="website">Website</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Verzija</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">prečica za ručno dodat upit</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Pregled</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Prečica je nedustupna, molim Vas izaberite drugu prečicu</system:String>
<system:String x:Key="invalidPluginHotkey">Nepravlna prečica za plugin</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">Hakkında</system:String>
<system:String x:Key="website">Website</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Sürüm</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -234,7 +234,7 @@
<system:String x:Key="fileManager_file_arg">Arg For File</system:String>
<!-- DefaultBrowser Setting Dialog -->
<system:String x:Key="defaultBrowserTitle">Default Web Browser</system:String>
<system:String x:Key="defaultBrowserTitle">Varsayılan İnternet Tarayıcısı</system:String>
<system:String x:Key="defaultBrowser_tips">The default setting follows the OS default browser setting. If specified separately, flow uses that browser.</system:String>
<system:String x:Key="defaultBrowser_name">Browser</system:String>
<system:String x:Key="defaultBrowser_profile_name">Browser Name</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Özel Sorgu Kısayolları</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Önizleme</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Kısayol tuşu kullanılabilir değil, lütfen başka bir kısayol tuşu seçin</system:String>
<system:String x:Key="invalidPluginHotkey">Geçersiz eklenti kısayol tuşu</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">Про Flow Launcher</system:String>
<system:String x:Key="website">Website</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Версія</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">Задані гарячі клавіші для запитів</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">Переглянути</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">Гаряча клавіша недоступна. Будь ласка, вкажіть нову</system:String>
<system:String x:Key="invalidPluginHotkey">Недійсна гаряча клавіша плагіна</system:String>
@ -336,7 +336,7 @@
<system:String x:Key="HotkeyUpDownDesc">Back / Context Menu</system:String>
<system:String x:Key="HotkeyLeftRightDesc">Item Navigation</system:String>
<system:String x:Key="HotkeyShiftEnterDesc">Open Context Menu</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Contaning Folder</system:String>
<system:String x:Key="HotkeyCtrlEnterDesc">Open Containing Folder</system:String>
<system:String x:Key="HotkeyCtrlShiftEnterDesc">Run as Admin</system:String>
<system:String x:Key="HotkeyCtrlHDesc">Query History</system:String>
<system:String x:Key="HotkeyESCDesc">Back to Result in Context Menu</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">关于</system:String>
<system:String x:Key="website">官方网站</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">文档</system:String>
<system:String x:Key="version">版本</system:String>
<system:String x:Key="icons">图标</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">自定义查询热键</system:String>
<system:String x:Key="customeQueryHotkeyTips">输入一个自定义的快捷键来打开 Flow Laucher 并自动输入指定的查询。</system:String>
<system:String x:Key="customeQueryHotkeyTips">输入一个自定义的快捷键来打开 Flow Launcher 并自动输入指定的查询。</system:String>
<system:String x:Key="preview">预览</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">热键不可用,请选择一个新的热键</system:String>
<system:String x:Key="invalidPluginHotkey">插件热键不合法</system:String>

View file

@ -201,7 +201,7 @@
<!-- Setting About -->
<system:String x:Key="about">關於</system:String>
<system:String x:Key="website">官方網站</system:String>
<system:String x:Key="github">Github</system:String>
<system:String x:Key="github">GitHub</system:String>
<system:String x:Key="docs">文檔</system:String>
<system:String x:Key="version">版本</system:String>
<system:String x:Key="icons">Icons</system:String>
@ -262,7 +262,7 @@
<!-- Custom Query Hotkey Dialog -->
<system:String x:Key="customeQueryHotkeyTitle">自定義快捷鍵查詢</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Laucher and input the specified query automatically.</system:String>
<system:String x:Key="customeQueryHotkeyTips">Press a custom hotkey to open Flow Launcher and input the specified query automatically.</system:String>
<system:String x:Key="preview">預覽</system:String>
<system:String x:Key="hotkeyIsNotUnavailable">快捷鍵不存在,請設定一個新的快捷鍵</system:String>
<system:String x:Key="invalidPluginHotkey">外掛熱鍵無法使用</system:String>

View file

@ -9,11 +9,11 @@
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
xmlns:ui="http://schemas.modernwpf.com/2019"
xmlns:vm="clr-namespace:Flow.Launcher.ViewModel"
d:DataContext="{d:DesignInstance Type=vm:MainViewModel}"
Name="FlowMainWindow"
Title="Flow Launcher"
MinWidth="{Binding MainWindowWidth, Mode=OneWay}"
MaxWidth="{Binding MainWindowWidth, Mode=OneWay}"
d:DataContext="{d:DesignInstance Type=vm:MainViewModel}"
AllowDrop="True"
AllowsTransparency="True"
Background="Transparent"
@ -38,9 +38,9 @@
<converters:QuerySuggestionBoxConverter x:Key="QuerySuggestionBoxConverter" />
<converters:BorderClipConverter x:Key="BorderClipConverter" />
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<converters:BoolToIMEConversionModeConverter x:Key="BoolToIMEConversionModeConverter"/>
<converters:BoolToIMEStateConverter x:Key="BoolToIMEStateConverter"/>
<converters:StringToKeyBindingConverter x:Key="StringToKeyBindingConverter"/>
<converters:BoolToIMEConversionModeConverter x:Key="BoolToIMEConversionModeConverter" />
<converters:BoolToIMEStateConverter x:Key="BoolToIMEStateConverter" />
<converters:StringToKeyBindingConverter x:Key="StringToKeyBindingConverter" />
</Window.Resources>
<Window.InputBindings>
<KeyBinding Key="Escape" Command="{Binding EscCommand}" />
@ -180,11 +180,11 @@
<KeyBinding
Key="F12"
Command="{Binding ToggleGameModeCommand}"
Modifiers="Ctrl"/>
Modifiers="Ctrl" />
<KeyBinding
Key="{Binding PreviewHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
Command="{Binding TogglePreviewCommand}"
Modifiers="{Binding PreviewHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}"/>
Modifiers="{Binding PreviewHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
</Window.InputBindings>
<Grid>
<Border MouseDown="OnMouseDown" Style="{DynamicResource WindowBorderStyle}">
@ -207,12 +207,12 @@
<TextBox
x:Name="QueryTextBox"
AllowDrop="True"
InputMethod.PreferredImeConversionMode="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEConversionModeConverter}}"
InputMethod.PreferredImeState="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEStateConverter}}"
PreviewDragOver="OnPreviewDragOver"
PreviewKeyUp="QueryTextBox_KeyUp"
Style="{DynamicResource QueryBoxStyle}"
Text="{Binding QueryText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
InputMethod.PreferredImeConversionMode="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEConversionModeConverter}}"
InputMethod.PreferredImeState="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEStateConverter}}"
Visibility="Visible">
<TextBox.CommandBindings>
<CommandBinding Command="ApplicationCommands.Copy" Executed="OnCopy" />
@ -273,9 +273,6 @@
<Grid>
<Image
x:Name="PluginActivationIcon"
Width="32"
Height="32"
Margin="0,0,18,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Panel.ZIndex="2"
@ -403,10 +400,10 @@
VerticalAlignment="Stretch"
Style="{DynamicResource PreviewArea}"
Visibility="{Binding PreviewVisible, Converter={StaticResource BoolToVisibilityConverter}}">
<Border
Style="{DynamicResource PreviewBorderStyle}"
<Border
d:DataContext="{d:DesignInstance vm:ResultViewModel}"
DataContext="{Binding SelectedItem, ElementName=ResultListBox}"
Style="{DynamicResource PreviewBorderStyle}"
Visibility="{Binding ShowDefaultPreview}">
<Grid
Margin="20,0,10,0"
@ -478,10 +475,10 @@
</StackPanel>
</Grid>
</Border>
<Border
<Border
d:DataContext="{d:DesignInstance vm:ResultViewModel}"
DataContext="{Binding SelectedItem, ElementName=ResultListBox}"
Style="{DynamicResource PreviewBorderStyle}"
Style="{DynamicResource PreviewBorderStyle}"
Visibility="{Binding ShowCustomizedPreview}">
<ContentControl Content="{Binding Result.PreviewPanel.Value}" />
</Border>

View file

@ -485,7 +485,7 @@ namespace Flow.Launcher
if (_settings.UseAnimation)
await Task.Delay(100);
if (_settings.HideWhenDeactive)
if (_settings.HideWhenDeactivated)
{
_viewModel.Hide();
}

View file

@ -85,6 +85,8 @@
<ui:NumberBox
x:Name="tbAction"
Width="200"
Maximum="100"
Minimum="-100"
Margin="10,0,15,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"

View file

@ -27,7 +27,7 @@ namespace Flow.Launcher.Resources.Pages
tbMsgTextOriginal = HotkeyControl.tbMsg.Text;
tbMsgForegroundColorOriginal = HotkeyControl.tbMsg.Foreground;
HotkeyControl.SetHotkeyAsync(new Infrastructure.Hotkey.HotkeyModel(Settings.Hotkey), false);
HotkeyControl.SetHotkeyAsync(Settings.Hotkey, false);
}
private void HotkeyControl_OnGotFocus(object sender, RoutedEventArgs args)
{
@ -49,4 +49,4 @@ namespace Flow.Launcher.Resources.Pages
HotkeyControl.tbMsg.Foreground = tbMsgForegroundColorOriginal;
}
}
}
}

View file

@ -27,10 +27,14 @@
Style="{DynamicResource BaseListboxStyle}"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Standard"
Visibility="{Binding Visbility}"
Visibility="{Binding Visibility}"
mc:Ignorable="d">
<!-- IsSynchronizedWithCurrentItem: http://stackoverflow.com/a/7833798/2833083 -->
<ListBox.Resources>
<converter:IconRadiusConverter x:Key="IconRadiusConverter" />
<converter:DiameterToCenterPointConverter x:Key="DiameterToCenterPointConverter" />
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Button HorizontalAlignment="Stretch">
@ -52,7 +56,7 @@
<converter:OpenResultHotkeyVisibilityConverter x:Key="OpenResultHotkeyVisibilityConverter" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60" />
<ColumnDefinition Style="{DynamicResource ImageAreaWidth}" />
<ColumnDefinition Width="9*" />
<ColumnDefinition Width="Auto" MinWidth="8" />
</Grid.ColumnDefinitions>
@ -99,20 +103,29 @@
BorderThickness="1">
<Image
x:Name="ImageIcon"
Width="{Binding IconXY}"
Height="{Binding IconXY}"
Margin="0,0,0,0"
HorizontalAlignment="Center"
IsHitTestVisible="False"
RenderOptions.BitmapScalingMode="Fant"
Source="{Binding Image, TargetNullValue={x:Null}}"
Stretch="Uniform"
Style="{DynamicResource ImageIconStyle}"
Visibility="{Binding ShowIcon}">
<Image.Clip>
<EllipseGeometry
Center="16 16"
RadiusX="{Binding IconRadius}"
RadiusY="{Binding IconRadius}" />
<EllipseGeometry Center="{Binding ElementName=ImageIcon, Path=ActualWidth, Converter={StaticResource DiameterToCenterPointConverter}}">
<EllipseGeometry.RadiusX>
<MultiBinding Converter="{StaticResource IconRadiusConverter}">
<Binding ElementName="ImageIcon" Path="ActualWidth" />
<Binding Path="Result.RoundedIcon" />
</MultiBinding>
</EllipseGeometry.RadiusX>
<EllipseGeometry.RadiusY>
<MultiBinding Converter="{StaticResource IconRadiusConverter}">
<Binding ElementName="ImageIcon" Path="ActualWidth" />
<Binding Path="Result.RoundedIcon" />
</MultiBinding>
</EllipseGeometry.RadiusY>
</EllipseGeometry>
</Image.Clip>
</Image>
</Border>
@ -196,7 +209,6 @@
<Setter TargetName="Title" Property="Style" Value="{DynamicResource ItemTitleSelectedStyle}" />
<Setter TargetName="SubTitle" Property="Style" Value="{DynamicResource ItemSubTitleSelectedStyle}" />
<Setter TargetName="Hotkey" Property="Style" Value="{DynamicResource ItemHotkeySelectedStyle}" />
<Setter TargetName="ImageIcon" Property="Style" Value="{DynamicResource ItemImageSelectedStyle}" />
<Setter TargetName="GlyphIcon" Property="Style" Value="{DynamicResource ItemGlyphSelectedStyle}" />
</DataTrigger>
</DataTemplate.Triggers>
@ -207,7 +219,7 @@
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="MouseEnter" Handler="OnMouseEnter" />
<EventSetter Event="MouseMove" Handler="OnMouseMove" />
<Setter Property="Height" Value="52" />
<Setter Property="Height" Value="{DynamicResource ResultItemHeight}" />
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="BorderThickness" Value="0" />
@ -240,4 +252,4 @@
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</ListBox>

View file

@ -673,7 +673,7 @@
<ui:ToggleSwitch
Grid.Column="2"
FocusVisualMargin="5"
IsOn="{Binding Settings.HideWhenDeactive}"
IsOn="{Binding Settings.HideWhenDeactivated}"
Style="{DynamicResource SideToggleSwitch}" />
</ItemsControl>
</Border>
@ -1821,7 +1821,7 @@
</Border.Clip>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="54" />
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
@ -2438,7 +2438,7 @@
<Border Margin="0,8,0,0" Style="{DynamicResource SettingGroupBox}">
<ItemsControl Style="{StaticResource SettingGrid}">
<StackPanel Style="{StaticResource TextPanel}">
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource previewHotkey}"/>
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource previewHotkey}" />
<TextBlock Style="{DynamicResource SettingSubTitleLabel}" Text="{DynamicResource previewHotkeyToolTip}" />
</StackPanel>
<flowlauncher:HotkeyControl
@ -3041,7 +3041,7 @@
Name="ClearLogFolderBtn"
Margin="0,0,12,0"
Click="ClearLogFolder"
Content="{Binding CheckLogFolder, UpdateSourceTrigger=PropertyChanged}" />
Content="{Binding CheckLogFolder, Mode=OneWay}" />
<Button
Margin="0,0,8,0"
Content="&#xec7a;"

View file

@ -250,7 +250,7 @@ namespace Flow.Launcher
}
private void OpenLogFolder(object sender, RoutedEventArgs e)
{
PluginManager.API.OpenDirectory(Path.Combine(DataLocation.DataDirectory(), Constant.Logs, Constant.Version));
viewModel.OpenLogFolder();
}
private void ClearLogFolder(object sender, RoutedEventArgs e)
{
@ -262,8 +262,6 @@ namespace Flow.Launcher
if (confirmResult == MessageBoxResult.Yes)
{
viewModel.ClearLogFolder();
ClearLogFolderBtn.Content = viewModel.CheckLogFolder;
}
}

View file

@ -6,7 +6,9 @@
<CornerRadius x:Key="ItemRadius">0</CornerRadius>
<Thickness x:Key="ItemMargin">0</Thickness>
<Thickness x:Key="ResultMargin">0</Thickness>
<!-- Further font customisations are dynamically loaded in Theme.cs -->
<!-- Further font customizations are dynamically loaded in Theme.cs -->
<system:Double x:Key="ResultItemHeight">52</system:Double>
<Style x:Key="BaseBulletStyle" TargetType="{x:Type Border}" />
<Style
@ -17,6 +19,10 @@
x:Key="ItemBulletSelectedStyle"
BasedOn="{StaticResource BaseBulletStyle}"
TargetType="{x:Type Border}" />
<Style x:Key="ImageIconStyle" TargetType="{x:Type Image}">
<Setter Property="Height" Value="32" />
<Setter Property="Width" Value="32" />
</Style>
<Style x:Key="BaseQueryBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="BorderThickness" Value="0" />
@ -301,7 +307,7 @@
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
<!-- Scrollbar in thr rigth of ScrollViewer -->
<!-- Scrollbar in the right of ScrollViewer -->
<ScrollBar
x:Name="PART_VerticalScrollBar"
Grid.Row="0"
@ -385,6 +391,12 @@
<Setter Property="FontSize" Value="15" />
<Setter Property="Foreground" Value="#8f8f8f" />
</Style>
<Style x:Key="BaseItemHotkeySelectedStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="15" />
<Setter Property="Foreground" Value="#8f8f8f" />
</Style>
<!-- DO NOT USE THIS KEY. this key for themes with wrong typo. This key should be removed. Right key is BaseItemHotkeySelectedStyle. -->
<Style x:Key="BaseItemHotkeySelecetedStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="15" />
<Setter Property="Foreground" Value="#8f8f8f" />
@ -425,6 +437,9 @@
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="ImageAreaWidth" TargetType="{x:Type ColumnDefinition}">
<Setter Property="Width" Value="60" />
</Style>
<Style
x:Key="PreviewGlyph"
BasedOn="{StaticResource BasePreviewGlyph}"
@ -464,6 +479,14 @@
</Style.Triggers>
</Style>
<!-- for classic themes -->
<Style x:Key="PluginActivationIcon" TargetType="{x:Type Image}">
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
<Setter Property="Margin" Value="0,0,18,0" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#555555" />
<Setter Property="Width" Value="32" />
@ -492,7 +515,7 @@
</Style>
<Style
x:Key="ItemHotkeySelectedStyle"
BasedOn="{StaticResource BaseItemHotkeySelecetedStyle}"
BasedOn="{StaticResource BaseItemHotkeySelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="15" />
<Setter Property="Foreground" Value="#8f8f8f" />

View file

@ -106,7 +106,7 @@
</Style>
<Style
x:Key="ItemHotkeySelectedStyle"
BasedOn="{StaticResource BaseItemHotkeySelecetedStyle}"
BasedOn="{StaticResource BaseItemHotkeySelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="13" />
<Setter Property="Foreground" Value="#ff79c6" />

View file

@ -0,0 +1,217 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<system:Double x:Key="ResultItemHeight">38</system:Double>
<Style x:Key="ImageAreaWidth" TargetType="{x:Type ColumnDefinition}">
<Setter Property="Width" Value="46" />
</Style>
<Style x:Key="ImageIconStyle" TargetType="{x:Type Image}">
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="24" />
</Style>
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="24" />
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
<Setter Property="Foreground" Value="#100f0f" />
</Style>
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Padding" Value="0,2,42,0" />
<Setter Property="Foreground" Value="#282728" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Height" Value="24" />
</Style>
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Padding" Value="0,2,42,0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="24" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Foreground" Value="#8f8c8f" />
</Style>
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#bcbabd" />
<Setter Property="Background" Value="#edebee" />
<Setter Property="CornerRadius" Value="6" />
<Setter Property="UseLayoutRounding" Value="True" />
</Style>
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}" />
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}" />
<!-- Item Style -->
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="#100f0f" />
</Style>
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="10" />
<Setter Property="Foreground" Value="#8f8d90" />
</Style>
<Style
x:Key="SeparatorStyle"
BasedOn="{StaticResource BaseSeparatorStyle}"
TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#dedcde" />
<Setter Property="Height" Value="1" />
<Setter Property="Margin" Value="0,0,0,4" />
</Style>
<Style x:Key="HighlightStyle" />
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="#100f0f" />
</Style>
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="10" />
<Setter Property="Foreground" Value="#8f8d90" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#d6d4d7</SolidColorBrush>
<!-- button style in the middle of the scrollbar -->
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border
Width="4"
Margin="0,0,2,0"
Background="#878687"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
DockPanel.Dock="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}" />
<Style
x:Key="SearchIconStyle"
BasedOn="{StaticResource BaseSearchIconStyle}"
TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#d5d3d6" />
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
</Style>
<Style x:Key="SearchIconPosition" TargetType="{x:Type Canvas}">
<Setter Property="Background" Value="#edebee" />
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
<Setter Property="Margin" Value="0,0,8,0" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style x:Key="PluginActivationIcon" TargetType="{x:Type Image}">
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
<Setter Property="Margin" Value="0,0,8,0" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style x:Key="ItemHotkeyStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="12" />
<Setter Property="Foreground" Value="#8f8d90" />
</Style>
<Style x:Key="ItemHotkeySelectedStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="12" />
<Setter Property="Foreground" Value="#8f8d90" />
</Style>
<Style x:Key="ItemGlyphSelectedStyle" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#100f0f" />
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
<Setter Property="FontSize" Value="24" />
</Style>
<CornerRadius x:Key="ItemRadius">6</CornerRadius>
<Thickness x:Key="ItemMargin">4 0 4 0</Thickness>
<Thickness x:Key="ResultMargin">0 0 0 4</Thickness>
<Style
x:Key="ClockPanel"
BasedOn="{StaticResource ClockPanel}"
TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="Margin" Value="0,0,42,0" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="#8f8d90" />
<Setter Property="Margin" Value="0,0,10,0" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="#8f8d90" />
</Style>
<Style
x:Key="PreviewBorderStyle"
BasedOn="{StaticResource BasePreviewBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="Margin" Value="0,0,10,8" />
<Setter Property="BorderBrush" Value="#dedcde" />
</Style>
<Style
x:Key="PreviewItemTitleStyle"
BasedOn="{StaticResource BasePreviewItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#100f0f" />
</Style>
<Style
x:Key="PreviewItemSubTitleStyle"
BasedOn="{StaticResource BasePreviewItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#8f8d90" />
</Style>
<Style
x:Key="PreviewGlyph"
BasedOn="{StaticResource BasePreviewGlyph}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#100f0f" />
</Style>
</ResourceDictionary>

View file

@ -120,7 +120,7 @@
</Style>
<Style
x:Key="ItemHotkeySelectedStyle"
BasedOn="{StaticResource BaseItemHotkeySelecetedStyle}"
BasedOn="{StaticResource BaseItemHotkeySelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="13" />
<Setter Property="Foreground" Value="#acacac" />

View file

@ -113,7 +113,7 @@
</Style>
<Style
x:Key="ItemHotkeySelectedStyle"
BasedOn="{StaticResource BaseItemHotkeySelecetedStyle}"
BasedOn="{StaticResource BaseItemHotkeySelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="13" />
<Setter Property="Foreground" Value="{DynamicResource HotkeySelectedForeground}" />

View file

@ -535,13 +535,13 @@ namespace Flow.Launcher.ViewModel
_selectedResults = value;
if (SelectedIsFromQueryResults())
{
ContextMenu.Visbility = Visibility.Collapsed;
History.Visbility = Visibility.Collapsed;
ContextMenu.Visibility = Visibility.Collapsed;
History.Visibility = Visibility.Collapsed;
ChangeQueryText(_queryTextBeforeLeaveResults);
}
else
{
Results.Visbility = Visibility.Collapsed;
Results.Visibility = Visibility.Collapsed;
_queryTextBeforeLeaveResults = QueryText;
@ -559,7 +559,7 @@ namespace Flow.Launcher.ViewModel
}
}
_selectedResults.Visbility = Visibility.Visible;
_selectedResults.Visibility = Visibility.Visible;
}
}
@ -710,7 +710,7 @@ namespace Flow.Launcher.ViewModel
if (query == null) // shortcut expanded
{
Results.Clear();
Results.Visbility = Visibility.Collapsed;
Results.Visibility = Visibility.Collapsed;
PluginIconPath = null;
SearchIconVisibility = Visibility.Visible;
return;
@ -841,15 +841,20 @@ namespace Flow.Launcher.ViewModel
queryBuilder.Replace('@' + shortcut.Key, shortcut.Expand());
}
string customExpanded = queryBuilder.ToString();
Application.Current.Dispatcher.Invoke(() =>
{
foreach (var shortcut in builtInShortcuts)
{
try
{
var expansion = shortcut.Expand();
queryBuilder.Replace(shortcut.Key, expansion);
queryBuilderTmp.Replace(shortcut.Key, expansion);
if (customExpanded.Contains(shortcut.Key))
{
var expansion = shortcut.Expand();
queryBuilder.Replace(shortcut.Key, expansion);
queryBuilderTmp.Replace(shortcut.Key, expansion);
}
}
catch (Exception e)
{

View file

@ -188,7 +188,7 @@ namespace Flow.Launcher.ViewModel
{
try
{
var image = await Task.Run(() => icon()).ConfigureAwait(false);
var image = icon();
return image;
}
catch (Exception e)

View file

@ -43,13 +43,13 @@ namespace Flow.Launcher.ViewModel
#region Properties
public int MaxHeight => MaxResults * 52;
public double MaxHeight => MaxResults * (double)Application.Current.FindResource("ResultItemHeight")!;
public int SelectedIndex { get; set; }
public ResultViewModel SelectedItem { get; set; }
public Thickness Margin { get; set; }
public Visibility Visbility { get; set; } = Visibility.Collapsed;
public Visibility Visibility { get; set; } = Visibility.Collapsed;
public ICommand RightClickResultCommand { get; init; }
public ICommand LeftClickResultCommand { get; init; }
@ -167,14 +167,14 @@ namespace Flow.Launcher.ViewModel
SelectedItem = Results[0];
}
switch (Visbility)
switch (Visibility)
{
case Visibility.Collapsed when Results.Count > 0:
SelectedIndex = 0;
Visbility = Visibility.Visible;
Visibility = Visibility.Visible;
break;
case Visibility.Visible when Results.Count == 0:
Visbility = Visibility.Collapsed;
Visibility = Visibility.Collapsed;
break;
}
}
@ -259,7 +259,7 @@ namespace Flow.Launcher.ViewModel
return;
// manually update event
// wpf use directx / double buffered already, so just reset all won't cause ui flickering
// wpf use DirectX / double buffered already, so just reset all won't cause ui flickering
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
private void AddAll(List<ResultViewModel> Items)

View file

@ -325,18 +325,14 @@ namespace Flow.Launcher.ViewModel
public IList<PluginViewModel> PluginViewModels
{
get
{
var metadatas = PluginManager.AllPlugins
.OrderBy(x => x.Metadata.Disabled)
.ThenBy(y => y.Metadata.Name)
.Select(p => new PluginViewModel
{
PluginPair = p
})
.ToList();
return metadatas;
}
get => PluginManager.AllPlugins
.OrderBy(x => x.Metadata.Disabled)
.ThenBy(y => y.Metadata.Name)
.Select(p => new PluginViewModel
{
PluginPair = p
})
.ToList();
}
public IList<PluginStoreItemViewModel> ExternalPlugins
@ -407,7 +403,6 @@ namespace Flow.Launcher.ViewModel
get { return Settings.Theme; }
set
{
Settings.Theme = value;
ThemeManager.Instance.ChangeTheme(value);
if (ThemeManager.Instance.BlurEnabled && Settings.UseDropShadowEffect)
@ -863,31 +858,48 @@ namespace Flow.Launcher.ViewModel
{
get
{
var dirInfo = new DirectoryInfo(Path.Combine(DataLocation.DataDirectory(), Constant.Logs, Constant.Version));
long size = dirInfo.EnumerateFiles("*", SearchOption.AllDirectories).Sum(file => file.Length);
return _translater.GetTranslation("clearlogfolder") + " (" + FormatBytes(size) + ")";
var logFiles = GetLogFiles();
long size = logFiles.Sum(file => file.Length);
return string.Format("{0} ({1})", _translater.GetTranslation("clearlogfolder"), BytesToReadableString(size));
}
}
private static DirectoryInfo GetLogDir(string version = "")
{
return new DirectoryInfo(Path.Combine(DataLocation.DataDirectory(), Constant.Logs, version));
}
private static List<FileInfo> GetLogFiles(string version = "")
{
return GetLogDir(version).EnumerateFiles("*", SearchOption.AllDirectories).ToList();
}
internal void ClearLogFolder()
{
var directory = new DirectoryInfo(
Path.Combine(
DataLocation.DataDirectory(),
Constant.Logs,
Constant.Version));
var logDirectory = GetLogDir();
var logFiles = GetLogFiles();
directory.EnumerateFiles()
logFiles.ForEach(f => f.Delete());
logDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
.Where(dir => !Constant.Version.Equals(dir.Name))
.ToList()
.ForEach(x => x.Delete());
.ForEach(dir => dir.Delete());
OnPropertyChanged(nameof(CheckLogFolder));
}
internal string FormatBytes(long bytes)
internal void OpenLogFolder()
{
App.API.OpenDirectory(GetLogDir(Constant.Version).FullName);
}
internal static string BytesToReadableString(long bytes)
{
const int scale = 1024;
string[] orders = new string[]
{
"GB", "MB", "KB", "Bytes"
"GB", "MB", "KB", "B"
};
long max = (long)Math.Pow(scale, orders.Length - 1);
@ -898,7 +910,7 @@ namespace Flow.Launcher.ViewModel
max /= scale;
}
return "0 Bytes";
return "0 B";
}
#endregion

View file

@ -339,6 +339,7 @@ namespace Flow.Launcher.Plugin.Explorer
return false;
}
},
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue70f"),
IcoPath = Constants.FileImagePath
};
}
@ -371,7 +372,8 @@ namespace Flow.Launcher.Plugin.Explorer
return false;
}
},
IcoPath = Constants.FileImagePath
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue756"),
IcoPath = Constants.FolderImagePath
};
}
@ -437,7 +439,7 @@ namespace Flow.Launcher.Plugin.Explorer
};
}
public void LogException(string message, Exception e)
private void LogException(string message, Exception e)
{
Log.Exception($"|Flow.Launcher.Plugin.Folder.ContextMenu|{message}", e);
}

View file

@ -3,8 +3,6 @@
using System;
using System.Threading.Tasks;
using System.Windows;
using Flow.Launcher.Plugin.Explorer.Search.IProvider;
using JetBrains.Annotations;
namespace Flow.Launcher.Plugin.Explorer.Exceptions;
@ -20,7 +18,7 @@ public class EngineNotAvailableException : Exception
string engineName,
string resolution,
string message,
Func<ActionContext, ValueTask<bool>> action = null) : base(message)
Func<ActionContext, ValueTask<bool>>? action = null) : base(message)
{
EngineName = engineName;
Resolution = resolution;
@ -40,6 +38,23 @@ public class EngineNotAvailableException : Exception
EngineName = engineName;
Resolution = resolution;
}
public EngineNotAvailableException(
string engineName,
string resolution,
string message,
string errorIconPath,
Func<ActionContext, ValueTask<bool>>? action = null) : base(message)
{
EngineName = engineName;
Resolution = resolution;
ErrorIcon = errorIconPath;
Action = action ?? (_ =>
{
Clipboard.SetDataObject(this.ToString());
return ValueTask.FromResult(true);
});
}
public override string ToString()
{

View file

@ -14,7 +14,7 @@ public static class SortOptionTranslationHelper
const string prefix = "flowlauncher_plugin_everything_sort_by_";
ArgumentNullException.ThrowIfNull(API);
var enumName = Enum.GetName(sortOption);
var splited = enumName.Split('_');
var name = string.Join('_', splited[..^1]);
@ -22,4 +22,4 @@ public static class SortOptionTranslationHelper
return $"{API.GetTranslation(prefix + name.ToLower())} {API.GetTranslation(prefix + direction.ToLower())}";
}
}
}

View file

@ -89,9 +89,9 @@
<system:String x:Key="plugin_explorer_add_to_quickaccess_title">Añadir al acceso rápido</system:String>
<system:String x:Key="plugin_explorer_add_to_quickaccess_subtitle">Añade elemento actual al acceso rápido</system:String>
<system:String x:Key="plugin_explorer_addfilefoldersuccess">Añadido/a correctamente</system:String>
<system:String x:Key="plugin_explorer_addfilefoldersuccess_detail">Añadido/a correctamente al acceso rápido</system:String>
<system:String x:Key="plugin_explorer_addfilefoldersuccess_detail">Añadido correctamente al acceso rápido</system:String>
<system:String x:Key="plugin_explorer_removefilefoldersuccess">Eliminado/a correctamente</system:String>
<system:String x:Key="plugin_explorer_removefilefoldersuccess_detail">Eliminado/a correctamente del acceso rápido</system:String>
<system:String x:Key="plugin_explorer_removefilefoldersuccess_detail">Eliminado correctamente del acceso rápido</system:String>
<system:String x:Key="plugin_explorer_contextmenu_titletooltip">Añade al acceso rápido para que se pueda abrir con la palabra clave de acción que activa la búsqueda del explorador</system:String>
<system:String x:Key="plugin_explorer_contextmenu_remove_titletooltip">Eliminar del acceso rápido</system:String>
<system:String x:Key="plugin_explorer_remove_from_quickaccess_title">Eliminar del acceso rápido</system:String>

View file

@ -79,7 +79,7 @@
<system:String x:Key="plugin_explorer_opencontainingfolder_subtitle">Otvoriť umiestnenie aktuálnej položky</system:String>
<system:String x:Key="plugin_explorer_openwitheditor">Otvoriť v editore:</system:String>
<system:String x:Key="plugin_explorer_openwitheditor_error">Nepodarilo sa otvoriť súbor {0} v editore {1} {2}</system:String>
<system:String x:Key="plugin_explorer_openwithshell">Otvori v príkazovom riadku:</system:String>
<system:String x:Key="plugin_explorer_openwithshell">Otvoriť v príkazovom riadku:</system:String>
<system:String x:Key="plugin_explorer_openwithshell_error">Nepodarilo sa otvoriť priečinok {0} v prostredí {1} {2}</system:String>
<system:String x:Key="plugin_explorer_excludefromindexsearch">Vylúčiť položku a jej podpriečinky z indexu vyhľadávania</system:String>
<system:String x:Key="plugin_explorer_excludedfromindexsearch_msg">Vylúčiť z indexu vyhľadávania</system:String>

View file

@ -32,7 +32,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
internal const string DefaultContentSearchActionKeyword = "doc:";
internal const char DirectorySeperator = '\\';
internal const char DirectorySeparator = '\\';
internal const string WindowsIndexingOptions = "srchadmin.dll";

View file

@ -15,7 +15,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo
var criteria = ConstructSearchCriteria(search);
if (search.LastIndexOf(Constants.AllFilesFolderSearchWildcard) >
search.LastIndexOf(Constants.DirectorySeperator))
search.LastIndexOf(Constants.DirectorySeparator))
return DirectorySearch(new EnumerationOptions
{
RecurseSubdirectories = true
@ -29,9 +29,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo
{
string incompleteName = "";
if (!search.EndsWith(Constants.DirectorySeperator))
if (!search.EndsWith(Constants.DirectorySeparator))
{
var indexOfSeparator = search.LastIndexOf(Constants.DirectorySeperator);
var indexOfSeparator = search.LastIndexOf(Constants.DirectorySeparator);
incompleteName = search[(indexOfSeparator + 1)..].ToLower();
@ -76,7 +76,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo
}
catch (Exception e)
{
Log.Exception(nameof(DirectoryInfoSearch), "Error occured while searching path", e);
Log.Exception(nameof(DirectoryInfoSearch), "Error occurred while searching path", e);
throw;
}

View file

@ -1,70 +1,75 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using Flow.Launcher.Plugin.SharedCommands;
namespace Flow.Launcher.Plugin.Explorer.Search
{
public static class EnvironmentVariables
{
internal static bool IsEnvironmentVariableSearch(string search)
private static Dictionary<string, string> _envStringPaths = null;
private static Dictionary<string, string> EnvStringPaths
{
return search.StartsWith("%")
&& search != "%%"
&& !search.Contains("\\") &&
LoadEnvironmentStringPaths().Count > 0;
get
{
if (_envStringPaths == null)
{
LoadEnvironmentStringPaths();
}
return _envStringPaths;
}
}
internal static Dictionary<string, string> LoadEnvironmentStringPaths()
internal static bool IsEnvironmentVariableSearch(string search)
{
var envStringPaths = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
return search.StartsWith("%")
&& search != "%%"
&& !search.Contains('\\')
&& EnvStringPaths.Count > 0;
}
public static bool HasEnvironmentVar(string search)
{
// "c:\foo %appdata%\" returns false
var splited = search.Split(Path.DirectorySeparatorChar);
return splited.Any(dir => dir.StartsWith('%') &&
dir.EndsWith('%') &&
dir.Length > 2 &&
dir.Split('%').Length == 3);
}
private static void LoadEnvironmentStringPaths()
{
_envStringPaths = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
var homedrive = Environment.GetEnvironmentVariable("HOMEDRIVE")?.EnsureTrailingSlash() ?? "C:\\";
foreach (DictionaryEntry special in Environment.GetEnvironmentVariables())
{
var path = special.Value.ToString();
// we add a trailing slash to the path to make sure drive paths become valid absolute paths.
// for example, if %systemdrive% is C: we turn it to C:\
path = path.EnsureTrailingSlash();
// if we don't have an absolute path, we use Path.GetFullPath to get one.
// for example, if %homepath% is \Users\John we turn it to C:\Users\John
// Add basepath for GetFullPath() to parse %HOMEPATH% correctly
path = Path.IsPathFullyQualified(path) ? path : Path.GetFullPath(path, homedrive);
if (Directory.Exists(path))
{
// we add a trailing slash to the path to make sure drive paths become valid absolute paths.
// for example, if %systemdrive% is C: we turn it to C:\
path = path.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
// if we don't have an absolute path, we use Path.GetFullPath to get one.
// for example, if %homepath% is \Users\John we turn it to C:\Users\John
path = Path.IsPathFullyQualified(path) ? path : Path.GetFullPath(path);
// Variables are returned with a mixture of all upper/lower case.
// Call ToLower() to make the results look consistent
envStringPaths.Add(special.Key.ToString().ToLower(), path);
// Call ToUpper() to make the results look consistent
_envStringPaths.Add(special.Key.ToString().ToUpper(), path);
}
}
return envStringPaths;
}
internal static string TranslateEnvironmentVariablePath(string environmentVariablePath)
{
var envStringPaths = LoadEnvironmentStringPaths();
var splitSearch = environmentVariablePath.Substring(1).Split("%");
var exactEnvStringPath = splitSearch[0];
// if there are more than 2 % characters in the query, don't bother
if (splitSearch.Length == 2 && envStringPaths.ContainsKey(exactEnvStringPath))
{
var queryPartToReplace = $"%{exactEnvStringPath}%";
var expandedPath = envStringPaths[exactEnvStringPath];
// replace the %envstring% part of the query with its expanded equivalent
return environmentVariablePath.Replace(queryPartToReplace, expandedPath);
}
return environmentVariablePath;
}
internal static List<Result> GetEnvironmentStringPathSuggestions(string querySearch, Query query, PluginInitContext context)
{
var results = new List<Result>();
var environmentVariables = LoadEnvironmentStringPaths();
var search = querySearch;
if (querySearch.EndsWith("%") && search.Length > 1)
@ -72,12 +77,12 @@ namespace Flow.Launcher.Plugin.Explorer.Search
// query starts and ends with a %, find an exact match from env-string paths
search = querySearch.Substring(1, search.Length - 2);
if (environmentVariables.ContainsKey(search))
if (EnvStringPaths.ContainsKey(search))
{
var expandedPath = environmentVariables[search];
var expandedPath = EnvStringPaths[search];
results.Add(ResultManager.CreateFolderResult($"%{search}%", expandedPath, expandedPath, query));
return results;
}
}
@ -90,8 +95,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{
search = search.Substring(1);
}
foreach (var p in environmentVariables)
foreach (var p in EnvStringPaths)
{
if (p.Key.StartsWith(search, StringComparison.InvariantCultureIgnoreCase))
{

View file

@ -27,20 +27,16 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
Enum.GetName(Settings.IndexSearchEngineOption.Everything)!,
Main.Context.API.GetTranslation("flowlauncher_plugin_everything_click_to_launch_or_install"),
Main.Context.API.GetTranslation("flowlauncher_plugin_everything_is_not_running"),
ClickToInstallEverythingAsync)
{
ErrorIcon = Constants.EverythingErrorImagePath
};
Constants.EverythingErrorImagePath,
ClickToInstallEverythingAsync);
}
catch (DllNotFoundException)
{
throw new EngineNotAvailableException(
Enum.GetName(Settings.IndexSearchEngineOption.Everything)!,
"Please check whether your system is x86 or x64",
Main.Context.API.GetTranslation("flowlauncher_plugin_everything_sdk_issue"))
{
ErrorIcon = Constants.GeneralSearchErrorImagePath
};
Constants.GeneralSearchErrorImagePath,
Main.Context.API.GetTranslation("flowlauncher_plugin_everything_sdk_issue"));
}
}
private async ValueTask<bool> ClickToInstallEverythingAsync(ActionContext _)
@ -72,16 +68,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
if (!Settings.EnableEverythingContentSearch)
{
throw new EngineNotAvailableException(Enum.GetName(Settings.IndexSearchEngineOption.Everything)!,
"Click to Enable Everything Content Search (only applicable to Everything 1.5+ with indexed content)",
"Everything Content Search is not enabled.",
Main.Context.API.GetTranslation("flowlauncher_plugin_everything_enable_content_search"),
Main.Context.API.GetTranslation("flowlauncher_plugin_everything_enable_content_search_tips"),
Constants.EverythingErrorImagePath,
_ =>
{
Settings.EnableEverythingContentSearch = true;
return ValueTask.FromResult(true);
})
{
ErrorIcon = Constants.EverythingErrorImagePath
};
});
}
if (token.IsCancellationRequested)
yield break;

View file

@ -15,7 +15,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks
{
get
{
var path = Path.EndsWith(Constants.DirectorySeperator) ? Path[0..^1] : Path;
var path = Path.EndsWith(Constants.DirectorySeparator) ? Path[0..^1] : Path;
if (path.EndsWith(':'))
return path[0..^1] + " Drive";

View file

@ -27,8 +27,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search
var usePathSearchActionKeyword = Settings.PathSearchKeywordEnabled && !Settings.SearchActionKeywordEnabled;
var pathSearchActionKeyword = Settings.PathSearchActionKeyword == Query.GlobalPluginWildcardSign
? string.Empty
var pathSearchActionKeyword = Settings.PathSearchActionKeyword == Query.GlobalPluginWildcardSign
? string.Empty
: $"{Settings.PathSearchActionKeyword} ";
var searchActionKeyword = Settings.SearchActionKeyword == Query.GlobalPluginWildcardSign
@ -36,12 +36,12 @@ namespace Flow.Launcher.Plugin.Explorer.Search
: $"{Settings.SearchActionKeyword} ";
var keyword = usePathSearchActionKeyword ? pathSearchActionKeyword : searchActionKeyword;
var formatted_path = path;
if (type == ResultType.Folder)
// the seperator is needed so when navigating the folder structure contents of the folder are listed
formatted_path = path.EndsWith(Constants.DirectorySeperator) ? path : path + Constants.DirectorySeperator;
// the separator is needed so when navigating the folder structure contents of the folder are listed
formatted_path = path.EndsWith(Constants.DirectorySeparator) ? path : path + Constants.DirectorySeparator;
return $"{keyword}{formatted_path}";
}
@ -49,8 +49,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search
public static string GetAutoCompleteText(string title, Query query, string path, ResultType resultType)
{
return !Settings.PathSearchKeywordEnabled && !Settings.SearchActionKeywordEnabled
? $"{query.ActionKeyword} {title}" // Only Quick Access action keyword is used in this scenario
: GetPathWithActionKeyword(path, resultType, query.ActionKeyword);
? $"{query.ActionKeyword} {title}" // Only Quick Access action keyword is used in this scenario
: GetPathWithActionKeyword(path, resultType, query.ActionKeyword);
}
public static Result CreateResult(Query query, SearchResult result)
@ -71,7 +71,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{
Title = title,
IcoPath = path,
SubTitle = Path.GetDirectoryName(path),
SubTitle = subtitle,
AutoCompleteText = GetAutoCompleteText(title, query, path, ResultType.Folder),
TitleHighlightData = StringMatcher.FuzzySearch(query.Search, title).MatchData,
CopyText = path,
@ -187,9 +187,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search
internal static Result CreateOpenCurrentFolderResult(string path, string actionKeyword, bool windowsIndexed = false)
{
// Path passed from PathSearchAsync ends with Constants.DirectorySeperator ('\'), need to remove the seperator
// Path passed from PathSearchAsync ends with Constants.DirectorySeparator ('\'), need to remove the separator
// so it's consistent with folder results returned by index search which does not end with one
var folderPath = path.TrimEnd(Constants.DirectorySeperator);
var folderPath = path.TrimEnd(Constants.DirectorySeparator);
return new Result
{
@ -215,9 +215,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search
internal static Result CreateFileResult(string filePath, Query query, int score = 0, bool windowsIndexed = false)
{
Result.PreviewInfo preview = IsMedia(Path.GetExtension(filePath)) ? new Result.PreviewInfo {
IsMedia = true,
PreviewImagePath = filePath,
Result.PreviewInfo preview = IsMedia(Path.GetExtension(filePath)) ? new Result.PreviewInfo
{
IsMedia = true, PreviewImagePath = filePath,
} : Result.PreviewInfo.Default;
var title = Path.GetFileName(filePath);
@ -246,6 +246,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{
FileName = filePath,
UseShellExecute = true,
WorkingDirectory = Settings.UseLocationAsWorkingDir ? Path.GetDirectoryName(filePath) : string.Empty,
Verb = "runas",
});
}
@ -286,8 +287,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search
public static bool IsMedia(string extension)
{
if (string.IsNullOrEmpty(extension))
{
return false;
{
return false;
}
else
{
@ -295,7 +296,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search
}
}
public static readonly string[] MediaExtensions = { ".jpg", ".png", ".avi", ".mkv", ".bmp", ".gif", ".wmv", ".mp3", ".flac", ".mp4" };
public static readonly string[] MediaExtensions =
{
".jpg", ".png", ".avi", ".mkv", ".bmp", ".gif", ".wmv", ".mp3", ".flac", ".mp4"
};
}
public enum ResultType

View file

@ -13,9 +13,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{
public class SearchManager
{
internal static PluginInitContext Context;
internal PluginInitContext Context;
internal static Settings Settings;
internal Settings Settings;
public SearchManager(Settings settings, PluginInitContext context)
{
@ -23,19 +23,23 @@ namespace Flow.Launcher.Plugin.Explorer.Search
Settings = settings;
}
private class PathEqualityComparator : IEqualityComparer<Result>
/// <summary>
/// Note: A path that ends with "\" and one that doesn't will not be regarded as equal.
/// </summary>
public class PathEqualityComparator : IEqualityComparer<Result>
{
private static PathEqualityComparator instance;
public static PathEqualityComparator Instance => instance ??= new PathEqualityComparator();
public bool Equals(Result x, Result y)
{
return x.Title == y.Title && x.SubTitle == y.SubTitle;
return x.Title.Equals(y.Title, StringComparison.OrdinalIgnoreCase)
&& string.Equals(x.SubTitle, y.SubTitle, StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode(Result obj)
{
return HashCode.Combine(obj.Title.GetHashCode(), obj.SubTitle?.GetHashCode() ?? 0);
return HashCode.Combine(obj.Title.ToLowerInvariant(), obj.SubTitle?.ToLowerInvariant() ?? "");
}
}
@ -105,19 +109,21 @@ namespace Flow.Launcher.Plugin.Explorer.Search
await foreach (var search in searchResults.WithCancellation(token).ConfigureAwait(false))
results.Add(ResultManager.CreateResult(query, search));
}
catch (OperationCanceledException)
{
return new List<Result>();
}
catch (EngineNotAvailableException)
{
throw;
}
catch (Exception e)
{
if (e is OperationCanceledException)
return results.ToList();
if (e is EngineNotAvailableException)
throw;
throw new SearchException(engineName, e.Message, e);
}
results.RemoveWhere(r => Settings.IndexSearchExcludedSubdirectoryPaths.Any(
excludedPath => r.SubTitle.StartsWith(excludedPath.Path, StringComparison.OrdinalIgnoreCase)));
excludedPath => FilesFolders.PathContains(excludedPath.Path, r.SubTitle)));
return results.ToList();
}
@ -142,7 +148,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
};
}
private static List<Result> EverythingContentSearchResult(Query query)
private List<Result> EverythingContentSearchResult(Query query)
{
return new List<Result>()
{
@ -167,18 +173,12 @@ namespace Flow.Launcher.Plugin.Explorer.Search
var results = new HashSet<Result>(PathEqualityComparator.Instance);
var isEnvironmentVariable = EnvironmentVariables.IsEnvironmentVariableSearch(querySearch);
if (isEnvironmentVariable)
if (EnvironmentVariables.IsEnvironmentVariableSearch(querySearch))
return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, Context);
// Query is a location path with a full environment variable, eg. %appdata%\somefolder\
var isEnvironmentVariablePath = querySearch[1..].Contains("%\\");
var locationPath = querySearch;
if (isEnvironmentVariablePath)
locationPath = EnvironmentVariables.TranslateEnvironmentVariablePath(locationPath);
// Query is a location path with a full environment variable, eg. %appdata%\somefolder\, c:\users\%USERNAME%\downloads
var needToExpand = EnvironmentVariables.HasEnvironmentVar(querySearch);
var locationPath = needToExpand ? Environment.ExpandEnvironmentVariables(querySearch) : querySearch;
// Check that actual location exists, otherwise directory search will throw directory not found exception
if (!FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath).LocationExists())
@ -234,7 +234,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
return results.ToList();
}
public static bool IsFileContentSearch(string actionKeyword) => actionKeyword == Settings.FileContentSearchActionKeyword;
public bool IsFileContentSearch(string actionKeyword) => actionKeyword == Settings.FileContentSearchActionKeyword;
private bool UseWindowsIndexForDirectorySearch(string locationPath)
@ -245,10 +245,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search
x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(pathToDirectory).StartsWith(x.Path, StringComparison.OrdinalIgnoreCase))
&& WindowsIndex.WindowsIndex.PathIsIndexed(pathToDirectory);
}
internal static bool IsEnvironmentVariableSearch(string search)
{
return search.StartsWith("%")
return search.StartsWith("%")
&& search != "%%"
&& !search.Contains('\\');
}

View file

@ -97,27 +97,25 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
private IAsyncEnumerable<SearchResult> HandledEngineNotAvailableExceptionAsync()
{
if (!SearchManager.Settings.WarnWindowsSearchServiceOff)
if (!Settings.WarnWindowsSearchServiceOff)
return AsyncEnumerable.Empty<SearchResult>();
var api = SearchManager.Context.API;
var api = Main.Context.API;
throw new EngineNotAvailableException(
"Windows Index",
api.GetTranslation("plugin_explorer_windowsSearchServiceFix"),
api.GetTranslation("plugin_explorer_windowsSearchServiceNotRunning"),
Constants.WindowsIndexErrorImagePath,
c =>
{
SearchManager.Settings.WarnWindowsSearchServiceOff = false;
Settings.WarnWindowsSearchServiceOff = false;
// Clears the warning message so user is not mistaken that it has not worked
api.ChangeQuery(string.Empty);
return ValueTask.FromResult(false);
})
{
ErrorIcon = Constants.WindowsIndexErrorImagePath
};
});
}
}
}

View file

@ -10,7 +10,7 @@
"Name": "Explorer",
"Description": "Find and manage files and folders via Windows Search or Everything",
"Author": "Jeremy Wu",
"Version": "2.1.0",
"Version": "2.2.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll",

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicator</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Provides plugins action words suggestions</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indikator</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Stellt Vorschläge für Plugin-Befehle bereit</system:String>
</ResourceDictionary>

View file

@ -2,7 +2,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicator</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Provides plugins action words suggestions</system:String>
</ResourceDictionary>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Indicador de Plugins</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Sugiere palabras clave de plugins</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activa {0} palabra clave de acción del complemento</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Indicador de complementos</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Proporciona sugerencias de palabras de acción para los complementos</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicator</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Provides plugins action words suggestions</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Indicatore Plugin</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Fornisce suggerimenti sulle parole d'azione dei plugin</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicator</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Provides plugins action words suggestions</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">플러그인 인디케이터</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">플러그인의 액션 키워드 제안을 제공합니다</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicator</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Provides plugins action words suggestions</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicator</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Provides plugins action words suggestions</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicator</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Pokazuje podpowiedzi jakich zainstalowanych wtyczek możesz użyć</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicator</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Provides plugins action words suggestions</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Palavra-chave para ativar o plugin {0}</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicador</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Disponibiliza sugestões de palavras-chave para os plugins</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Activate {0} plugin action keyword</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicator</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Provides plugins action words suggestions</system:String>
</ResourceDictionary>

View file

@ -1,7 +1,9 @@
<?xml version="1.0"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="flowlauncher_plugin_pluginindicator_result_subtitle">Aktivovať plugin {0} aktivačným príkazom</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicator</system:String>
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Ponúka návrhy pre akcie pluginov</system:String>
</ResourceDictionary>

Some files were not shown because too many files have changed in this diff Show more