├── .editorconfig ├── .gitignore ├── .vsconfig ├── Assest ├── InstallIcon.ico ├── InstallIcon.png ├── Readme_Screenshots_1.jpg ├── Readme_Title.jpg ├── Readme_Title.psd ├── WindowIcon.ico └── WindowIcon.png ├── LICENSE ├── MoreFlyout.Server.Core ├── Contracts │ └── Services │ │ └── IFileService.cs ├── Helpers │ └── Json.cs ├── MoreFlyout.Server.Core.csproj ├── README.md └── Services │ └── FileService.cs ├── MoreFlyout.Server ├── Activation │ ├── ActivationHandler.cs │ ├── DefaultActivationHandler.cs │ └── IActivationHandler.cs ├── App.xaml ├── App.xaml.cs ├── Assets │ └── WindowIcon.ico ├── Contracts │ ├── Services │ │ ├── IActivationService.cs │ │ ├── ILocalSettingsService.cs │ │ ├── INavigationService.cs │ │ └── IPageService.cs │ └── ViewModels │ │ └── INavigationAware.cs ├── FlyoutWindow.xaml ├── FlyoutWindow.xaml.cs ├── Helpers │ ├── FrameExtensions.cs │ ├── ResourceExtensions.cs │ ├── RuntimeHelper.cs │ └── SettingsStorageExtensions.cs ├── Models │ └── LocalSettingsOptions.cs ├── MoreFlyout.Server.csproj ├── NativeMethods.txt ├── Properties │ ├── PublishProfiles │ │ ├── win-arm64.pubxml │ │ ├── win-x64.pubxml │ │ └── win-x86.pubxml │ └── launchsettings.json ├── README.md ├── Services │ ├── ActivationService.cs │ ├── LocalSettingsService.cs │ ├── NavigationService.cs │ └── PageService.cs ├── Strings │ ├── en-us │ │ └── Resources.resw │ └── zh-CN │ │ └── Resources.resw ├── Styles │ ├── FontSizes.xaml │ ├── TextBlock.xaml │ └── Thickness.xaml ├── TemplateStudio.xml ├── Usings.cs ├── ViewModels │ └── FlyoutViewModel.cs ├── Views │ ├── FlyoutPage.xaml │ └── FlyoutPage.xaml.cs ├── app.manifest └── appsettings.json ├── MoreFlyout.Shell.Core ├── Contracts │ └── Services │ │ └── IFileService.cs ├── Helpers │ └── Json.cs ├── MoreFlyout.Shell.Core.csproj ├── README.md └── Services │ └── FileService.cs ├── MoreFlyout.Shell ├── Activation │ ├── ActivationHandler.cs │ ├── DefaultActivationHandler.cs │ └── IActivationHandler.cs ├── App.xaml ├── App.xaml.cs ├── Assets │ └── WindowIcon.ico ├── Contracts │ ├── Services │ │ ├── IActivationService.cs │ │ ├── ILocalSettingsService.cs │ │ ├── INavigationService.cs │ │ ├── IPageService.cs │ │ └── IThemeSelectorService.cs │ └── ViewModels │ │ └── INavigationAware.cs ├── Helpers │ ├── FrameExtensions.cs │ ├── ResourceExtensions.cs │ ├── RuntimeHelper.cs │ ├── SettingsStorageExtensions.cs │ └── TitleBarHelper.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Models │ └── LocalSettingsOptions.cs ├── MoreFlyout.Shell.csproj ├── Package.appinstaller ├── Package.appxmanifest ├── Properties │ ├── PublishProfiles │ │ ├── win-arm64.pubxml │ │ ├── win-x64.pubxml │ │ └── win-x86.pubxml │ └── launchsettings.json ├── README.md ├── Services │ ├── ActivationService.cs │ ├── LocalSettingsService.cs │ ├── NavigationService.cs │ ├── PageService.cs │ └── ThemeSelectorService.cs ├── Strings │ ├── en-us │ │ └── Resources.resw │ └── zh-cn │ │ └── Resources.resw ├── Styles │ ├── FontSizes.xaml │ ├── TextBlock.xaml │ └── Thickness.xaml ├── TemplateStudio.xml ├── Usings.cs ├── ViewModels │ └── MainViewModel.cs ├── Views │ ├── MainPage.xaml │ └── MainPage.xaml.cs ├── app.manifest └── appsettings.json ├── MoreFlyout.iss ├── MoreFlyout.sln ├── README.md ├── RELEASENOTE_CN.md └── RELEASENOTE_EN.md /.editorconfig: -------------------------------------------------------------------------------- 1 | # Rules in this file were initially inferred by Visual Studio IntelliCode from the Template Studio codebase. 2 | # You can modify the rules from these initially generated values to suit your own policies. 3 | # You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference. 4 | 5 | [*.cs] 6 | 7 | #Core editorconfig formatting - indentation 8 | 9 | #use soft tabs (spaces) for indentation 10 | indent_style = space 11 | 12 | #Formatting - new line options 13 | 14 | #place else statements on a new line 15 | csharp_new_line_before_else = true 16 | #require braces to be on a new line for lambdas, methods, control_blocks, types, properties, and accessors (also known as "Allman" style) 17 | csharp_new_line_before_open_brace = all 18 | 19 | #Formatting - organize using options 20 | 21 | #sort System.* using directives alphabetically, and place them before other usings 22 | dotnet_sort_system_directives_first = true 23 | 24 | #Formatting - spacing options 25 | 26 | #require NO space between a cast and the value 27 | csharp_space_after_cast = false 28 | #require a space before the colon for bases or interfaces in a type declaration 29 | csharp_space_after_colon_in_inheritance_clause = true 30 | #require a space after a keyword in a control flow statement such as a for loop 31 | csharp_space_after_keywords_in_control_flow_statements = true 32 | #require a space before the colon for bases or interfaces in a type declaration 33 | csharp_space_before_colon_in_inheritance_clause = true 34 | #remove space within empty argument list parentheses 35 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 36 | #remove space between method call name and opening parenthesis 37 | csharp_space_between_method_call_name_and_opening_parenthesis = false 38 | #do not place space characters after the opening parenthesis and before the closing parenthesis of a method call 39 | csharp_space_between_method_call_parameter_list_parentheses = false 40 | #remove space within empty parameter list parentheses for a method declaration 41 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 42 | #place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list. 43 | csharp_space_between_method_declaration_parameter_list_parentheses = false 44 | 45 | #Formatting - wrapping options 46 | 47 | #leave code block on separate lines 48 | csharp_preserve_single_line_blocks = false 49 | 50 | #Style - Code block preferences 51 | 52 | #prefer curly braces even for one line of code 53 | csharp_prefer_braces = true:none 54 | 55 | #Style - expression bodied member options 56 | 57 | #prefer expression bodies for accessors 58 | csharp_style_expression_bodied_accessors = true:warning 59 | #prefer block bodies for constructors 60 | csharp_style_expression_bodied_constructors = false:suggestion 61 | #prefer expression bodies for methods 62 | csharp_style_expression_bodied_methods = when_on_single_line:silent 63 | #prefer expression-bodied members for properties 64 | csharp_style_expression_bodied_properties = true:warning 65 | 66 | #Style - expression level options 67 | 68 | #prefer out variables to be declared before the method call 69 | csharp_style_inlined_variable_declaration = false:suggestion 70 | #prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them 71 | dotnet_style_predefined_type_for_member_access = true:suggestion 72 | 73 | #Style - Expression-level preferences 74 | 75 | #prefer default over default(T) 76 | csharp_prefer_simple_default_expression = true:suggestion 77 | #prefer objects to be initialized using object initializers when possible 78 | dotnet_style_object_initializer = true:suggestion 79 | 80 | #Style - implicit and explicit types 81 | 82 | #prefer var over explicit type in all cases, unless overridden by another code style rule 83 | csharp_style_var_elsewhere = true:suggestion 84 | #prefer var is used to declare variables with built-in system types such as int 85 | csharp_style_var_for_built_in_types = true:suggestion 86 | #prefer var when the type is already mentioned on the right-hand side of a declaration expression 87 | csharp_style_var_when_type_is_apparent = true:suggestion 88 | 89 | #Style - language keyword and framework type options 90 | 91 | #prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them 92 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 93 | 94 | #Style - Language rules 95 | csharp_style_implicit_object_creation_when_type_is_apparent = true:warning 96 | csharp_style_var_for_built_in_types = true:warning 97 | 98 | #Style - modifier options 99 | 100 | #prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods. 101 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 102 | 103 | #Style - Modifier preferences 104 | 105 | #when this rule is set to a list of modifiers, prefer the specified ordering. 106 | csharp_preferred_modifier_order = public,private,protected,internal,static,async,readonly,override,sealed,abstract,virtual:warning 107 | dotnet_style_readonly_field = true:warning 108 | 109 | #Style - Pattern matching 110 | 111 | #prefer pattern matching instead of is expression with type casts 112 | csharp_style_pattern_matching_over_as_with_null_check = true:warning 113 | 114 | #Style - qualification options 115 | 116 | #prefer events not to be prefaced with this. or Me. in Visual Basic 117 | dotnet_style_qualification_for_event = false:suggestion 118 | #prefer fields not to be prefaced with this. or Me. in Visual Basic 119 | dotnet_style_qualification_for_field = false:suggestion 120 | #prefer methods not to be prefaced with this. or Me. in Visual Basic 121 | dotnet_style_qualification_for_method = false:suggestion 122 | #prefer properties not to be prefaced with this. or Me. in Visual Basic 123 | dotnet_style_qualification_for_property = false:suggestion 124 | csharp_indent_labels = one_less_than_current 125 | csharp_using_directive_placement = outside_namespace:silent 126 | csharp_prefer_simple_using_statement = true:warning 127 | csharp_style_namespace_declarations = file_scoped:warning 128 | csharp_style_expression_bodied_operators = false:silent 129 | csharp_style_expression_bodied_indexers = true:silent 130 | csharp_style_expression_bodied_lambdas = true:silent 131 | csharp_style_expression_bodied_local_functions = false:silent 132 | 133 | [*.{cs,vb}] 134 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 135 | tab_width = 4 136 | indent_size = 4 137 | end_of_line = crlf 138 | dotnet_style_coalesce_expression = true:suggestion 139 | dotnet_style_null_propagation = true:suggestion 140 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 141 | dotnet_style_prefer_auto_properties = true:silent 142 | dotnet_style_object_initializer = true:suggestion 143 | dotnet_style_collection_initializer = true:suggestion 144 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 145 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 146 | dotnet_style_prefer_conditional_expression_over_return = true:silent 147 | [*.{cs,vb}] 148 | 149 | #Style - Unnecessary code rules 150 | csharp_style_unused_value_assignment_preference = discard_variable:warning 151 | 152 | #### Naming styles #### 153 | 154 | # Naming rules 155 | 156 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 157 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 158 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 159 | 160 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 161 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 162 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 163 | 164 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 165 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 166 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 167 | 168 | # Symbol specifications 169 | 170 | dotnet_naming_symbols.interface.applicable_kinds = interface 171 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 172 | dotnet_naming_symbols.interface.required_modifiers = 173 | 174 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 175 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 176 | dotnet_naming_symbols.types.required_modifiers = 177 | 178 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 179 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 180 | dotnet_naming_symbols.non_field_members.required_modifiers = 181 | 182 | # Naming styles 183 | 184 | dotnet_naming_style.begins_with_i.required_prefix = I 185 | dotnet_naming_style.begins_with_i.required_suffix = 186 | dotnet_naming_style.begins_with_i.word_separator = 187 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 188 | 189 | dotnet_naming_style.pascal_case.required_prefix = 190 | dotnet_naming_style.pascal_case.required_suffix = 191 | dotnet_naming_style.pascal_case.word_separator = 192 | dotnet_naming_style.pascal_case.capitalization = pascal_case 193 | 194 | dotnet_naming_style.pascal_case.required_prefix = 195 | dotnet_naming_style.pascal_case.required_suffix = 196 | dotnet_naming_style.pascal_case.word_separator = 197 | dotnet_naming_style.pascal_case.capitalization = pascal_case 198 | dotnet_style_explicit_tuple_names = true:suggestion 199 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 200 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 201 | dotnet_style_prefer_compound_assignment = true:warning 202 | dotnet_style_prefer_simplified_interpolation = true:suggestion 203 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | MoreFlyout.Server.Core/obj/ 2 | MoreFlyout.Server.Core/bin/ 3 | MoreFlyout.Server/bin/ 4 | MoreFlyout.Server/obj/ 5 | MoreFlyout.Shell.Core/bin/ 6 | MoreFlyout.Shell.Core/obj/ 7 | MoreFlyout.Shell/bin/ 8 | MoreFlyout.Shell/obj/ 9 | .vs/ 10 | MoreFlyout.Server/Properties/PublishProfiles/win10-x64.pubxml.user 11 | MoreFlyout.Server/Properties/PublishProfiles/FolderProfile.pubxml.user 12 | MoreFlyout.Server/Generated Files/ 13 | MoreFlyout.Server/Properties/PublishProfiles/win-x64.pubxml.user 14 | MoreFlyout.Server/MoreFlyout.Server.csproj.user 15 | MoreFlyout.Shell/Properties/PublishProfiles/win-x64.pubxml.user 16 | MoreFlyout.Shell/MoreFlyout.Shell.csproj.user 17 | MoreFlyout.Shell/Properties/PublishProfiles/win-x86.pubxml.user 18 | MoreFlyout.Server/Properties/PublishProfiles/win-arm64.pubxml.user 19 | MoreFlyout.Server/Properties/PublishProfiles/win-x86.pubxml.user 20 | MoreFlyout.Shell/Properties/PublishProfiles/win-arm64.pubxml.user 21 | MoreFlyout.Shell/Generated Files/CsWinRT/cswinrt.rsp 22 | MoreFlyout.Shell/Generated Files/CsWinRT/cswinrt_internal.rsp 23 | MoreFlyout.Shell/Generated Files/CsWinRT/WinRTEventHelpers.cs 24 | -------------------------------------------------------------------------------- /.vsconfig: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "components": [ 4 | "Microsoft.Component.MSBuild", 5 | "Microsoft.NetCore.Component.Runtime.7.0", 6 | "Microsoft.NetCore.Component.SDK", 7 | "Microsoft.VisualStudio.Component.ManagedDesktop.Core", 8 | "Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites", 9 | "Microsoft.VisualStudio.Component.NuGet", 10 | "Microsoft.VisualStudio.Component.Windows10SDK.19041", 11 | "Microsoft.VisualStudio.Component.Windows10SDK", 12 | "Microsoft.VisualStudio.ComponentGroup.MSIX.Packaging", 13 | "Microsoft.VisualStudio.ComponentGroup.WindowsAppSDK.Cs", 14 | "Microsoft.VisualStudio.Workload.ManagedDesktop" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /Assest/InstallIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiLins/MoreFlyout/602b4b84f22aa83cb7c818f3f139efffa964596c/Assest/InstallIcon.ico -------------------------------------------------------------------------------- /Assest/InstallIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiLins/MoreFlyout/602b4b84f22aa83cb7c818f3f139efffa964596c/Assest/InstallIcon.png -------------------------------------------------------------------------------- /Assest/Readme_Screenshots_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiLins/MoreFlyout/602b4b84f22aa83cb7c818f3f139efffa964596c/Assest/Readme_Screenshots_1.jpg -------------------------------------------------------------------------------- /Assest/Readme_Title.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiLins/MoreFlyout/602b4b84f22aa83cb7c818f3f139efffa964596c/Assest/Readme_Title.jpg -------------------------------------------------------------------------------- /Assest/Readme_Title.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiLins/MoreFlyout/602b4b84f22aa83cb7c818f3f139efffa964596c/Assest/Readme_Title.psd -------------------------------------------------------------------------------- /Assest/WindowIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiLins/MoreFlyout/602b4b84f22aa83cb7c818f3f139efffa964596c/Assest/WindowIcon.ico -------------------------------------------------------------------------------- /Assest/WindowIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiLins/MoreFlyout/602b4b84f22aa83cb7c818f3f139efffa964596c/Assest/WindowIcon.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /MoreFlyout.Server.Core/Contracts/Services/IFileService.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Server.Core.Contracts.Services; 2 | 3 | public interface IFileService 4 | { 5 | T Read(string folderPath, string fileName); 6 | 7 | void Save(string folderPath, string fileName, T content); 8 | 9 | void Delete(string folderPath, string fileName); 10 | } 11 | -------------------------------------------------------------------------------- /MoreFlyout.Server.Core/Helpers/Json.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace MoreFlyout.Server.Core.Helpers; 4 | 5 | public static class Json 6 | { 7 | public static async Task ToObjectAsync(string value) 8 | { 9 | return await Task.Run(() => 10 | { 11 | return JsonConvert.DeserializeObject(value); 12 | }); 13 | } 14 | 15 | public static async Task StringifyAsync(object value) 16 | { 17 | return await Task.Run(() => 18 | { 19 | return JsonConvert.SerializeObject(value); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /MoreFlyout.Server.Core/MoreFlyout.Server.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0 4 | MoreFlyout.Server.Core 5 | x86;x64;arm64;AnyCPU 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /MoreFlyout.Server.Core/README.md: -------------------------------------------------------------------------------- 1 | *Recommended Markdown Viewer: [Markdown Editor](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.MarkdownEditor2)* 2 | 3 | ## Getting Started 4 | 5 | The Core project contains code that can be [reused across multiple application projects](https://docs.microsoft.com/dotnet/standard/net-standard#net-5-and-net-standard). 6 | -------------------------------------------------------------------------------- /MoreFlyout.Server.Core/Services/FileService.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | using MoreFlyout.Server.Core.Contracts.Services; 4 | 5 | using Newtonsoft.Json; 6 | 7 | namespace MoreFlyout.Server.Core.Services; 8 | 9 | public class FileService : IFileService 10 | { 11 | public T Read(string folderPath, string fileName) 12 | { 13 | var path = Path.Combine(folderPath, fileName); 14 | if (File.Exists(path)) 15 | { 16 | var json = File.ReadAllText(path); 17 | return JsonConvert.DeserializeObject(json); 18 | } 19 | 20 | return default; 21 | } 22 | 23 | public void Save(string folderPath, string fileName, T content) 24 | { 25 | if (!Directory.Exists(folderPath)) 26 | { 27 | Directory.CreateDirectory(folderPath); 28 | } 29 | 30 | var fileContent = JsonConvert.SerializeObject(content); 31 | File.WriteAllText(Path.Combine(folderPath, fileName), fileContent, Encoding.UTF8); 32 | } 33 | 34 | public void Delete(string folderPath, string fileName) 35 | { 36 | if (fileName != null && File.Exists(Path.Combine(folderPath, fileName))) 37 | { 38 | File.Delete(Path.Combine(folderPath, fileName)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Activation/ActivationHandler.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Server.Activation; 2 | 3 | // Extend this class to implement new ActivationHandlers. See DefaultActivationHandler for an example. 4 | // https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/activation.md 5 | public abstract class ActivationHandler : IActivationHandler 6 | where T : class 7 | { 8 | // Override this method to add the logic for whether to handle the activation. 9 | protected virtual bool CanHandleInternal(T args) => true; 10 | 11 | // Override this method to add the logic for your activation handler. 12 | protected abstract Task HandleInternalAsync(T args); 13 | 14 | public bool CanHandle(object args) => args is T && CanHandleInternal((args as T)!); 15 | 16 | public async Task HandleAsync(object args) => await HandleInternalAsync((args as T)!); 17 | } 18 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Activation/DefaultActivationHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | 3 | using MoreFlyout.Server.Contracts.Services; 4 | using MoreFlyout.Server.ViewModels; 5 | 6 | namespace MoreFlyout.Server.Activation; 7 | 8 | public class DefaultActivationHandler : ActivationHandler 9 | { 10 | private readonly INavigationService _navigationService; 11 | 12 | public DefaultActivationHandler(INavigationService navigationService) 13 | { 14 | _navigationService = navigationService; 15 | } 16 | 17 | protected override bool CanHandleInternal(LaunchActivatedEventArgs args) 18 | { 19 | // None of the ActivationHandlers has handled the activation. 20 | return _navigationService.Frame?.Content == null; 21 | } 22 | 23 | protected async override Task HandleInternalAsync(LaunchActivatedEventArgs args) 24 | { 25 | _navigationService.NavigateTo(typeof(FlyoutViewModel).FullName!, args.Arguments); 26 | 27 | await Task.CompletedTask; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Activation/IActivationHandler.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Server.Activation; 2 | 3 | public interface IActivationHandler 4 | { 5 | bool CanHandle(object args); 6 | 7 | Task HandleAsync(object args); 8 | } 9 | -------------------------------------------------------------------------------- /MoreFlyout.Server/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /MoreFlyout.Server/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Hosting; 4 | using Microsoft.UI.Xaml; 5 | 6 | using MoreFlyout.Server.Activation; 7 | using MoreFlyout.Server.Contracts.Services; 8 | using MoreFlyout.Server.Core.Contracts.Services; 9 | using MoreFlyout.Server.Core.Services; 10 | using MoreFlyout.Server.Models; 11 | using MoreFlyout.Server.Services; 12 | using MoreFlyout.Server.ViewModels; 13 | using MoreFlyout.Server.Views; 14 | 15 | namespace MoreFlyout.Server; 16 | 17 | // To learn more about WinUI 3, see https://docs.microsoft.com/windows/apps/winui/winui3/. 18 | public partial class App : Application 19 | { 20 | // The .NET Generic Host provides dependency injection, configuration, logging, and other services. 21 | // https://docs.microsoft.com/dotnet/core/extensions/generic-host 22 | // https://docs.microsoft.com/dotnet/core/extensions/dependency-injection 23 | // https://docs.microsoft.com/dotnet/core/extensions/configuration 24 | // https://docs.microsoft.com/dotnet/core/extensions/logging 25 | public IHost Host 26 | { 27 | get; 28 | } 29 | 30 | public static T GetService() 31 | where T : class 32 | { 33 | if ((App.Current as App)!.Host.Services.GetService(typeof(T)) is not T service) 34 | { 35 | throw new ArgumentException($"{typeof(T)} needs to be registered in ConfigureServices within App.xaml.cs."); 36 | } 37 | 38 | return service; 39 | } 40 | 41 | public static WindowEx FlyoutWindow { get; } = new FlyoutWindow(); 42 | 43 | [RequiresUnreferencedCode("DynamicBehavior is incompatible with trimming.")] 44 | public App() 45 | { 46 | InitializeComponent(); 47 | 48 | Host = Microsoft.Extensions.Hosting.Host. 49 | CreateDefaultBuilder(). 50 | UseContentRoot(AppContext.BaseDirectory). 51 | ConfigureServices((context, services) => 52 | { 53 | // Default Activation Handler 54 | services.AddTransient, DefaultActivationHandler>(); 55 | 56 | // Other Activation Handlers 57 | 58 | // Services 59 | services.AddSingleton(); 60 | services.AddSingleton(); 61 | services.AddSingleton(); 62 | services.AddSingleton(); 63 | 64 | // Core Services 65 | services.AddSingleton(); 66 | 67 | // Views and ViewModels 68 | services.AddTransient(); 69 | services.AddTransient(); 70 | 71 | // Configuration 72 | services.Configure(context.Configuration.GetSection(nameof(LocalSettingsOptions))); 73 | }). 74 | Build(); 75 | 76 | UnhandledException += App_UnhandledException; 77 | } 78 | 79 | private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) 80 | { 81 | // TODO: Log and handle exceptions as appropriate. 82 | // https://docs.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.application.unhandledexception. 83 | } 84 | 85 | protected async override void OnLaunched(LaunchActivatedEventArgs args) 86 | { 87 | base.OnLaunched(args); 88 | 89 | await App.GetService().ActivateAsync(args); 90 | 91 | App.Current.DispatcherShutdownMode = DispatcherShutdownMode.OnExplicitShutdown; 92 | 93 | if (FlyoutWindow.Content is FrameworkElement rootElement) 94 | { 95 | rootElement.RequestedTheme = ElementTheme.Dark; 96 | FlyoutWindow.Content = rootElement; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Assets/WindowIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiLins/MoreFlyout/602b4b84f22aa83cb7c818f3f139efffa964596c/MoreFlyout.Server/Assets/WindowIcon.ico -------------------------------------------------------------------------------- /MoreFlyout.Server/Contracts/Services/IActivationService.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Server.Contracts.Services; 2 | 3 | public interface IActivationService 4 | { 5 | Task ActivateAsync(object activationArgs); 6 | } 7 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Contracts/Services/ILocalSettingsService.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Server.Contracts.Services; 2 | 3 | public interface ILocalSettingsService 4 | { 5 | Task ReadSettingAsync(string key); 6 | 7 | Task SaveSettingAsync(string key, T value); 8 | } 9 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Contracts/Services/INavigationService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml.Controls; 2 | using Microsoft.UI.Xaml.Navigation; 3 | 4 | namespace MoreFlyout.Server.Contracts.Services; 5 | 6 | public interface INavigationService 7 | { 8 | event NavigatedEventHandler Navigated; 9 | 10 | bool CanGoBack 11 | { 12 | get; 13 | } 14 | 15 | Frame? Frame 16 | { 17 | get; set; 18 | } 19 | 20 | bool NavigateTo(string pageKey, object? parameter = null, bool clearNavigation = false); 21 | 22 | bool GoBack(); 23 | } 24 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Contracts/Services/IPageService.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Server.Contracts.Services; 2 | 3 | public interface IPageService 4 | { 5 | Type GetPageType(string key); 6 | } 7 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Contracts/ViewModels/INavigationAware.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Server.Contracts.ViewModels; 2 | 3 | public interface INavigationAware 4 | { 5 | void OnNavigatedTo(object parameter); 6 | 7 | void OnNavigatedFrom(); 8 | } 9 | -------------------------------------------------------------------------------- /MoreFlyout.Server/FlyoutWindow.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | -------------------------------------------------------------------------------- /MoreFlyout.Server/FlyoutWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using Windows.Win32; 2 | using Windows.Win32.Foundation; 3 | using Windows.Win32.UI.WindowsAndMessaging; 4 | 5 | namespace MoreFlyout.Server; 6 | 7 | public sealed partial class FlyoutWindow : WindowEx 8 | { 9 | public FlyoutWindow() 10 | { 11 | InitializeComponent(); 12 | Content = null; 13 | 14 | // Change FlyoutWindow style 15 | var hWnd = (HWND)WinRT.Interop.WindowNative.GetWindowHandle(this); 16 | _ = PInvoke.SetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, PInvoke.GetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE) | (int)WINDOW_EX_STYLE.WS_EX_NOACTIVATE); 17 | this.SetWindowOpacity(0); 18 | 19 | // Set FlyoutWindow position 20 | var screenWidth = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CXSCREEN); 21 | var screenHeight = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CYSCREEN); 22 | var dpiForWindow = PInvoke.GetDpiForWindow(hWnd); 23 | var windowRatio = dpiForWindow / 96.0; 24 | AppWindow.Resize(new Windows.Graphics.SizeInt32((int)(195 * windowRatio), (int)(48 * windowRatio))); 25 | AppWindow.Move(new Windows.Graphics.PointInt32(screenWidth / 2 - (int)(195 / 2 * windowRatio), screenHeight - (int)(86 * windowRatio))); 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Helpers/FrameExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using Microsoft.UI.Xaml.Controls; 3 | 4 | namespace MoreFlyout.Server.Helpers; 5 | 6 | [RequiresUnreferencedCode("This functionality is not compatible with trimming.")] 7 | public static class FrameExtensions 8 | { 9 | public static object? GetPageViewModel(this Frame frame) => frame?.Content?.GetType().GetProperty("ViewModel")?.GetValue(frame.Content, null); 10 | } 11 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Helpers/ResourceExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Windows.ApplicationModel.Resources; 2 | 3 | namespace MoreFlyout.Server.Helpers; 4 | 5 | public static class ResourceExtensions 6 | { 7 | private static readonly ResourceLoader _resourceLoader = new(); 8 | 9 | public static string GetLocalized(this string resourceKey) => _resourceLoader.GetString(resourceKey); 10 | } 11 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Helpers/RuntimeHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using System.Text; 3 | 4 | namespace MoreFlyout.Server.Helpers; 5 | 6 | public class RuntimeHelper 7 | { 8 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 9 | private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder? packageFullName); 10 | 11 | public static bool IsMSIX 12 | { 13 | get 14 | { 15 | var length = 0; 16 | 17 | return GetCurrentPackageFullName(ref length, null) != 15700L; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Helpers/SettingsStorageExtensions.cs: -------------------------------------------------------------------------------- 1 | using MoreFlyout.Server.Core.Helpers; 2 | 3 | using Windows.Storage; 4 | using Windows.Storage.Streams; 5 | 6 | namespace MoreFlyout.Server.Helpers; 7 | 8 | // Use these extension methods to store and retrieve local and roaming app data 9 | // More details regarding storing and retrieving app data at https://docs.microsoft.com/windows/apps/design/app-settings/store-and-retrieve-app-data 10 | public static class SettingsStorageExtensions 11 | { 12 | private const string FileExtension = ".json"; 13 | 14 | public static bool IsRoamingStorageAvailable(this ApplicationData appData) 15 | { 16 | return appData.RoamingStorageQuota == 0; 17 | } 18 | 19 | public static async Task SaveAsync(this StorageFolder folder, string name, T content) 20 | { 21 | var file = await folder.CreateFileAsync(GetFileName(name), CreationCollisionOption.ReplaceExisting); 22 | var fileContent = await Json.StringifyAsync(content); 23 | 24 | await FileIO.WriteTextAsync(file, fileContent); 25 | } 26 | 27 | public static async Task ReadAsync(this StorageFolder folder, string name) 28 | { 29 | if (!File.Exists(Path.Combine(folder.Path, GetFileName(name)))) 30 | { 31 | return default; 32 | } 33 | 34 | var file = await folder.GetFileAsync($"{name}.json"); 35 | var fileContent = await FileIO.ReadTextAsync(file); 36 | 37 | return await Json.ToObjectAsync(fileContent); 38 | } 39 | 40 | public static async Task SaveAsync(this ApplicationDataContainer settings, string key, T value) 41 | { 42 | settings.SaveString(key, await Json.StringifyAsync(value)); 43 | } 44 | 45 | public static void SaveString(this ApplicationDataContainer settings, string key, string value) 46 | { 47 | settings.Values[key] = value; 48 | } 49 | 50 | public static async Task ReadAsync(this ApplicationDataContainer settings, string key) 51 | { 52 | object? obj; 53 | 54 | if (settings.Values.TryGetValue(key, out obj)) 55 | { 56 | return await Json.ToObjectAsync((string)obj); 57 | } 58 | 59 | return default; 60 | } 61 | 62 | public static async Task SaveFileAsync(this StorageFolder folder, byte[] content, string fileName, CreationCollisionOption options = CreationCollisionOption.ReplaceExisting) 63 | { 64 | if (content == null) 65 | { 66 | throw new ArgumentNullException(nameof(content)); 67 | } 68 | 69 | if (string.IsNullOrEmpty(fileName)) 70 | { 71 | throw new ArgumentException("File name is null or empty. Specify a valid file name", nameof(fileName)); 72 | } 73 | 74 | var storageFile = await folder.CreateFileAsync(fileName, options); 75 | await FileIO.WriteBytesAsync(storageFile, content); 76 | return storageFile; 77 | } 78 | 79 | public static async Task ReadFileAsync(this StorageFolder folder, string fileName) 80 | { 81 | var item = await folder.TryGetItemAsync(fileName).AsTask().ConfigureAwait(false); 82 | 83 | if ((item != null) && item.IsOfType(StorageItemTypes.File)) 84 | { 85 | var storageFile = await folder.GetFileAsync(fileName); 86 | var content = await storageFile.ReadBytesAsync(); 87 | return content; 88 | } 89 | 90 | return null; 91 | } 92 | 93 | public static async Task ReadBytesAsync(this StorageFile file) 94 | { 95 | if (file != null) 96 | { 97 | using IRandomAccessStream stream = await file.OpenReadAsync(); 98 | using var reader = new DataReader(stream.GetInputStreamAt(0)); 99 | await reader.LoadAsync((uint)stream.Size); 100 | var bytes = new byte[stream.Size]; 101 | reader.ReadBytes(bytes); 102 | return bytes; 103 | } 104 | 105 | return null; 106 | } 107 | 108 | private static string GetFileName(string name) 109 | { 110 | return string.Concat(name, FileExtension); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Models/LocalSettingsOptions.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Server.Models; 2 | 3 | public class LocalSettingsOptions 4 | { 5 | public string? ApplicationDataFolder 6 | { 7 | get; set; 8 | } 9 | 10 | public string? LocalSettingsFile 11 | { 12 | get; set; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MoreFlyout.Server/MoreFlyout.Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | WinExe 4 | net8.0-windows10.0.22621.0 5 | 10.0.17763.0 6 | 10.0.22621.38 7 | MoreFlyout.Server 8 | Assets/WindowIcon.ico 9 | app.manifest 10 | x86;x64;arm64 11 | win-x86;win-x64;win-arm64 12 | Properties\PublishProfiles\win-$(Platform).pubxml 13 | enable 14 | enable 15 | true 16 | true 17 | true 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | all 38 | runtime; build; native; contentfiles; analyzers; buildtransitive 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Always 54 | 55 | 56 | 57 | 58 | Always 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | true 68 | 69 | 70 | -------------------------------------------------------------------------------- /MoreFlyout.Server/NativeMethods.txt: -------------------------------------------------------------------------------- 1 | User32.* 2 | dwmapi.* 3 | 4 | RegisterWindowMessage 5 | GetModuleHandle 6 | GetCurrentThreadId 7 | 8 | WM_* 9 | CWPSTRUCT -------------------------------------------------------------------------------- /MoreFlyout.Server/Properties/PublishProfiles/win-arm64.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FileSystem 5 | arm64 6 | win-arm64 7 | bin\publish\win-arm64 8 | true 9 | false 10 | true 11 | partial 12 | Release 13 | net8.0-windows10.0.22621.0 14 | false 15 | 16 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Properties/PublishProfiles/win-x64.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FileSystem 5 | net8.0-windows10.0.22621.0 6 | x64 7 | win-x64 8 | true 9 | Release 10 | true 11 | partial 12 | bin\publish\$(RuntimeIdentifier) 13 | 16 | 17 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Properties/PublishProfiles/win-x86.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FileSystem 5 | x86 6 | win-x86 7 | bin\publish\win-x86 8 | true 9 | false 10 | Release 11 | net8.0-windows10.0.22621.0 12 | true 13 | partial 14 | 15 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Properties/launchsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "MoreFlyout.Server (Unpackaged)": { 4 | "commandName": "Project" 5 | }, 6 | "MoreFlyout.Server (Package)": { 7 | "commandName": "MsixPackage" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /MoreFlyout.Server/README.md: -------------------------------------------------------------------------------- 1 | *Recommended Markdown Viewer: [Markdown Editor](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.MarkdownEditor2)* 2 | 3 | ## Getting Started 4 | 5 | Browse and address `TODO:` comments in `View -> Task List` to learn the codebase and understand next steps for turning the generated code into production code. 6 | 7 | Explore the [WinUI Gallery](https://www.microsoft.com/store/productId/9P3JFPWWDZRC) to learn about available controls and design patterns. 8 | 9 | Relaunch Template Studio to modify the project by right-clicking on the project in `View -> Solution Explorer` then selecting `Add -> New Item (Template Studio)`. 10 | 11 | ## Publishing 12 | 13 | For projects with MSIX packaging, right-click on the application project and select `Package and Publish -> Create App Packages...` to create an MSIX package. 14 | 15 | For projects without MSIX packaging, follow the [deployment guide](https://docs.microsoft.com/windows/apps/windows-app-sdk/deploy-unpackaged-apps) or add the `Self-Contained` Feature to enable xcopy deployment. 16 | 17 | ## CI Pipelines 18 | 19 | See [README.md](https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/pipelines/README.md) for guidance on building and testing projects in CI pipelines. 20 | 21 | ## Changelog 22 | 23 | See [releases](https://github.com/microsoft/TemplateStudio/releases) and [milestones](https://github.com/microsoft/TemplateStudio/milestones). 24 | 25 | ## Feedback 26 | 27 | Bugs and feature requests should be filed at https://aka.ms/templatestudio. 28 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Services/ActivationService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | using Microsoft.UI.Xaml.Controls; 3 | 4 | using MoreFlyout.Server.Activation; 5 | using MoreFlyout.Server.Contracts.Services; 6 | 7 | namespace MoreFlyout.Server.Services; 8 | 9 | public class ActivationService : IActivationService 10 | { 11 | private readonly ActivationHandler _defaultHandler; 12 | private readonly IEnumerable _activationHandlers; 13 | private UIElement? _shell = null; 14 | 15 | public ActivationService(ActivationHandler defaultHandler, IEnumerable activationHandlers) 16 | { 17 | _defaultHandler = defaultHandler; 18 | _activationHandlers = activationHandlers; 19 | } 20 | 21 | public async Task ActivateAsync(object activationArgs) 22 | { 23 | // Execute tasks before activation. 24 | await InitializeAsync(); 25 | 26 | // Set the FlyoutWindow Content. 27 | if (App.FlyoutWindow.Content == null) 28 | { 29 | App.FlyoutWindow.Content = _shell ?? new Frame(); 30 | } 31 | 32 | // Handle activation via ActivationHandlers. 33 | await HandleActivationAsync(activationArgs); 34 | 35 | // Activate the FlyoutWindow. 36 | App.FlyoutWindow.Activate(); 37 | 38 | // Execute tasks after activation. 39 | await StartupAsync(); 40 | } 41 | 42 | private async Task HandleActivationAsync(object activationArgs) 43 | { 44 | var activationHandler = _activationHandlers.FirstOrDefault(h => h.CanHandle(activationArgs)); 45 | 46 | if (activationHandler != null) 47 | { 48 | await activationHandler.HandleAsync(activationArgs); 49 | } 50 | 51 | if (_defaultHandler.CanHandle(activationArgs)) 52 | { 53 | await _defaultHandler.HandleAsync(activationArgs); 54 | } 55 | } 56 | 57 | private async Task InitializeAsync() 58 | { 59 | await Task.CompletedTask; 60 | } 61 | 62 | private async Task StartupAsync() 63 | { 64 | await Task.CompletedTask; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Services/LocalSettingsService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Options; 2 | 3 | using MoreFlyout.Server.Contracts.Services; 4 | using MoreFlyout.Server.Core.Contracts.Services; 5 | using MoreFlyout.Server.Core.Helpers; 6 | using MoreFlyout.Server.Helpers; 7 | using MoreFlyout.Server.Models; 8 | using Windows.Storage; 9 | 10 | namespace MoreFlyout.Server.Services; 11 | 12 | public class LocalSettingsService : ILocalSettingsService 13 | { 14 | private const string _defaultApplicationDataFolder = "MoreFlyout.Server/ApplicationData"; 15 | private const string _defaultLocalSettingsFile = "LocalSettings.json"; 16 | 17 | private readonly IFileService _fileService; 18 | private readonly LocalSettingsOptions _options; 19 | 20 | private readonly string _localApplicationData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); 21 | private readonly string _applicationDataFolder; 22 | private readonly string _localsettingsFile; 23 | 24 | private IDictionary _settings; 25 | 26 | private bool _isInitialized; 27 | 28 | public LocalSettingsService(IFileService fileService, IOptions options) 29 | { 30 | _fileService = fileService; 31 | _options = options.Value; 32 | 33 | _applicationDataFolder = Path.Combine(_localApplicationData, _options.ApplicationDataFolder ?? _defaultApplicationDataFolder); 34 | _localsettingsFile = _options.LocalSettingsFile ?? _defaultLocalSettingsFile; 35 | 36 | _settings = new Dictionary(); 37 | } 38 | 39 | private async Task InitializeAsync() 40 | { 41 | if (!_isInitialized) 42 | { 43 | _settings = await Task.Run(() => _fileService.Read>(_applicationDataFolder, _localsettingsFile)) ?? new Dictionary(); 44 | 45 | _isInitialized = true; 46 | } 47 | } 48 | 49 | public async Task ReadSettingAsync(string key) 50 | { 51 | if (RuntimeHelper.IsMSIX) 52 | { 53 | if (ApplicationData.Current.LocalSettings.Values.TryGetValue(key, out var obj)) 54 | { 55 | return await Json.ToObjectAsync((string)obj); 56 | } 57 | } 58 | else 59 | { 60 | await InitializeAsync(); 61 | 62 | if (_settings != null && _settings.TryGetValue(key, out var obj)) 63 | { 64 | return await Json.ToObjectAsync((string)obj); 65 | } 66 | } 67 | 68 | return default; 69 | } 70 | 71 | public async Task SaveSettingAsync(string key, T value) 72 | { 73 | if (RuntimeHelper.IsMSIX) 74 | { 75 | ApplicationData.Current.LocalSettings.Values[key] = await Json.StringifyAsync(value); 76 | } 77 | else 78 | { 79 | await InitializeAsync(); 80 | 81 | _settings[key] = await Json.StringifyAsync(value); 82 | 83 | await Task.Run(() => _fileService.Save(_applicationDataFolder, _localsettingsFile, _settings)); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Services/NavigationService.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | using Microsoft.UI.Xaml.Controls; 4 | using Microsoft.UI.Xaml.Navigation; 5 | 6 | using MoreFlyout.Server.Contracts.Services; 7 | using MoreFlyout.Server.Contracts.ViewModels; 8 | using MoreFlyout.Server.Helpers; 9 | 10 | namespace MoreFlyout.Server.Services; 11 | 12 | // For more information on navigation between pages see 13 | // https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/navigation.md 14 | public class NavigationService : INavigationService 15 | { 16 | private readonly IPageService _pageService; 17 | private object? _lastParameterUsed; 18 | private Frame? _frame; 19 | 20 | public event NavigatedEventHandler? Navigated; 21 | 22 | public Frame? Frame 23 | { 24 | get 25 | { 26 | if (_frame == null) 27 | { 28 | _frame = App.FlyoutWindow.Content as Frame; 29 | RegisterFrameEvents(); 30 | } 31 | 32 | return _frame; 33 | } 34 | 35 | set 36 | { 37 | UnregisterFrameEvents(); 38 | _frame = value; 39 | RegisterFrameEvents(); 40 | } 41 | } 42 | 43 | [MemberNotNullWhen(true, nameof(Frame), nameof(_frame))] 44 | public bool CanGoBack => Frame != null && Frame.CanGoBack; 45 | 46 | public NavigationService(IPageService pageService) 47 | { 48 | _pageService = pageService; 49 | } 50 | 51 | private void RegisterFrameEvents() 52 | { 53 | if (_frame != null) 54 | { 55 | _frame.Navigated += OnNavigated; 56 | } 57 | } 58 | 59 | private void UnregisterFrameEvents() 60 | { 61 | if (_frame != null) 62 | { 63 | _frame.Navigated -= OnNavigated; 64 | } 65 | } 66 | 67 | public bool GoBack() 68 | { 69 | if (CanGoBack) 70 | { 71 | var vmBeforeNavigation = _frame.GetPageViewModel(); 72 | _frame.GoBack(); 73 | if (vmBeforeNavigation is INavigationAware navigationAware) 74 | { 75 | navigationAware.OnNavigatedFrom(); 76 | } 77 | 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | 84 | public bool NavigateTo(string pageKey, object? parameter = null, bool clearNavigation = false) 85 | { 86 | var pageType = _pageService.GetPageType(pageKey); 87 | 88 | if (_frame != null && (_frame.Content?.GetType() != pageType || (parameter != null && !parameter.Equals(_lastParameterUsed)))) 89 | { 90 | _frame.Tag = clearNavigation; 91 | var vmBeforeNavigation = _frame.GetPageViewModel(); 92 | var navigated = _frame.Navigate(pageType, parameter); 93 | if (navigated) 94 | { 95 | _lastParameterUsed = parameter; 96 | if (vmBeforeNavigation is INavigationAware navigationAware) 97 | { 98 | navigationAware.OnNavigatedFrom(); 99 | } 100 | } 101 | 102 | return navigated; 103 | } 104 | 105 | return false; 106 | } 107 | 108 | private void OnNavigated(object sender, NavigationEventArgs e) 109 | { 110 | if (sender is Frame frame) 111 | { 112 | var clearNavigation = (bool)frame.Tag; 113 | if (clearNavigation) 114 | { 115 | frame.BackStack.Clear(); 116 | } 117 | 118 | if (frame.GetPageViewModel() is INavigationAware navigationAware) 119 | { 120 | navigationAware.OnNavigatedTo(e.Parameter); 121 | } 122 | 123 | Navigated?.Invoke(sender, e); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Services/PageService.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | using Microsoft.UI.Xaml.Controls; 4 | 5 | using MoreFlyout.Server.Contracts.Services; 6 | using MoreFlyout.Server.ViewModels; 7 | using MoreFlyout.Server.Views; 8 | 9 | namespace MoreFlyout.Server.Services; 10 | 11 | public class PageService : IPageService 12 | { 13 | private readonly Dictionary _pages = []; 14 | 15 | public PageService() 16 | { 17 | Configure(); 18 | } 19 | 20 | public Type GetPageType(string key) 21 | { 22 | Type? pageType; 23 | lock (_pages) 24 | { 25 | if (!_pages.TryGetValue(key, out pageType)) 26 | { 27 | throw new ArgumentException($"Page not found: {key}. Did you forget to call PageService.Configure?"); 28 | } 29 | } 30 | 31 | return pageType; 32 | } 33 | 34 | private void Configure() 35 | where VM : ObservableObject 36 | where V : Page 37 | { 38 | lock (_pages) 39 | { 40 | var key = typeof(VM).FullName!; 41 | if (_pages.ContainsKey(key)) 42 | { 43 | throw new ArgumentException($"The key {key} is already configured in PageService"); 44 | } 45 | 46 | var type = typeof(V); 47 | if (_pages.ContainsValue(type)) 48 | { 49 | throw new ArgumentException($"This type is already configured with key {_pages.First(p => p.Value == type).Key}"); 50 | } 51 | 52 | _pages.Add(key, type); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Strings/en-us/Resources.resw: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | text/microsoft-resx 51 | 52 | 53 | 2.0 54 | 55 | 56 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 57 | 58 | 59 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 60 | 61 | 62 | MoreFlyout.Server 63 | 64 | 65 | MoreFlyout.Server 66 | 67 | 68 | The number keys are not locked 69 | 70 | 71 | The number keys are locked 72 | 73 | 74 | The caps keys are not locked 75 | 76 | 77 | The caps keys are locked 78 | 79 | 80 | About this project 81 | 82 | 83 | Quit 84 | 85 | 86 | Start with computer 87 | 88 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Strings/zh-CN/Resources.resw: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 数字键未锁定 122 | 123 | 124 | MoreFlyout.Server 125 | 126 | 127 | MoreFlyout.Server 128 | 129 | 130 | 数字键已锁定 131 | 132 | 133 | 大写键未锁定 134 | 135 | 136 | 大写键已锁定 137 | 138 | 139 | 关于这个项目 140 | 141 | 142 | 退出 143 | 144 | 145 | 开机自启 146 | 147 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Styles/FontSizes.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 24 4 | 5 | 16 6 | 7 | 8 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Styles/TextBlock.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 10 | 11 | 17 | 18 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Styles/Thickness.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 0,36,0,0 4 | 0,36,0,36 5 | 6 | 0,24,0,0 7 | 0,24,0,24 8 | 24,0,24,0 9 | 0,0,0,24 10 | 11 | 12,0,0,0 12 | 12,0,12,0 13 | 0,12,0,0 14 | 0,0,12,0 15 | 0,12,0,12 16 | 17 | 8,0,0,0 18 | 0,8,0,0 19 | 8,8,8,8 20 | 21 | 0,4,0,0 22 | 4,4,4,4 23 | 24 | 1,1,0,0 25 | 8,0,0,0 26 | 0,48,0,0 27 | 56,34,0,0 28 | 56,24,56,0 29 | 30 | 36,24,36,0 31 | 32 | -12,4,0,0 33 | 34 | 35 | -------------------------------------------------------------------------------- /MoreFlyout.Server/TemplateStudio.xml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Usings.cs: -------------------------------------------------------------------------------- 1 | global using WinUIEx; 2 | -------------------------------------------------------------------------------- /MoreFlyout.Server/ViewModels/FlyoutViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace MoreFlyout.Server.ViewModels; 4 | 5 | public partial class FlyoutViewModel : ObservableRecipient 6 | { 7 | public FlyoutViewModel() 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Views/FlyoutPage.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /MoreFlyout.Server/Views/FlyoutPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.InteropServices; 3 | using Microsoft.UI.Composition; 4 | using Microsoft.UI.Composition.SystemBackdrops; 5 | using Microsoft.UI.Xaml; 6 | using Microsoft.UI.Xaml.Controls; 7 | using MoreFlyout.Server.Contracts.Services; 8 | using MoreFlyout.Server.Helpers; 9 | using MoreFlyout.Server.ViewModels; 10 | using Windows.Win32; 11 | using Windows.Win32.Foundation; 12 | using Windows.Win32.UI.WindowsAndMessaging; 13 | 14 | namespace MoreFlyout.Server.Views; 15 | 16 | public sealed partial class FlyoutPage : Page 17 | { 18 | // DispatcherTimer to instead Timer 19 | private readonly DispatcherTimer hiddenTimer; 20 | 21 | // This static assignment will ensure GC doesn't move the procedure around 22 | private static readonly HOOKPROC _keyboardHook = KeyboardCallback; 23 | private static readonly HOOKPROC _callWndProcHook = CallWndProcCallback; 24 | private static readonly UnhookWindowsHookExSafeHandle _keyboardHookId; 25 | private static readonly UnhookWindowsHookExSafeHandle _callWndProcHookId; 26 | 27 | // Define different key event codes 28 | private const int WM_KEYDOWN = 0x0100; 29 | private const int VK_NUMLOCK = 0x90; 30 | private const int VK_CAPSLOCK = 0x14; 31 | 32 | // Define key state 33 | private static bool numKeyState = false; 34 | private static bool capsKeyState = false; 35 | 36 | public FlyoutViewModel ViewModel 37 | { 38 | get; 39 | } 40 | 41 | static FlyoutPage() 42 | { 43 | // Hook here (expected to be done in UI thread in our case, it facilitates everything) 44 | _keyboardHookId = PInvoke.SetWindowsHookEx(WINDOWS_HOOK_ID.WH_KEYBOARD_LL, _keyboardHook, null, 0); 45 | var hModule = PInvoke.GetModuleHandle(Process.GetCurrentProcess().MainModule!.ModuleName); 46 | _callWndProcHookId = PInvoke.SetWindowsHookEx(WINDOWS_HOOK_ID.WH_CALLWNDPROC, _callWndProcHook, hModule, PInvoke.GetCurrentThreadId()); 47 | 48 | // Unhook on exit (more or less useless) 49 | AppDomain.CurrentDomain.ProcessExit += (s, e) => { _keyboardHookId.Close(); }; 50 | AppDomain.CurrentDomain.ProcessExit += (s, e) => { _callWndProcHookId.Close(); }; 51 | } 52 | 53 | public FlyoutPage() 54 | { 55 | ViewModel = App.GetService(); 56 | InitializeComponent(); 57 | 58 | // Set DispatcherTimer to control the window will disappear after a certain period of time 59 | hiddenTimer = new DispatcherTimer 60 | { 61 | Interval = new TimeSpan(0, 0, 0, 0, 2800) 62 | }; 63 | hiddenTimer.Stop(); 64 | 65 | // Get the key state 66 | numKeyState = (PInvoke.GetKeyState(VK_NUMLOCK) & 1) == 1; 67 | capsKeyState = (PInvoke.GetKeyState(VK_CAPSLOCK) & 1) == 1; 68 | 69 | //Microsoft.Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = "en-us"; 70 | } 71 | 72 | // The hook function must be static 73 | private static LRESULT KeyboardCallback(int nCode, WPARAM wParam, LPARAM lParam) 74 | { 75 | // Lucky us WH_KEYBOARD_LL calls back on initial hooking thread, ie: the UI thread 76 | // so no need for Dispatcher mumbo jumbo 77 | 78 | // Get your navigation service and defer to the instance method if found 79 | var navigation = App.GetService(); 80 | if (navigation?.Frame != null) 81 | { 82 | if (navigation.Frame.Content is not FlyoutPage) 83 | { 84 | navigation.NavigateTo(typeof(FlyoutViewModel).FullName!); 85 | } 86 | 87 | if (navigation.Frame.Content is FlyoutPage page) 88 | { 89 | page.KeyboardHookCallback(nCode, wParam, lParam); 90 | } 91 | } 92 | return PInvoke.CallNextHookEx(_keyboardHookId, nCode, wParam, lParam); 93 | } 94 | 95 | private static LRESULT CallWndProcCallback(int nCode, WPARAM wParam, LPARAM lParam) 96 | { 97 | // Get your navigation service and defer to the instance method if found 98 | var navigation = App.GetService(); 99 | if (navigation?.Frame != null) 100 | { 101 | if (navigation.Frame.Content is not FlyoutPage) 102 | { 103 | navigation.NavigateTo(typeof(FlyoutViewModel).FullName!); 104 | } 105 | 106 | if (navigation.Frame.Content is FlyoutPage) 107 | { 108 | CallWndProcHookCallback(nCode, wParam, lParam); 109 | } 110 | } 111 | return PInvoke.CallNextHookEx(_callWndProcHookId, nCode, wParam, lParam); 112 | } 113 | 114 | private void KeyboardHookCallback(int nCode, WPARAM wParam, LPARAM lParam) 115 | { 116 | if (nCode >= 0 && wParam == WM_KEYDOWN) 117 | { 118 | var vkCode = Marshal.ReadInt32(lParam); 119 | 120 | if (App.FlyoutWindow.IsAlwaysOnTop == false) App.FlyoutWindow.IsAlwaysOnTop = true; 121 | 122 | if (vkCode == VK_NUMLOCK || vkCode == VK_CAPSLOCK) 123 | { 124 | switch (vkCode) 125 | { 126 | case VK_NUMLOCK: 127 | StatusTextBlock.Text = numKeyState ? "StatusWords_NumUnlock".GetLocalized() : "StatusWords_NumLock".GetLocalized(); 128 | StatusFontIcon.Glyph = numKeyState ? "\uE785" : "\uE72E"; 129 | numKeyState = !numKeyState; 130 | break; 131 | case VK_CAPSLOCK: 132 | StatusTextBlock.Text = capsKeyState ? "StatusWords_CapsUnlock".GetLocalized() : "StatusWords_CapsLock".GetLocalized(); 133 | StatusFontIcon.Glyph = capsKeyState ? "\uE785" : "\uE72E"; 134 | capsKeyState = !capsKeyState; 135 | break; 136 | } 137 | if (FlyoutPageContextFlyout.IsOpen == false && IsFullScreenActive() == false) FlyoutPageContextFlyout.ShowAt(this); 138 | RunTimer(); 139 | } 140 | } 141 | } 142 | 143 | private static void CallWndProcHookCallback(int nCode, WPARAM wParam, LPARAM lParam) 144 | { 145 | if (nCode >= 0) 146 | { 147 | var msg = Marshal.PtrToStructure(lParam); 148 | if (msg.message == PInvoke.RegisterWindowMessage("TaskbarCreated")) 149 | { 150 | App.FlyoutWindow.IsShownInSwitchers = true; 151 | App.FlyoutWindow.IsShownInSwitchers = false; 152 | } 153 | } 154 | } 155 | 156 | private void RunTimer() 157 | { 158 | if (hiddenTimer.IsEnabled == false) 159 | { 160 | hiddenTimer.Start(); 161 | hiddenTimer.Tick += (sender, e) => 162 | { 163 | if (FlyoutPageContextFlyout.IsOpen) FlyoutPageContextFlyout.Hide(); 164 | hiddenTimer.Stop(); 165 | }; 166 | } 167 | else 168 | { 169 | hiddenTimer.Stop(); 170 | } 171 | hiddenTimer.Start(); 172 | } 173 | 174 | private unsafe bool IsFullScreenActive() 175 | { 176 | var isFullScreen = true; 177 | const int MAX_PATH = 260; 178 | Span buffer = new char[MAX_PATH + 1]; 179 | 180 | var screenWidth = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CXSCREEN); 181 | var screenHeight = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CYSCREEN); 182 | 183 | System.Drawing.Point[] screenCorners = 184 | [ 185 | new(1, screenHeight - 1), 186 | new(screenWidth - 1, screenHeight - 1) 187 | ]; 188 | 189 | foreach (var corner in screenCorners) 190 | { 191 | var hWnd = PInvoke.WindowFromPoint(corner); 192 | 193 | fixed (char* pBuffer = buffer) 194 | { 195 | PWSTR pWSTR = pBuffer; 196 | _ = PInvoke.GetClassName(hWnd, pWSTR, MAX_PATH); 197 | if (pWSTR.ToString() == "Shell_TrayWnd" || pWSTR.ToString() == "TrayNotifyWnd") isFullScreen = false; 198 | } 199 | } 200 | 201 | return isFullScreen; 202 | } 203 | 204 | } 205 | 206 | public partial class AcrylicSystemBackdrop : Microsoft.UI.Xaml.Media.SystemBackdrop 207 | { 208 | private DesktopAcrylicController? acrylicController; 209 | 210 | protected override void OnTargetConnected(ICompositionSupportsSystemBackdrop connectedTarget, XamlRoot xamlRoot) 211 | { 212 | // Call the base method to initialize the default configuration object. 213 | base.OnTargetConnected(connectedTarget, xamlRoot); 214 | 215 | // This example does not support sharing MicaSystemBackdrop instances. 216 | if (acrylicController is not null) 217 | { 218 | throw new Exception("This controller cannot be shared"); 219 | } 220 | 221 | acrylicController = new DesktopAcrylicController(); 222 | 223 | // Set configuration. 224 | var defaultConfig = GetDefaultSystemBackdropConfiguration(connectedTarget, xamlRoot); 225 | defaultConfig.IsInputActive = true; 226 | defaultConfig.Theme = SystemBackdropTheme.Dark; 227 | acrylicController.SetSystemBackdropConfiguration(defaultConfig); 228 | 229 | // Add target. 230 | acrylicController.AddSystemBackdropTarget(connectedTarget); 231 | } 232 | 233 | protected override void OnTargetDisconnected(ICompositionSupportsSystemBackdrop disconnectedTarget) 234 | { 235 | base.OnTargetDisconnected(disconnectedTarget); 236 | 237 | acrylicController?.RemoveSystemBackdropTarget(disconnectedTarget); 238 | acrylicController = null; 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /MoreFlyout.Server/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | true/PM 12 | PerMonitorV2, PerMonitor 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /MoreFlyout.Server/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "LocalSettingsOptions": { 3 | "ApplicationDataFolder": "MoreFlyout.Server/ApplicationData", 4 | "LocalSettingsFile": "LocalSettings.json" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /MoreFlyout.Shell.Core/Contracts/Services/IFileService.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Shell.Core.Contracts.Services; 2 | 3 | public interface IFileService 4 | { 5 | T Read(string folderPath, string fileName); 6 | 7 | void Save(string folderPath, string fileName, T content); 8 | 9 | void Delete(string folderPath, string fileName); 10 | } 11 | -------------------------------------------------------------------------------- /MoreFlyout.Shell.Core/Helpers/Json.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace MoreFlyout.Shell.Core.Helpers; 4 | 5 | public static class Json 6 | { 7 | public static async Task ToObjectAsync(string value) 8 | { 9 | return await Task.Run(() => 10 | { 11 | return JsonConvert.DeserializeObject(value); 12 | }); 13 | } 14 | 15 | public static async Task StringifyAsync(object value) 16 | { 17 | return await Task.Run(() => 18 | { 19 | return JsonConvert.SerializeObject(value); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /MoreFlyout.Shell.Core/MoreFlyout.Shell.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0 4 | MoreFlyout.Shell.Core 5 | x86;x64;arm64;AnyCPU 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /MoreFlyout.Shell.Core/README.md: -------------------------------------------------------------------------------- 1 | *Recommended Markdown Viewer: [Markdown Editor](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.MarkdownEditor2)* 2 | 3 | ## Getting Started 4 | 5 | The Core project contains code that can be [reused across multiple application projects](https://docs.microsoft.com/dotnet/standard/net-standard#net-5-and-net-standard). 6 | -------------------------------------------------------------------------------- /MoreFlyout.Shell.Core/Services/FileService.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | using MoreFlyout.Shell.Core.Contracts.Services; 4 | 5 | using Newtonsoft.Json; 6 | 7 | namespace MoreFlyout.Shell.Core.Services; 8 | 9 | public class FileService : IFileService 10 | { 11 | public T Read(string folderPath, string fileName) 12 | { 13 | var path = Path.Combine(folderPath, fileName); 14 | if (File.Exists(path)) 15 | { 16 | var json = File.ReadAllText(path); 17 | return JsonConvert.DeserializeObject(json); 18 | } 19 | 20 | return default; 21 | } 22 | 23 | public void Save(string folderPath, string fileName, T content) 24 | { 25 | if (!Directory.Exists(folderPath)) 26 | { 27 | Directory.CreateDirectory(folderPath); 28 | } 29 | 30 | var fileContent = JsonConvert.SerializeObject(content); 31 | File.WriteAllText(Path.Combine(folderPath, fileName), fileContent, Encoding.UTF8); 32 | } 33 | 34 | public void Delete(string folderPath, string fileName) 35 | { 36 | if (fileName != null && File.Exists(Path.Combine(folderPath, fileName))) 37 | { 38 | File.Delete(Path.Combine(folderPath, fileName)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Activation/ActivationHandler.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Shell.Activation; 2 | 3 | // Extend this class to implement new ActivationHandlers. See DefaultActivationHandler for an example. 4 | // https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/activation.md 5 | public abstract class ActivationHandler : IActivationHandler 6 | where T : class 7 | { 8 | // Override this method to add the logic for whether to handle the activation. 9 | protected virtual bool CanHandleInternal(T args) => true; 10 | 11 | // Override this method to add the logic for your activation handler. 12 | protected abstract Task HandleInternalAsync(T args); 13 | 14 | public bool CanHandle(object args) => args is T && CanHandleInternal((args as T)!); 15 | 16 | public async Task HandleAsync(object args) => await HandleInternalAsync((args as T)!); 17 | } 18 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Activation/DefaultActivationHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | 3 | using MoreFlyout.Shell.Contracts.Services; 4 | using MoreFlyout.Shell.ViewModels; 5 | 6 | namespace MoreFlyout.Shell.Activation; 7 | 8 | public class DefaultActivationHandler : ActivationHandler 9 | { 10 | private readonly INavigationService _navigationService; 11 | 12 | public DefaultActivationHandler(INavigationService navigationService) 13 | { 14 | _navigationService = navigationService; 15 | } 16 | 17 | protected override bool CanHandleInternal(LaunchActivatedEventArgs args) 18 | { 19 | // None of the ActivationHandlers has handled the activation. 20 | return _navigationService.Frame?.Content == null; 21 | } 22 | 23 | protected async override Task HandleInternalAsync(LaunchActivatedEventArgs args) 24 | { 25 | _navigationService.NavigateTo(typeof(MainViewModel).FullName!, args.Arguments); 26 | 27 | await Task.CompletedTask; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Activation/IActivationHandler.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Shell.Activation; 2 | 3 | public interface IActivationHandler 4 | { 5 | bool CanHandle(object args); 6 | 7 | Task HandleAsync(object args); 8 | } 9 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Hosting; 3 | using Microsoft.UI.Xaml; 4 | 5 | using MoreFlyout.Shell.Activation; 6 | using MoreFlyout.Shell.Contracts.Services; 7 | using MoreFlyout.Shell.Core.Contracts.Services; 8 | using MoreFlyout.Shell.Core.Services; 9 | using MoreFlyout.Shell.Models; 10 | using MoreFlyout.Shell.Services; 11 | using MoreFlyout.Shell.ViewModels; 12 | using MoreFlyout.Shell.Views; 13 | 14 | namespace MoreFlyout.Shell; 15 | 16 | // To learn more about WinUI 3, see https://docs.microsoft.com/windows/apps/winui/winui3/. 17 | public partial class App : Application 18 | { 19 | // The .NET Generic Host provides dependency injection, configuration, logging, and other services. 20 | // https://docs.microsoft.com/dotnet/core/extensions/generic-host 21 | // https://docs.microsoft.com/dotnet/core/extensions/dependency-injection 22 | // https://docs.microsoft.com/dotnet/core/extensions/configuration 23 | // https://docs.microsoft.com/dotnet/core/extensions/logging 24 | public IHost Host 25 | { 26 | get; 27 | } 28 | 29 | public static T GetService() 30 | where T : class 31 | { 32 | if ((App.Current as App)!.Host.Services.GetService(typeof(T)) is not T service) 33 | { 34 | throw new ArgumentException($"{typeof(T)} needs to be registered in ConfigureServices within App.xaml.cs."); 35 | } 36 | 37 | return service; 38 | } 39 | 40 | public static WindowEx MainWindow { get; } = new MainWindow(); 41 | 42 | public static UIElement? AppTitlebar 43 | { 44 | get; set; 45 | } 46 | 47 | public App() 48 | { 49 | InitializeComponent(); 50 | 51 | Host = Microsoft.Extensions.Hosting.Host. 52 | CreateDefaultBuilder(). 53 | UseContentRoot(AppContext.BaseDirectory). 54 | ConfigureServices((context, services) => 55 | { 56 | // Default Activation Handler 57 | services.AddTransient, DefaultActivationHandler>(); 58 | 59 | // Other Activation Handlers 60 | 61 | // Services 62 | services.AddSingleton(); 63 | services.AddSingleton(); 64 | services.AddSingleton(); 65 | services.AddSingleton(); 66 | services.AddSingleton(); 67 | 68 | // Core Services 69 | services.AddSingleton(); 70 | 71 | // Views and ViewModels 72 | services.AddTransient(); 73 | services.AddTransient(); 74 | 75 | // Configuration 76 | services.Configure(context.Configuration.GetSection(nameof(LocalSettingsOptions))); 77 | }). 78 | Build(); 79 | 80 | UnhandledException += App_UnhandledException; 81 | } 82 | 83 | private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) 84 | { 85 | // TODO: Log and handle exceptions as appropriate. 86 | // https://docs.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.application.unhandledexception. 87 | } 88 | 89 | protected async override void OnLaunched(LaunchActivatedEventArgs args) 90 | { 91 | base.OnLaunched(args); 92 | 93 | await App.GetService().ActivateAsync(args); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Assets/WindowIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChenYiLins/MoreFlyout/602b4b84f22aa83cb7c818f3f139efffa964596c/MoreFlyout.Shell/Assets/WindowIcon.ico -------------------------------------------------------------------------------- /MoreFlyout.Shell/Contracts/Services/IActivationService.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Shell.Contracts.Services; 2 | 3 | public interface IActivationService 4 | { 5 | Task ActivateAsync(object activationArgs); 6 | } 7 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Contracts/Services/ILocalSettingsService.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Shell.Contracts.Services; 2 | 3 | public interface ILocalSettingsService 4 | { 5 | Task ReadSettingAsync(string key); 6 | 7 | Task SaveSettingAsync(string key, T value); 8 | } 9 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Contracts/Services/INavigationService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml.Controls; 2 | using Microsoft.UI.Xaml.Navigation; 3 | 4 | namespace MoreFlyout.Shell.Contracts.Services; 5 | 6 | public interface INavigationService 7 | { 8 | event NavigatedEventHandler Navigated; 9 | 10 | bool CanGoBack 11 | { 12 | get; 13 | } 14 | 15 | Frame? Frame 16 | { 17 | get; set; 18 | } 19 | 20 | bool NavigateTo(string pageKey, object? parameter = null, bool clearNavigation = false); 21 | 22 | bool GoBack(); 23 | } 24 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Contracts/Services/IPageService.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Shell.Contracts.Services; 2 | 3 | public interface IPageService 4 | { 5 | Type GetPageType(string key); 6 | } 7 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Contracts/Services/IThemeSelectorService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | 3 | namespace MoreFlyout.Shell.Contracts.Services; 4 | 5 | public interface IThemeSelectorService 6 | { 7 | ElementTheme Theme 8 | { 9 | get; 10 | } 11 | 12 | Task InitializeAsync(); 13 | 14 | Task SetThemeAsync(ElementTheme theme); 15 | 16 | Task SetRequestedThemeAsync(); 17 | } 18 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Contracts/ViewModels/INavigationAware.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Shell.Contracts.ViewModels; 2 | 3 | public interface INavigationAware 4 | { 5 | void OnNavigatedTo(object parameter); 6 | 7 | void OnNavigatedFrom(); 8 | } 9 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Helpers/FrameExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using Microsoft.UI.Xaml.Controls; 3 | 4 | namespace MoreFlyout.Shell.Helpers; 5 | 6 | [RequiresUnreferencedCode("This functionality is not compatible with trimming.")] 7 | public static class FrameExtensions 8 | { 9 | public static object? GetPageViewModel(this Frame frame) => frame?.Content?.GetType().GetProperty("ViewModel")?.GetValue(frame.Content, null); 10 | } 11 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Helpers/ResourceExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Windows.ApplicationModel.Resources; 2 | 3 | namespace MoreFlyout.Shell.Helpers; 4 | 5 | public static class ResourceExtensions 6 | { 7 | private static readonly ResourceLoader _resourceLoader = new(); 8 | 9 | public static string GetLocalized(this string resourceKey) => _resourceLoader.GetString(resourceKey); 10 | } 11 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Helpers/RuntimeHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using System.Text; 3 | 4 | namespace MoreFlyout.Shell.Helpers; 5 | 6 | public class RuntimeHelper 7 | { 8 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 9 | private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder? packageFullName); 10 | 11 | public static bool IsMSIX 12 | { 13 | get 14 | { 15 | var length = 0; 16 | 17 | return GetCurrentPackageFullName(ref length, null) != 15700L; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Helpers/SettingsStorageExtensions.cs: -------------------------------------------------------------------------------- 1 | using MoreFlyout.Shell.Core.Helpers; 2 | 3 | using Windows.Storage; 4 | using Windows.Storage.Streams; 5 | 6 | namespace MoreFlyout.Shell.Helpers; 7 | 8 | // Use these extension methods to store and retrieve local and roaming app data 9 | // More details regarding storing and retrieving app data at https://docs.microsoft.com/windows/apps/design/app-settings/store-and-retrieve-app-data 10 | public static class SettingsStorageExtensions 11 | { 12 | private const string FileExtension = ".json"; 13 | 14 | public static bool IsRoamingStorageAvailable(this ApplicationData appData) 15 | { 16 | return appData.RoamingStorageQuota == 0; 17 | } 18 | 19 | public static async Task SaveAsync(this StorageFolder folder, string name, T content) 20 | { 21 | var file = await folder.CreateFileAsync(GetFileName(name), CreationCollisionOption.ReplaceExisting); 22 | var fileContent = await Json.StringifyAsync(content); 23 | 24 | await FileIO.WriteTextAsync(file, fileContent); 25 | } 26 | 27 | public static async Task ReadAsync(this StorageFolder folder, string name) 28 | { 29 | if (!File.Exists(Path.Combine(folder.Path, GetFileName(name)))) 30 | { 31 | return default; 32 | } 33 | 34 | var file = await folder.GetFileAsync($"{name}.json"); 35 | var fileContent = await FileIO.ReadTextAsync(file); 36 | 37 | return await Json.ToObjectAsync(fileContent); 38 | } 39 | 40 | public static async Task SaveAsync(this ApplicationDataContainer settings, string key, T value) 41 | { 42 | settings.SaveString(key, await Json.StringifyAsync(value)); 43 | } 44 | 45 | public static void SaveString(this ApplicationDataContainer settings, string key, string value) 46 | { 47 | settings.Values[key] = value; 48 | } 49 | 50 | public static async Task ReadAsync(this ApplicationDataContainer settings, string key) 51 | { 52 | object? obj; 53 | 54 | if (settings.Values.TryGetValue(key, out obj)) 55 | { 56 | return await Json.ToObjectAsync((string)obj); 57 | } 58 | 59 | return default; 60 | } 61 | 62 | public static async Task SaveFileAsync(this StorageFolder folder, byte[] content, string fileName, CreationCollisionOption options = CreationCollisionOption.ReplaceExisting) 63 | { 64 | if (content == null) 65 | { 66 | throw new ArgumentNullException(nameof(content)); 67 | } 68 | 69 | if (string.IsNullOrEmpty(fileName)) 70 | { 71 | throw new ArgumentException("File name is null or empty. Specify a valid file name", nameof(fileName)); 72 | } 73 | 74 | var storageFile = await folder.CreateFileAsync(fileName, options); 75 | await FileIO.WriteBytesAsync(storageFile, content); 76 | return storageFile; 77 | } 78 | 79 | public static async Task ReadFileAsync(this StorageFolder folder, string fileName) 80 | { 81 | var item = await folder.TryGetItemAsync(fileName).AsTask().ConfigureAwait(false); 82 | 83 | if ((item != null) && item.IsOfType(StorageItemTypes.File)) 84 | { 85 | var storageFile = await folder.GetFileAsync(fileName); 86 | var content = await storageFile.ReadBytesAsync(); 87 | return content; 88 | } 89 | 90 | return null; 91 | } 92 | 93 | public static async Task ReadBytesAsync(this StorageFile file) 94 | { 95 | if (file != null) 96 | { 97 | using IRandomAccessStream stream = await file.OpenReadAsync(); 98 | using var reader = new DataReader(stream.GetInputStreamAt(0)); 99 | await reader.LoadAsync((uint)stream.Size); 100 | var bytes = new byte[stream.Size]; 101 | reader.ReadBytes(bytes); 102 | return bytes; 103 | } 104 | 105 | return null; 106 | } 107 | 108 | private static string GetFileName(string name) 109 | { 110 | return string.Concat(name, FileExtension); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Helpers/TitleBarHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | using Microsoft.UI; 4 | using Microsoft.UI.Xaml; 5 | using Microsoft.UI.Xaml.Media; 6 | 7 | using Windows.UI; 8 | using Windows.UI.ViewManagement; 9 | 10 | namespace MoreFlyout.Shell.Helpers; 11 | 12 | // Helper class to workaround custom title bar bugs. 13 | // DISCLAIMER: The resource key names and color values used below are subject to change. Do not depend on them. 14 | // https://github.com/microsoft/TemplateStudio/issues/4516 15 | internal class TitleBarHelper 16 | { 17 | private const int WAINACTIVE = 0x00; 18 | private const int WAACTIVE = 0x01; 19 | private const int WMACTIVATE = 0x0006; 20 | 21 | [DllImport("user32.dll")] 22 | private static extern IntPtr GetActiveWindow(); 23 | 24 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 25 | private static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam); 26 | 27 | public static void UpdateTitleBar(ElementTheme theme) 28 | { 29 | if (App.MainWindow.ExtendsContentIntoTitleBar) 30 | { 31 | if (theme == ElementTheme.Default) 32 | { 33 | var uiSettings = new UISettings(); 34 | var background = uiSettings.GetColorValue(UIColorType.Background); 35 | 36 | theme = background == Colors.White ? ElementTheme.Light : ElementTheme.Dark; 37 | } 38 | 39 | if (theme == ElementTheme.Default) 40 | { 41 | theme = Application.Current.RequestedTheme == ApplicationTheme.Light ? ElementTheme.Light : ElementTheme.Dark; 42 | } 43 | 44 | App.MainWindow.AppWindow.TitleBar.ButtonForegroundColor = theme switch 45 | { 46 | ElementTheme.Dark => Colors.White, 47 | ElementTheme.Light => Colors.Black, 48 | _ => Colors.Transparent 49 | }; 50 | 51 | App.MainWindow.AppWindow.TitleBar.ButtonHoverForegroundColor = theme switch 52 | { 53 | ElementTheme.Dark => Colors.White, 54 | ElementTheme.Light => Colors.Black, 55 | _ => Colors.Transparent 56 | }; 57 | 58 | App.MainWindow.AppWindow.TitleBar.ButtonHoverBackgroundColor = theme switch 59 | { 60 | ElementTheme.Dark => Color.FromArgb(0x33, 0xFF, 0xFF, 0xFF), 61 | ElementTheme.Light => Color.FromArgb(0x33, 0x00, 0x00, 0x00), 62 | _ => Colors.Transparent 63 | }; 64 | 65 | App.MainWindow.AppWindow.TitleBar.ButtonPressedBackgroundColor = theme switch 66 | { 67 | ElementTheme.Dark => Color.FromArgb(0x66, 0xFF, 0xFF, 0xFF), 68 | ElementTheme.Light => Color.FromArgb(0x66, 0x00, 0x00, 0x00), 69 | _ => Colors.Transparent 70 | }; 71 | 72 | App.MainWindow.AppWindow.TitleBar.BackgroundColor = Colors.Transparent; 73 | 74 | var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow); 75 | if (hwnd == GetActiveWindow()) 76 | { 77 | SendMessage(hwnd, WMACTIVATE, WAINACTIVE, IntPtr.Zero); 78 | SendMessage(hwnd, WMACTIVATE, WAACTIVE, IntPtr.Zero); 79 | } 80 | else 81 | { 82 | SendMessage(hwnd, WMACTIVATE, WAACTIVE, IntPtr.Zero); 83 | SendMessage(hwnd, WMACTIVATE, WAINACTIVE, IntPtr.Zero); 84 | } 85 | } 86 | } 87 | 88 | public static void ApplySystemThemeToCaptionButtons() 89 | { 90 | var frame = App.AppTitlebar as FrameworkElement; 91 | if (frame != null) 92 | { 93 | UpdateTitleBar(frame.ActualTheme); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  15 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using MoreFlyout.Shell.Helpers; 2 | 3 | using Windows.UI.ViewManagement; 4 | 5 | namespace MoreFlyout.Shell; 6 | 7 | public sealed partial class MainWindow : WindowEx 8 | { 9 | private readonly Microsoft.UI.Dispatching.DispatcherQueue dispatcherQueue; 10 | 11 | private readonly UISettings settings; 12 | 13 | public MainWindow() 14 | { 15 | InitializeComponent(); 16 | 17 | AppWindow.SetIcon(Path.Combine(AppContext.BaseDirectory, "Assets/WindowIcon.ico")); 18 | Content = null; 19 | Title = "AppDisplayName".GetLocalized(); 20 | ExtendsContentIntoTitleBar = true; 21 | 22 | // Theme change code picked from https://github.com/microsoft/WinUI-Gallery/pull/1239 23 | dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread(); 24 | settings = new UISettings(); 25 | settings.ColorValuesChanged += Settings_ColorValuesChanged; // cannot use FrameworkElement.ActualThemeChanged event 26 | } 27 | 28 | // this handles updating the caption button colors correctly when windows system theme is changed 29 | // while the app is open 30 | private void Settings_ColorValuesChanged(UISettings sender, object args) 31 | { 32 | // This calls comes off-thread, hence we will need to dispatch it to current app's thread 33 | dispatcherQueue.TryEnqueue(() => 34 | { 35 | TitleBarHelper.ApplySystemThemeToCaptionButtons(); 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Models/LocalSettingsOptions.cs: -------------------------------------------------------------------------------- 1 | namespace MoreFlyout.Shell.Models; 2 | 3 | public class LocalSettingsOptions 4 | { 5 | public string? ApplicationDataFolder 6 | { 7 | get; set; 8 | } 9 | 10 | public string? LocalSettingsFile 11 | { 12 | get; set; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/MoreFlyout.Shell.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | WinExe 4 | net8.0-windows10.0.22621.0 5 | 10.0.17763.0 6 | 10.0.22621.38 7 | MoreFlyout.Shell 8 | Assets/WindowIcon.ico 9 | app.manifest 10 | x86;x64;arm64 11 | win-x86;win-x64;win-arm64 12 | Properties\PublishProfiles\win-$(Platform).pubxml 13 | enable 14 | enable 15 | true 16 | true 17 | true 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | PreserveNewest 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | true 59 | 60 | 61 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Package.appinstaller: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | MoreFlyout.Shell 22 | 10627 23 | Assets\StoreLogo.png 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 39 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Properties/PublishProfiles/win-arm64.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FileSystem 5 | arm64 6 | win-arm64 7 | bin\publish\$(RuntimeIdentifier) 8 | True 9 | False 10 | false 11 | partial 12 | 13 | 14 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Properties/PublishProfiles/win-x64.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FileSystem 5 | x64 6 | win-x64 7 | bin\publish\win-x64 8 | true 9 | Release 10 | false 11 | false 12 | net8.0-windows10.0.22621.0 13 | true 14 | partial 15 | 18 | 19 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Properties/PublishProfiles/win-x86.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FileSystem 5 | x86 6 | win-x86 7 | bin\publish\win-x86\ 8 | true 9 | false 10 | False 11 | false 12 | Release 13 | net8.0-windows10.0.22621.0 14 | false 15 | partial 16 | 17 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Properties/launchsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "MoreFlyout.Shell (Package)": { 4 | "commandName": "MsixPackage" 5 | }, 6 | "MoreFlyout.Shell (Unpackaged)": { 7 | "commandName": "Project" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/README.md: -------------------------------------------------------------------------------- 1 | *Recommended Markdown Viewer: [Markdown Editor](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.MarkdownEditor2)* 2 | 3 | ## Getting Started 4 | 5 | Browse and address `TODO:` comments in `View -> Task List` to learn the codebase and understand next steps for turning the generated code into production code. 6 | 7 | Explore the [WinUI Gallery](https://www.microsoft.com/store/productId/9P3JFPWWDZRC) to learn about available controls and design patterns. 8 | 9 | Relaunch Template Studio to modify the project by right-clicking on the project in `View -> Solution Explorer` then selecting `Add -> New Item (Template Studio)`. 10 | 11 | ## Publishing 12 | 13 | For projects with MSIX packaging, right-click on the application project and select `Package and Publish -> Create App Packages...` to create an MSIX package. 14 | 15 | For projects without MSIX packaging, follow the [deployment guide](https://docs.microsoft.com/windows/apps/windows-app-sdk/deploy-unpackaged-apps) or add the `Self-Contained` Feature to enable xcopy deployment. 16 | 17 | ## CI Pipelines 18 | 19 | See [README.md](https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/pipelines/README.md) for guidance on building and testing projects in CI pipelines. 20 | 21 | ## Changelog 22 | 23 | See [releases](https://github.com/microsoft/TemplateStudio/releases) and [milestones](https://github.com/microsoft/TemplateStudio/milestones). 24 | 25 | ## Feedback 26 | 27 | Bugs and feature requests should be filed at https://aka.ms/templatestudio. 28 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Services/ActivationService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | using Microsoft.UI.Xaml.Controls; 3 | 4 | using MoreFlyout.Shell.Activation; 5 | using MoreFlyout.Shell.Contracts.Services; 6 | using MoreFlyout.Shell.Views; 7 | 8 | namespace MoreFlyout.Shell.Services; 9 | 10 | public class ActivationService : IActivationService 11 | { 12 | private readonly ActivationHandler _defaultHandler; 13 | private readonly IEnumerable _activationHandlers; 14 | private readonly IThemeSelectorService _themeSelectorService; 15 | private UIElement? _shell = null; 16 | 17 | public ActivationService(ActivationHandler defaultHandler, IEnumerable activationHandlers, IThemeSelectorService themeSelectorService) 18 | { 19 | _defaultHandler = defaultHandler; 20 | _activationHandlers = activationHandlers; 21 | _themeSelectorService = themeSelectorService; 22 | } 23 | 24 | public async Task ActivateAsync(object activationArgs) 25 | { 26 | // Execute tasks before activation. 27 | await InitializeAsync(); 28 | 29 | // Set the MainWindow Content. 30 | if (App.MainWindow.Content == null) 31 | { 32 | App.MainWindow.Content = _shell ?? new Frame(); 33 | } 34 | 35 | // Handle activation via ActivationHandlers. 36 | await HandleActivationAsync(activationArgs); 37 | 38 | // Activate the MainWindow. 39 | App.MainWindow.Activate(); 40 | 41 | // Execute tasks after activation. 42 | await StartupAsync(); 43 | } 44 | 45 | private async Task HandleActivationAsync(object activationArgs) 46 | { 47 | var activationHandler = _activationHandlers.FirstOrDefault(h => h.CanHandle(activationArgs)); 48 | 49 | if (activationHandler != null) 50 | { 51 | await activationHandler.HandleAsync(activationArgs); 52 | } 53 | 54 | if (_defaultHandler.CanHandle(activationArgs)) 55 | { 56 | await _defaultHandler.HandleAsync(activationArgs); 57 | } 58 | } 59 | 60 | private async Task InitializeAsync() 61 | { 62 | await _themeSelectorService.InitializeAsync().ConfigureAwait(false); 63 | await Task.CompletedTask; 64 | } 65 | 66 | private async Task StartupAsync() 67 | { 68 | await _themeSelectorService.SetRequestedThemeAsync(); 69 | await Task.CompletedTask; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Services/LocalSettingsService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Options; 2 | 3 | using MoreFlyout.Shell.Contracts.Services; 4 | using MoreFlyout.Shell.Core.Contracts.Services; 5 | using MoreFlyout.Shell.Core.Helpers; 6 | using MoreFlyout.Shell.Helpers; 7 | using MoreFlyout.Shell.Models; 8 | 9 | using Windows.ApplicationModel; 10 | using Windows.Storage; 11 | 12 | namespace MoreFlyout.Shell.Services; 13 | 14 | public class LocalSettingsService : ILocalSettingsService 15 | { 16 | private const string _defaultApplicationDataFolder = "MoreFlyout.Shell/ApplicationData"; 17 | private const string _defaultLocalSettingsFile = "LocalSettings.json"; 18 | 19 | private readonly IFileService _fileService; 20 | private readonly LocalSettingsOptions _options; 21 | 22 | private readonly string _localApplicationData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); 23 | private readonly string _applicationDataFolder; 24 | private readonly string _localsettingsFile; 25 | 26 | private IDictionary _settings; 27 | 28 | private bool _isInitialized; 29 | 30 | public LocalSettingsService(IFileService fileService, IOptions options) 31 | { 32 | _fileService = fileService; 33 | _options = options.Value; 34 | 35 | _applicationDataFolder = Path.Combine(_localApplicationData, _options.ApplicationDataFolder ?? _defaultApplicationDataFolder); 36 | _localsettingsFile = _options.LocalSettingsFile ?? _defaultLocalSettingsFile; 37 | 38 | _settings = new Dictionary(); 39 | } 40 | 41 | private async Task InitializeAsync() 42 | { 43 | if (!_isInitialized) 44 | { 45 | _settings = await Task.Run(() => _fileService.Read>(_applicationDataFolder, _localsettingsFile)) ?? new Dictionary(); 46 | 47 | _isInitialized = true; 48 | } 49 | } 50 | 51 | public async Task ReadSettingAsync(string key) 52 | { 53 | if (RuntimeHelper.IsMSIX) 54 | { 55 | if (ApplicationData.Current.LocalSettings.Values.TryGetValue(key, out var obj)) 56 | { 57 | return await Json.ToObjectAsync((string)obj); 58 | } 59 | } 60 | else 61 | { 62 | await InitializeAsync(); 63 | 64 | if (_settings != null && _settings.TryGetValue(key, out var obj)) 65 | { 66 | return await Json.ToObjectAsync((string)obj); 67 | } 68 | } 69 | 70 | return default; 71 | } 72 | 73 | public async Task SaveSettingAsync(string key, T value) 74 | { 75 | if (RuntimeHelper.IsMSIX) 76 | { 77 | ApplicationData.Current.LocalSettings.Values[key] = await Json.StringifyAsync(value); 78 | } 79 | else 80 | { 81 | await InitializeAsync(); 82 | 83 | _settings[key] = await Json.StringifyAsync(value); 84 | 85 | await Task.Run(() => _fileService.Save(_applicationDataFolder, _localsettingsFile, _settings)); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Services/NavigationService.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | using Microsoft.UI.Xaml.Controls; 4 | using Microsoft.UI.Xaml.Navigation; 5 | 6 | using MoreFlyout.Shell.Contracts.Services; 7 | using MoreFlyout.Shell.Contracts.ViewModels; 8 | using MoreFlyout.Shell.Helpers; 9 | 10 | namespace MoreFlyout.Shell.Services; 11 | 12 | // For more information on navigation between pages see 13 | // https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/navigation.md 14 | public class NavigationService : INavigationService 15 | { 16 | private readonly IPageService _pageService; 17 | private object? _lastParameterUsed; 18 | private Frame? _frame; 19 | 20 | public event NavigatedEventHandler? Navigated; 21 | 22 | public Frame? Frame 23 | { 24 | get 25 | { 26 | if (_frame == null) 27 | { 28 | _frame = App.MainWindow.Content as Frame; 29 | RegisterFrameEvents(); 30 | } 31 | 32 | return _frame; 33 | } 34 | 35 | set 36 | { 37 | UnregisterFrameEvents(); 38 | _frame = value; 39 | RegisterFrameEvents(); 40 | } 41 | } 42 | 43 | [MemberNotNullWhen(true, nameof(Frame), nameof(_frame))] 44 | public bool CanGoBack => Frame != null && Frame.CanGoBack; 45 | 46 | public NavigationService(IPageService pageService) 47 | { 48 | _pageService = pageService; 49 | } 50 | 51 | private void RegisterFrameEvents() 52 | { 53 | if (_frame != null) 54 | { 55 | _frame.Navigated += OnNavigated; 56 | } 57 | } 58 | 59 | private void UnregisterFrameEvents() 60 | { 61 | if (_frame != null) 62 | { 63 | _frame.Navigated -= OnNavigated; 64 | } 65 | } 66 | 67 | public bool GoBack() 68 | { 69 | if (CanGoBack) 70 | { 71 | var vmBeforeNavigation = _frame.GetPageViewModel(); 72 | _frame.GoBack(); 73 | if (vmBeforeNavigation is INavigationAware navigationAware) 74 | { 75 | navigationAware.OnNavigatedFrom(); 76 | } 77 | 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | 84 | public bool NavigateTo(string pageKey, object? parameter = null, bool clearNavigation = false) 85 | { 86 | var pageType = _pageService.GetPageType(pageKey); 87 | 88 | if (_frame != null && (_frame.Content?.GetType() != pageType || (parameter != null && !parameter.Equals(_lastParameterUsed)))) 89 | { 90 | _frame.Tag = clearNavigation; 91 | var vmBeforeNavigation = _frame.GetPageViewModel(); 92 | var navigated = _frame.Navigate(pageType, parameter); 93 | if (navigated) 94 | { 95 | _lastParameterUsed = parameter; 96 | if (vmBeforeNavigation is INavigationAware navigationAware) 97 | { 98 | navigationAware.OnNavigatedFrom(); 99 | } 100 | } 101 | 102 | return navigated; 103 | } 104 | 105 | return false; 106 | } 107 | 108 | private void OnNavigated(object sender, NavigationEventArgs e) 109 | { 110 | if (sender is Frame frame) 111 | { 112 | var clearNavigation = (bool)frame.Tag; 113 | if (clearNavigation) 114 | { 115 | frame.BackStack.Clear(); 116 | } 117 | 118 | if (frame.GetPageViewModel() is INavigationAware navigationAware) 119 | { 120 | navigationAware.OnNavigatedTo(e.Parameter); 121 | } 122 | 123 | Navigated?.Invoke(sender, e); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Services/PageService.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | using Microsoft.UI.Xaml.Controls; 4 | 5 | using MoreFlyout.Shell.Contracts.Services; 6 | using MoreFlyout.Shell.ViewModels; 7 | using MoreFlyout.Shell.Views; 8 | 9 | namespace MoreFlyout.Shell.Services; 10 | 11 | public class PageService : IPageService 12 | { 13 | private readonly Dictionary _pages = new(); 14 | 15 | public PageService() 16 | { 17 | Configure(); 18 | } 19 | 20 | public Type GetPageType(string key) 21 | { 22 | Type? pageType; 23 | lock (_pages) 24 | { 25 | if (!_pages.TryGetValue(key, out pageType)) 26 | { 27 | throw new ArgumentException($"Page not found: {key}. Did you forget to call PageService.Configure?"); 28 | } 29 | } 30 | 31 | return pageType; 32 | } 33 | 34 | private void Configure() 35 | where VM : ObservableObject 36 | where V : Page 37 | { 38 | lock (_pages) 39 | { 40 | var key = typeof(VM).FullName!; 41 | if (_pages.ContainsKey(key)) 42 | { 43 | throw new ArgumentException($"The key {key} is already configured in PageService"); 44 | } 45 | 46 | var type = typeof(V); 47 | if (_pages.ContainsValue(type)) 48 | { 49 | throw new ArgumentException($"This type is already configured with key {_pages.First(p => p.Value == type).Key}"); 50 | } 51 | 52 | _pages.Add(key, type); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Services/ThemeSelectorService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | 3 | using MoreFlyout.Shell.Contracts.Services; 4 | using MoreFlyout.Shell.Helpers; 5 | 6 | namespace MoreFlyout.Shell.Services; 7 | 8 | public class ThemeSelectorService : IThemeSelectorService 9 | { 10 | private const string SettingsKey = "AppBackgroundRequestedTheme"; 11 | 12 | public ElementTheme Theme { get; set; } = ElementTheme.Default; 13 | 14 | private readonly ILocalSettingsService _localSettingsService; 15 | 16 | public ThemeSelectorService(ILocalSettingsService localSettingsService) 17 | { 18 | _localSettingsService = localSettingsService; 19 | } 20 | 21 | public async Task InitializeAsync() 22 | { 23 | Theme = await LoadThemeFromSettingsAsync(); 24 | await Task.CompletedTask; 25 | } 26 | 27 | public async Task SetThemeAsync(ElementTheme theme) 28 | { 29 | Theme = theme; 30 | 31 | await SetRequestedThemeAsync(); 32 | await SaveThemeInSettingsAsync(Theme); 33 | } 34 | 35 | public async Task SetRequestedThemeAsync() 36 | { 37 | if (App.MainWindow.Content is FrameworkElement rootElement) 38 | { 39 | rootElement.RequestedTheme = Theme; 40 | 41 | TitleBarHelper.UpdateTitleBar(Theme); 42 | } 43 | 44 | await Task.CompletedTask; 45 | } 46 | 47 | private async Task LoadThemeFromSettingsAsync() 48 | { 49 | var themeName = await _localSettingsService.ReadSettingAsync(SettingsKey); 50 | 51 | if (Enum.TryParse(themeName, out ElementTheme cacheTheme)) 52 | { 53 | return cacheTheme; 54 | } 55 | 56 | return ElementTheme.Default; 57 | } 58 | 59 | private async Task SaveThemeInSettingsAsync(ElementTheme theme) 60 | { 61 | await _localSettingsService.SaveSettingAsync(SettingsKey, theme.ToString()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Strings/en-us/Resources.resw: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | text/microsoft-resx 51 | 52 | 53 | 2.0 54 | 55 | 56 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 57 | 58 | 59 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 60 | 61 | 62 | MoreFlyout.Shell 63 | 64 | 65 | MoreFlyout.Shell 66 | 67 | 68 | MoreFlyout.Server 69 | 70 | 71 | MoreFlyout.Server Run With Windows 72 | 73 | 74 | MoreFlyout 75 | 76 | 77 | Repository about MoreFlyout 78 | 79 | 80 | Dependencies & references 81 | 82 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Strings/zh-cn/Resources.resw: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | text/microsoft-resx 51 | 52 | 53 | 2.0 54 | 55 | 56 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 57 | 58 | 59 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 60 | 61 | 62 | 更多的浮出控件.配置 63 | 64 | 65 | 更多的浮出控件.配置 66 | 67 | 68 | 更多的浮出控件.基础服务 69 | 70 | 71 | 更多的浮出控件.基础服务 开机自启动 72 | 73 | 74 | 更多的浮出控件 75 | 76 | 77 | 更多的浮出控件的源码仓库 78 | 79 | 80 | 项目依赖和引用 81 | 82 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Styles/FontSizes.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 24 4 | 5 | 16 6 | 7 | 8 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Styles/TextBlock.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 10 | 11 | 17 | 18 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Styles/Thickness.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 0,36,0,0 4 | 0,36,0,36 5 | 6 | 0,24,0,0 7 | 0,24,0,24 8 | 24,0,24,0 9 | 0,0,0,24 10 | 11 | 12,0,0,0 12 | 12,0,12,0 13 | 0,12,0,0 14 | 0,0,12,0 15 | 0,12,0,12 16 | 17 | 8,0,0,0 18 | 0,8,0,0 19 | 8,8,8,8 20 | 21 | 0,4,0,0 22 | 4,4,4,4 23 | 24 | 1,1,0,0 25 | 8,0,0,0 26 | 0,48,0,0 27 | 56,34,0,0 28 | 56,24,56,0 29 | 30 | 36,24,36,0 31 | 32 | -12,4,0,0 33 | 34 | 35 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/TemplateStudio.xml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Usings.cs: -------------------------------------------------------------------------------- 1 | global using WinUIEx; 2 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/ViewModels/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace MoreFlyout.Shell.ViewModels; 4 | 5 | public partial class MainViewModel : ObservableRecipient 6 | { 7 | public MainViewModel() 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Views/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 24 | 29 | 35 | 36 | 37 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/Views/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Microsoft.UI.Xaml.Controls; 3 | using Microsoft.Win32; 4 | using MoreFlyout.Shell.Helpers; 5 | using MoreFlyout.Shell.ViewModels; 6 | 7 | namespace MoreFlyout.Shell.Views; 8 | 9 | public sealed partial class MainPage : Page 10 | { 11 | public MainViewModel ViewModel 12 | { 13 | get; 14 | } 15 | 16 | public MainPage() 17 | { 18 | ViewModel = App.GetService(); 19 | InitializeComponent(); 20 | 21 | AppTitleBarText.Text = "AppDisplayName".GetLocalized(); 22 | 23 | // Check MoreFlyout.Server is running? 24 | var isProcessRunning = false; 25 | foreach (var process in Process.GetProcesses()) 26 | { 27 | if (process.ProcessName.Equals("MoreFlyout.Server", StringComparison.CurrentCultureIgnoreCase)) 28 | { 29 | isProcessRunning = true; 30 | break; 31 | } 32 | } 33 | if (isProcessRunning == true) RunServerToggleSwitch.IsOn = true; 34 | 35 | // Check MoreFlyout.Server is run with windows? 36 | using var key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); 37 | if (key?.GetValue("MoreFlyout.Server") != null) RunWithWindowsToggleSwitch.IsOn = true; 38 | } 39 | 40 | private void ToggleSwitch_Server_Toggled(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) 41 | { 42 | var toggleSwitch = sender as ToggleSwitch; 43 | if (toggleSwitch != null) 44 | { 45 | if (toggleSwitch.IsOn == true) 46 | { 47 | try 48 | { 49 | Process.Start(string.Concat(AppDomain.CurrentDomain.BaseDirectory.AsSpan(0, AppDomain.CurrentDomain.BaseDirectory.Length - @"MoreFlyout.Shell\".Length), @"MoreFlyout.Server\MoreFlyout.Server.exe")); 50 | } 51 | catch (Exception ex) 52 | { 53 | Debug.WriteLine($"Error terminating processes: {ex.Message}"); 54 | } 55 | } 56 | else 57 | { 58 | try 59 | { 60 | // Get all of processes named MoreFlyout.Server.exe 61 | var processes = Process.GetProcessesByName("MoreFlyout.Server"); 62 | 63 | // try to kill every processes 64 | foreach (var process in processes) 65 | { 66 | Debug.WriteLine($"Terminating process with ID: {process.Id}"); 67 | process.Kill(); 68 | } 69 | 70 | Debug.WriteLine("All instances of MoreFlyout.Server have been terminated."); 71 | } 72 | catch (Exception ex) 73 | { 74 | Debug.WriteLine($"Error terminating processes: {ex.Message}"); 75 | } 76 | } 77 | } 78 | } 79 | 80 | private void ToggleSwitch_RunWithWindows_Toggled(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) 81 | { 82 | var toggleSwitch = sender as ToggleSwitch; 83 | if (toggleSwitch != null) 84 | { 85 | if (toggleSwitch.IsOn == true) 86 | { 87 | try 88 | { 89 | // Open or create Registry key of "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" 90 | var key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); 91 | 92 | // MoreFlyout.Server.exe's path 93 | var exePath = string.Concat("\"", AppDomain.CurrentDomain.BaseDirectory.AsSpan(0, AppDomain.CurrentDomain.BaseDirectory.Length - @"MoreFlyout.Shell\".Length), @"MoreFlyout.Server\MoreFlyout.Server.exe", "\""); 94 | 95 | // SetValue 96 | key?.SetValue("MoreFlyout.Server", exePath); 97 | 98 | Debug.WriteLine("MoreFlyout.Server has been added to the startup list successfully."); 99 | } 100 | catch (Exception ex) 101 | { 102 | Debug.WriteLine($"An error occurred while adding MoreFlyout.Server to the startup list: {ex.Message}"); 103 | } 104 | } 105 | else 106 | { 107 | try 108 | { 109 | // Open Registry key of "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" 110 | using var key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); 111 | if (key != null) 112 | { 113 | // Delete "MoreFlyout.Server" 114 | key.DeleteValue("MoreFlyout.Server", false); 115 | 116 | Debug.WriteLine("The startup entry for MoreFlyout.Server has been removed successfully."); 117 | } 118 | else 119 | { 120 | throw new InvalidOperationException("Could not open the registry key for startup entries."); 121 | } 122 | } 123 | catch (Exception ex) 124 | { 125 | Debug.WriteLine($"An error occurred while removing the startup entry: {ex.Message}"); 126 | } 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | true/PM 12 | PerMonitorV2, PerMonitor 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /MoreFlyout.Shell/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "LocalSettingsOptions": { 3 | "ApplicationDataFolder": "MoreFlyout.Shell/ApplicationData", 4 | "LocalSettingsFile": "LocalSettings.json" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /MoreFlyout.iss: -------------------------------------------------------------------------------- 1 | ; Script generated by the Inno Setup Script Wizard. 2 | ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! 3 | 4 | #define MyAppName "MoreFlyout" 5 | #define MyAppVersion "1.1.2" 6 | #define MyAppPublisher "ChenYiLins" 7 | #define MyAppURL "https://github.com/ChenYiLins/MoreFlyout" 8 | #define MyAppExeName "MoreFlyout.Shell.exe" 9 | 10 | [Setup] 11 | ; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. 12 | ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) 13 | AppId={{ED91AC41-325B-4665-9660-328538C260E0} 14 | AppName={#MyAppName} 15 | AppVersion={#MyAppVersion} 16 | PrivilegesRequired=none 17 | ;AppVerName={#MyAppName} {#MyAppVersion} 18 | AppPublisher={#MyAppPublisher} 19 | AppPublisherURL={#MyAppURL} 20 | AppSupportURL={#MyAppURL} 21 | AppUpdatesURL={#MyAppURL} 22 | DefaultDirName={autopf}\{#MyAppName} 23 | DisableProgramGroupPage=yes 24 | UsePreviousAppDir=no 25 | LicenseFile=D:\Projects\Source\CSharp\MoreFlyout\LICENSE 26 | ; Uncomment the following line to run in non administrative install mode (install for current user only.) 27 | ;PrivilegesRequired=lowest 28 | OutputDir=D:\Downloads 29 | OutputBaseFilename=MoreFlyout 30 | SetupIconFile=D:\Projects\Source\CSharp\MoreFlyout\Assest\InstallIcon.ico 31 | Compression=lzma 32 | SolidCompression=yes 33 | WizardStyle=modern 34 | ArchitecturesInstallIn64BitMode=x64compatible 35 | 36 | [Languages] 37 | Name: "english"; MessagesFile: "compiler:Default.isl" 38 | Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl" 39 | 40 | [Tasks] 41 | Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked 42 | 43 | [Files] 44 | Source: "D:\Projects\Source\Package\MoreFlyout\MoreFlyout\MoreFlyout.Shell\{#MyAppExeName}"; DestDir: "{app}\MoreFlyout.Shell"; Flags: ignoreversion 45 | Source: "D:\Projects\Source\Package\MoreFlyout\MoreFlyout\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs 46 | ; NOTE: Don't use "Flags: ignoreversion" on any shared system files 47 | 48 | [Icons] 49 | Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\MoreFlyout.Shell\{#MyAppExeName}" 50 | Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon 51 | 52 | [Registry] 53 | Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueName:"MoreFlyout.Server"; Flags: uninsdeletevalue 54 | -------------------------------------------------------------------------------- /MoreFlyout.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.10.34707.107 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoreFlyout.Server", "MoreFlyout.Server\MoreFlyout.Server.csproj", "{46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoreFlyout.Server.Core", "MoreFlyout.Server.Core\MoreFlyout.Server.Core.csproj", "{51601B83-0ACC-437D-AA1C-53594F906CCA}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoreFlyout.Shell", "MoreFlyout.Shell\MoreFlyout.Shell.csproj", "{DD7FB294-C758-43F9-99D9-0BEC95AA2D74}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoreFlyout.Shell.Core", "MoreFlyout.Shell.Core\MoreFlyout.Shell.Core.csproj", "{3621494B-5786-48B1-9683-6FD32286E911}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|arm64 = Debug|arm64 18 | Debug|x64 = Debug|x64 19 | Debug|x86 = Debug|x86 20 | Release|Any CPU = Release|Any CPU 21 | Release|arm64 = Release|arm64 22 | Release|x64 = Release|x64 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|Any CPU.ActiveCfg = Debug|x64 27 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|Any CPU.Build.0 = Debug|x64 28 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|Any CPU.Deploy.0 = Debug|x64 29 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|arm64.ActiveCfg = Debug|arm64 30 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|arm64.Build.0 = Debug|arm64 31 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|arm64.Deploy.0 = Debug|arm64 32 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|x64.ActiveCfg = Debug|x64 33 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|x64.Build.0 = Debug|x64 34 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|x64.Deploy.0 = Debug|x64 35 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|x86.ActiveCfg = Debug|x86 36 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|x86.Build.0 = Debug|x86 37 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Debug|x86.Deploy.0 = Debug|x86 38 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|Any CPU.ActiveCfg = Release|x64 39 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|Any CPU.Build.0 = Release|x64 40 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|Any CPU.Deploy.0 = Release|x64 41 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|arm64.ActiveCfg = Release|arm64 42 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|arm64.Build.0 = Release|arm64 43 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|arm64.Deploy.0 = Release|arm64 44 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|x64.ActiveCfg = Release|x64 45 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|x64.Build.0 = Release|x64 46 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|x64.Deploy.0 = Release|x64 47 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|x86.ActiveCfg = Release|x86 48 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|x86.Build.0 = Release|x86 49 | {46F9AD8D-59ED-4A99-B1B0-428DBD6CA15E}.Release|x86.Deploy.0 = Release|x86 50 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Debug|arm64.ActiveCfg = Debug|arm64 53 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Debug|arm64.Build.0 = Debug|arm64 54 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Debug|x64.ActiveCfg = Debug|x64 55 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Debug|x64.Build.0 = Debug|x64 56 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Debug|x86.ActiveCfg = Debug|x86 57 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Debug|x86.Build.0 = Debug|x86 58 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Release|arm64.ActiveCfg = Release|arm64 61 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Release|arm64.Build.0 = Release|arm64 62 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Release|x64.ActiveCfg = Release|x64 63 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Release|x64.Build.0 = Release|x64 64 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Release|x86.ActiveCfg = Release|x86 65 | {51601B83-0ACC-437D-AA1C-53594F906CCA}.Release|x86.Build.0 = Release|x86 66 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Debug|Any CPU.ActiveCfg = Debug|x64 67 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Debug|Any CPU.Build.0 = Debug|x64 68 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Debug|arm64.ActiveCfg = Debug|arm64 69 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Debug|arm64.Build.0 = Debug|arm64 70 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Debug|x64.ActiveCfg = Debug|x64 71 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Debug|x64.Build.0 = Debug|x64 72 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Debug|x86.ActiveCfg = Debug|x86 73 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Debug|x86.Build.0 = Debug|x86 74 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Release|Any CPU.ActiveCfg = Release|x64 75 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Release|Any CPU.Build.0 = Release|x64 76 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Release|arm64.ActiveCfg = Release|arm64 77 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Release|arm64.Build.0 = Release|arm64 78 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Release|x64.ActiveCfg = Release|x64 79 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Release|x64.Build.0 = Release|x64 80 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Release|x86.ActiveCfg = Release|x86 81 | {DD7FB294-C758-43F9-99D9-0BEC95AA2D74}.Release|x86.Build.0 = Release|x86 82 | {3621494B-5786-48B1-9683-6FD32286E911}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 83 | {3621494B-5786-48B1-9683-6FD32286E911}.Debug|Any CPU.Build.0 = Debug|Any CPU 84 | {3621494B-5786-48B1-9683-6FD32286E911}.Debug|arm64.ActiveCfg = Debug|arm64 85 | {3621494B-5786-48B1-9683-6FD32286E911}.Debug|arm64.Build.0 = Debug|arm64 86 | {3621494B-5786-48B1-9683-6FD32286E911}.Debug|x64.ActiveCfg = Debug|x64 87 | {3621494B-5786-48B1-9683-6FD32286E911}.Debug|x64.Build.0 = Debug|x64 88 | {3621494B-5786-48B1-9683-6FD32286E911}.Debug|x86.ActiveCfg = Debug|x86 89 | {3621494B-5786-48B1-9683-6FD32286E911}.Debug|x86.Build.0 = Debug|x86 90 | {3621494B-5786-48B1-9683-6FD32286E911}.Release|Any CPU.ActiveCfg = Release|Any CPU 91 | {3621494B-5786-48B1-9683-6FD32286E911}.Release|Any CPU.Build.0 = Release|Any CPU 92 | {3621494B-5786-48B1-9683-6FD32286E911}.Release|arm64.ActiveCfg = Release|arm64 93 | {3621494B-5786-48B1-9683-6FD32286E911}.Release|arm64.Build.0 = Release|arm64 94 | {3621494B-5786-48B1-9683-6FD32286E911}.Release|x64.ActiveCfg = Release|x64 95 | {3621494B-5786-48B1-9683-6FD32286E911}.Release|x64.Build.0 = Release|x64 96 | {3621494B-5786-48B1-9683-6FD32286E911}.Release|x86.ActiveCfg = Release|x86 97 | {3621494B-5786-48B1-9683-6FD32286E911}.Release|x86.Build.0 = Release|x86 98 | EndGlobalSection 99 | GlobalSection(SolutionProperties) = preSolution 100 | HideSolutionNode = FALSE 101 | EndGlobalSection 102 | GlobalSection(ExtensibilityGlobals) = postSolution 103 | SolutionGuid = {94440D4F-B2BB-406A-8BBA-64A18587B367} 104 | EndGlobalSection 105 | EndGlobal 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MoreFlyout 2 | 3 | Title 4 | 5 | Provide OSD display similar Win11 FluentUI style. Maybe this application looks like [MordenFlyouts](https://github.com/ModernFlyouts-Community/ModernFlyouts), but this application is developed based on C# WinUI3, it's looks like Win11 native flyouts. 6 | 7 | [Release note](./RELEASENOTE_EN.md) 8 | 9 | ## Overview 10 | 11 | - Now add flyouts for Lock keys. 12 | 13 | ## Screenshots 14 | 15 | Screenshots 16 | 17 | ## Download 18 | 19 | You can download application from [Github Release](https://github.com/ChenYiLins/MoreFlyout/releases) Page. Later will provide a install program named `MoreFlyout-x64-x.x.x.exe` and a portable compressed package named `MoreFlyout-Portable-x64-x.x.x.zip`. 20 | 21 | System Requirements: 22 | 23 | - Windows10 build 1809 and above 24 | - x86 bit system 25 | -------------------------------------------------------------------------------- /RELEASENOTE_CN.md: -------------------------------------------------------------------------------- 1 | # MoreFlyout 2 | 3 | ## 开发日志 4 | 5 | ### v1.1.3-2024.10.08 6 | 7 | ### v1.1.2-health action1-2024.09.22 8 | 9 | - 此版本主要目的为修复程序目前存在的错误,优化程序结构,同时完善日志。 10 | - 修复了Shell主程序打开时,主页的按钮始终处于关闭状态的bug。 11 | - 修复了因为Windows App Sdk关于AppWindow的IsShownInSwitchers的bug。在重启Explorer后,此属性设置会失效。关于这个bug的[Issue](https://github.com/microsoft/microsoft-ui-xaml/issues/10026)。目前采用的解决方案为使用Hook钩子检测Explorer事件,因为直接检测窗口消息会因为主程序所使用Hook钩子而失效,目前并未发现其他有效的解决方案。(因为Hook并不是最有效的方法,会造成一部分的性能消耗) 12 | - 统一解决方案Nuget包,更新Windows App Sdk至1.6。 13 | - 新增英文开发日志,截止目前版本之前的日志基于中文日志使用翻译软件翻译,可能会存在部分词不达意的情况。 14 | - 为正常使用Windows Community Toolkit,将解决方案的TargetFramework更改为22621。 15 | - 代码质量更新:对部分代码进行修正,同时删除部分多余变量,精简代码。 16 | - 为MoreFlyout.Server引入AOT功能,同时对部分使用反射的代码就行标注,避免裁剪问题。 17 | - 因为一些不可抗因素,现在不得不为MoreFlyout.Shell弃用裁剪功能,程序体积变得有些许臃肿。可以查看github上的[Issue](https://github.com/ChenYiLins/MoreFlyout/issues/2)。 18 | - 更新了安装程序,卸载程序时会删除产生的注册表项。 19 | 20 | ### v1.1.1-2024.09.16 21 | 22 | - 现在修复了程序启动时所有按钮默认处于关闭的bug。 23 | 24 | ### v1.1.0-2024.07.24 25 | 26 | - 删除C++构建的MoreFlyout.Shell,改为C#编写。 27 | - 统一MoreFlyout.Server和MoreFlyout.Shell的 .Net、Windows App SDK版本。 28 | - 新增Preview分支,作为预览更新,在更新完毕时并入main分支,Preview分支可能会采用预览版Window App SDK,在使用预览版时不会并入main分支。 29 | 30 | ### v1.0.0-2024.06.01 31 | 32 | - 在分支CppVersion中曾考虑将主程序改为C++重构,但经过多次的压力测试,不得不面对C++ WinUI程序长时间运行下极易出现的内存泄露问题,决定保留主程序为C#编写,同时删除托盘图标功能,将项目分为MoreFlyout.Server和MoreFlyout.Shell,同时MoreFlyout.Shell部分由C++编写,作为程序的可视化管理外壳。 33 | 34 | ### v0.0.3-beta3-2024.03.12 35 | 36 | - 更改了程序结构,精简之前由TemplateStudio自动生成的模板,同时更改了部分命名,例如:MainWindow改为FlyoutWindow更加直观。精简了部分逻辑代码。 37 | - 感谢[Simon Mourier](https://github.com/smourier)的[回答](https://stackoverflow.com/questions/78210920/in-c-sharp-winui-a-crash-about-system-executioninexception-is-caused-for-unk),成功解决了因为CG回收导致WinUI的严重崩溃。 38 | - 将整个窗口显示改为Flyout组件显示,虽然系统Flyout其实没有使用WinUI Flyout的动画,但是动画效果上已经很接近了。 39 | - 将Windows App SDK由1.4版本升级到1.5版本,更改了整个程序的退出方法,不再因为窗口的崩溃导致整个程序的崩溃,后续考虑将检测窗口状态的功能放入托盘图标。 40 | - 程序必须以管理员方式运行,才能够显示在其他应用上层。 41 | - 添加了其他窗口全屏检测的功能,在有其他窗口全屏时(包括全屏的游戏窗口),Flyout不会显示。 42 | - 删除了托盘图标功能,在搜寻多方内容后,Windows App SDK不提供直接的托盘图标似乎也是一种无奈,如今的程序对用户的干扰入侵越来越深,托盘图标似乎并不是用户一定想拥有的。但是此程序本身由于没有直接的窗口界面,托盘图标是用户得知程序运行状态与设置功能的一个良好的入口。同时隐藏托盘后,用户没有直接的设置窗口再次启用托盘功能。最终决定在接下来的更新中重新加入托盘,且不可隐藏。 43 | - 完善了语言文件。 44 | - 添加托盘图标功能,加入开机自启选项。 45 | - 将Windows App SDK升级到1.5.240404000。 46 | 47 | ### v0.0.2-beta2 48 | 49 | - 修复了在高DPI情况下窗口位置、大小错位的问题。 50 | - Acrylic效果单独创建,避免窗口在失焦的情况下变为纯色效果。 51 | - 添加托盘图标功能。 52 | 53 | ## 更新日志 54 | 55 | ### v1.1.2-2024.10.06 56 | 57 | 1. 修复了Shell主程序打开时,主页的按钮始终处于关闭状态的bug [`9c18694`](https://github.com/ChenYiLins/MoreFlyout/commit/9c186940670a439e60b4e9b82d0a6de5b794abab)。 58 | 2. 修复了因为Windows App Sdk关于AppWindow的IsShownInSwitchers的bug。在重启Explorer后,此属性设置会失效。关于这个bug的[Issue](https://github.com/microsoft/microsoft-ui-xaml/issues/10026)。目前采用的解决方案为使用Hook钩子检测Explorer事件,因为直接检测窗口消息会因为主程序所使用Hook钩子而失效,目前并未发现其他有效的解决方案。(因为Hook并不是最有效的方法,会造成一部分的性能消耗)[`b66ba87`](https://github.com/ChenYiLins/MoreFlyout/commit/b66ba875ba850f2719ee92bfc6a11404c633a014) 59 | 3. 统一解决方案Nuget包,更新Windows App Sdk至1.6,由于Windows App Sdk的原因,导致MoreFlyout.Shell此版本无法启用裁剪功能,导致Shell的体积相比于上个版本几乎暴增一倍。(但是Server却意外地减少了几乎一倍🤣) 60 | 4. 为正常使用Windows Community Toolkit,将解决方案的TargetFramework更改为22621,但是不会影响最低版本支持。 61 | 5. 为MoreFlyout.Server引入AOT功能,同时对部分使用反射的代码就行标注,避免裁剪问题 [`d415045`](https://github.com/ChenYiLins/MoreFlyout/commit/d41504595e0c03991c5696ccd4be8ca25bd5077d)。 62 | 6. 修复了部分代码的错误,同时删除部分多余变量,精简代码 [`16c2d03`](https://github.com/ChenYiLins/MoreFlyout/commit/16c2d03a5173e54a6574250cec0b6222833664e2)。 63 | 7. 更新了安装程序,卸载程序时会删除产生的注册表项 [`d82d4d9`](https://github.com/ChenYiLins/MoreFlyout/commit/d82d4d9892757ebcde4e0fa10bcb780c9d59205a)。 64 | 8. 添加了英文开发日志,截止目前版本之前的日志基于中文日志使用翻译软件翻译,可能会存在部分词不达意的情况。 65 | 9. 添加了对x86和arm64的支持。 66 | 67 | ### v1.1.1-2024.09.18 68 | 69 | 1. 原程序变更为MoreFlyout.Server,作为基础服务部分,删除了托盘图标的功能。 70 | 2. 新增MoreFlyout.Shell,作为程序的可视化管理设置外壳,同时同步Server与Shell的Windows App SDK和.Net版本。 71 | 3. 修复了在v1.0.0版本开始存在的:Shell主程序打开时,主页的按钮始终处于关闭状态的bug。 72 | 73 | - 经测试,第3点并未成功修复,将在下一个版本修复。😭 74 | 75 | ### v0.0.2-beta2-2024.03.11 76 | 77 | 1. 现在能够提供正常的Acrylic效果。 78 | 2. 现在程序能够正常在托盘图标显示。 79 | 80 | ### v0.0.1-beta1-2024.02.26 81 | 82 | 1. 基础功能更新。 83 | -------------------------------------------------------------------------------- /RELEASENOTE_EN.md: -------------------------------------------------------------------------------- 1 | # MoreFlyout 2 | 3 | ## Development log 4 | 5 | ### v1.1.2-health action1-2024.09.22 6 | 7 | - The main purpose of this version is to fix the existing errors in the program, optimize the program structure and improve the log. 8 | - Fixed a bug where the button on the home page was always closed when the Shell main program was opened. 9 | - Fixed a bug caused by IsShownInSwitchers about AppWindow in Windows App Sdk. This property setting will become invalid after restarting Explorer. [Issues](https://github.com/Microsoft/Microsoft-UI-xaml/issues/10026) about this bug . At present, the solution is to use Hook to detect Explorer events, because directly detecting window messages will be invalid because the Hook is used by the main program, and no other effective solution has been found at present. (because Hook is not the most effective method, it will cause some performance consumption) 10 | - Unified solution Nuget package, update Windows App Sdk to 1.6. 11 | - English development logs have been added. The logs before the current version are translated based on Chinese logs using translation software, and some words may be unsatisfactory. 12 | - In order to use Windows Community Toolkit normally, change the TargetFramework of the solution to 22621. 13 | - Code quality update: some codes are revised, while some redundant variables are deleted and the codes are simplified. 14 | - Introduce AOT function for MoreFlyout.Server, and at the same time, just mark some reflected codes to avoid clipping problems. 15 | - Because of some force majeure factors, the clipping function has to be abandoned for MoreFlyout.Shell, and the program volume has become a little bloated. You can check [issue](https://github.com/ChenYiLins/MoreFlyout/issues/2) on github . 16 | - The installer has been updated, and the generated registry key will be deleted when uninstalling the program. 17 | 18 | ### v1.1.1-2024.09.16 19 | 20 | - Now fixed the bug that all buttons are off by default when the program starts. 21 | 22 | ### v1.1.0-2024.07.24 23 | 24 | - delete MoreFlyout.Shell built by C++ and write it in C#. 25 | -unify the. Net and Windows App SDK versions of MoreFlyout.Server and MoreFlyout.Shell 26 | - Add a Preview branch as a Preview update, and merge it into the main branch when the update is completed. The preview branch may adopt the preview version of Window App SDK, but it will not merge into the main branch when the preview version is used. 27 | 28 | ### v1.0.0-2024.06.01 29 | 30 | - In the branch CppVersion, I once considered changing the main program to C++ refactoring, but after many stress tests, I had to face the memory leak problem that is easy to occur when the C++ WinUI program runs for a long time, and decided to keep the main program written in C#, delete the tray icon function at the same time, and divide the project into MoreFlyout.Server and MoreFlyout.Shell. At the same time, the more flyout.shell part was written in C++ as the visual management shell of the program. 31 | 32 | ### v0.0.3-beta3-2024.03.12 33 | 34 | - Changed the program structure, streamlined the template automatically generated by TemplateStudio before, and changed some names at the same time, for example, changing MainWindow to FlyoutWindow is more intuitive. Streamlined some logic codes. 35 | - Thanks to [Simon Mourier](https://github.com/Smourier) for his [answer](https://stackoverflow.com/questions/78210920/) In-c-sharp-WinUI-a-crash-about-system-executioninexception-is-caused-for-unk, which successfully solved the serious collapse of winui caused by CG recycling. 36 | - Change the whole window display to Flyout component display. Although the system Flyout doesn't actually use WinUI Flyout animation, the animation effect is very close. 37 | - Upgrade the Windows App SDK from version 1.4 to version 1.5, and change the exit method of the whole program, so that the whole program will no longer crash because of the window crash. In the future, consider putting the function of detecting the window status into the tray icon. 38 | - The program must be run as an administrator before it can be displayed on top of other applications. 39 | - Added the function of full-screen detection of other windows. When other windows are full-screen (including full-screen game windows), Flyout will not be displayed. 40 | - The tray icon function has been deleted. After searching for multi-party content, it seems to be a kind of helplessness that Windows App SDK does not provide a direct tray icon. Nowadays, the program is more and more intrusive to users, and the tray icon does not seem to be what users must want. However, the program itself has no direct window interface, and the tray icon is a good entrance for users to know the running status and setting functions of the program. After hiding the tray at the same time, the user has no direct setting window to enable the tray function again. Finally, I decided to add the tray again in the next update, and it cannot be hidden. 41 | - The language file has been improved. 42 | - Add tray icon function, and add power-on and self-start option. 43 | - upgrade the Windows App SDK to 1.5.24000. 44 | 45 | ### v0.0.2-beta2 46 | 47 | - Fixed the problem of dislocation of window position and size under the condition of high DPI. 48 | The-Acrylic effect is created separately to prevent the window from becoming a solid color effect when it is out of focus. 49 | - Add tray icon function. 50 | 51 | ## Update log 52 | 53 | ### v1.1.2-2024.10.06 54 | 55 | 1. Fixed a bug where the button on the home page was always closed when the Shell main program was opened [`9c18694`](https://github.com/ChenYiLins/MoreFlyout/commit/9c186940670a439e60b4e9b82d0a6de5b794abab). 56 | 2. Fixed a bug caused by IsShownInSwitchers about AppWindow in Windows App Sdk. This property setting will become invalid after restarting Explorer. [issue](https://github.com/Microsoft/Microsoft-UI-xaml/issues/10026) about this bug . At present, the solution is to use Hook to detect Explorer events, because directly detecting window messages will be invalid because the Hook is used by the main program, and no other effective solution has been found at present. (Because Hook is not the most effective method, it will cause some performance consumption.) [`B66Ba87`](https://github.com/ChenYiLins/MoreFlyout/commit/b66ba875ba850f2719ee92bfc6a11404c633a014) 57 | 3. Updated and unify the solution Nuget package, and update the Windows App Sdk to 1.6. Due to the Windows App Sdk, this version of MoreFlyout.Shell can't enable the trimming, resulting in the volume of the Shell almost doubling compared with the previous version.(But the volume of Server was unexpectedly reduced by almost one time.🤣) 58 | 4. Updated the TargetFramework to 22621, in order to use Windows Community Toolkit normally, but the minimum version support will not be affected. 59 | 5. Added the AOT function for MoreFlyout.Server, and at the same time, just mark some reflected codes to avoid the clipping problem [`d415045`](https://github.com/ChenYiLins/MoreFlyout/commit/d41504595e0c03991c5696ccd4be8ca25bd5077d). 60 | 6. Fixed some code errors, and deleted some redundant variables to simplify the code [`16c2d03`](https://github.com/ChenYiLins/MoreFlyout/commit/16c2d03a5173e54a6574250cec0b6222833664e2). 61 | 7. Updated the installer, and the generated registry key will be deleted when uninstalling the program [`d82d4d9`](https://github.com/ChenYiLins/MoreFlyout/commit/d82d4d9892757ebcde4e0fa10bcb780c9d59205a). 62 | 8. Updated release note, you guess what you are reading now😂. 63 | 9. Added the support for x86 and arm64. And one more thing, AOT isnot support to x86. 64 | 65 | ### v1.1.1-2024.09.18 66 | 67 | 1. The original program was changed to MoreFlyout.Server, and as a basic service part, the function of tray icon was deleted. 68 | 2. Add MoreFlyout.Shell as the visual management setting Shell of the program, and synchronize the Windows App SDK and. Net versions of the Server and shell. 69 | 3. Fixed a bug that existed at the beginning of v1.0.0: when the Shell main program was opened, the button on the home page was always closed. 70 | 71 | - After testing, point 3 was not successfully fixed and will be fixed in the next version. 72 | 73 | ### v0.0.2-beta2-2024.03.11 74 | 75 | 1. Now it can provide normal Acrylic effect. 76 | 2. Now the program can be displayed on the tray icon normally. 77 | 78 | ### v0.0.1-beta1-2024.02.26 79 | 80 | 1. Basic function update. --------------------------------------------------------------------------------