Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Dependency Injection for Better Development Experience #3175

Open
wants to merge 21 commits into
base: dev
Choose a base branch
from

Conversation

Jack251970
Copy link
Contributor

@Jack251970 Jack251970 commented Jan 9, 2025

Introduce dependency injection for accessing the API property in anywhere inside the project.

This can improve development experience. E.g. We can put the MessgaeBoxEx to Flow.Launcher project and we can access the design page like this:

image

Copy link
Contributor

coderabbitai bot commented Jan 9, 2025

📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive refactoring of message display and dependency management across the Flow Launcher application. The primary changes involve replacing direct MessageBoxEx.Show calls with a centralized API.ShowMsgBox method and implementing dependency injection using Microsoft's hosting and dependency injection frameworks. The modifications span multiple files and classes, focusing on improving code modularity, testability, and consistent message handling.

Changes

File/Path Change Summary
Flow.Launcher.Core/Configuration/Portable.cs Replaced MessageBoxEx.Show with API.ShowMsgBox for message display. Added private readonly IPublicAPI API.
Flow.Launcher.Core/ExternalPlugins/Environments/* Updated message box display in environment-related classes, added protected readonly IPublicAPI API.
Flow.Launcher.Core/Plugin/PluginManager.cs Modified file copying message display method to use API.ShowMsgBox. Changed API property to be initialized directly.
Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj Added CommunityToolkit.Mvvm package reference.
Flow.Launcher/App.xaml.cs Refactored initialization with dependency injection, changed API property type to IPublicAPI.
Flow.Launcher/PublicAPIInstance.cs Updated constructor to parameterless and changed _alphabet field type to IAlphabet.
Multiple UI-related files Replaced MessageBoxEx.Show with App.API.ShowMsgBox in various methods.
Flow.Launcher/MessageBoxEx.xaml Updated class and namespace declaration to remove Core subnamespace.
Flow.Launcher/MessageBoxEx.xaml.cs Changed namespace from Flow.Launcher.Core to Flow.Launcher.

Suggested labels

dependencies, .NET

Suggested reviewers

  • JohnTheGr8
  • taooceros
  • jjw24

Poem

🐰 A Rabbit's Dependency Dance

With APIs aligned and injections so neat,
Our code now dances to a modular beat.
MessageBoxes transformed, no longer alone,
Dependency magic has found its new home!

Hop, hop, hooray! 🎉


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

This comment has been minimized.

@taooceros
Copy link
Member

I was thinking about unifying the access to IPublicAPI. Currently this is quite messy (some uses PluginManager.API some uses other technique).

Very earlier I was thinking about integrating dependency injection in flow, but that seems to be pretty complicated. Maybe we can do that gradually specifically for the PublicAPI?

I am not sure. What do others think about global state access?

@Jack251970
Copy link
Contributor Author

Jack251970 commented Jan 11, 2025

@taooceros I agree that dependency injection is the most elegant way to access API from anywhere. But considering the current architecture of the FL codes , App.API should not be deprecated (so many codes rely on this). So this PR exposes App.API for other projects to call it so that ProgressBoxEx can be placed into the main project which allows design page to work.

@Jack251970
Copy link
Contributor Author

Jack251970 commented Jan 12, 2025

I mean it can serve as a transitional solution for unifying the call of api functions. (here I just do for functions related to ProgressBoxEx)

This comment has been minimized.

@Jack251970 Jack251970 changed the title Move MessageBoxEx to main project for better development experience Introduce Dependency Injection for Better Development Experience Jan 12, 2025
Copy link

gitstream-cm bot commented Jan 12, 2025

🥷 Code experts: Yusyuriv, jjw24

Yusyuriv, jjw24 have most 🧠 knowledge in the files.

See details

Flow.Launcher.Core/Configuration/Portable.cs

Knowledge based on git-blame:
jjw24: 80%

Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs

Knowledge based on git-blame:
jjw24: 55%
Yusyuriv: 4%

Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs

Knowledge based on git-blame:
jjw24: 73%

Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs

Knowledge based on git-blame:
jjw24: 70%

Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs

Knowledge based on git-blame:

Flow.Launcher.Core/Plugin/PluginManager.cs

Knowledge based on git-blame:
jjw24: 4%
Yusyuriv: 4%

Flow.Launcher.Core/Plugin/PluginsLoader.cs

Knowledge based on git-blame:
jjw24: 16%

Flow.Launcher.Core/Resource/Internationalization.cs

Knowledge based on git-blame:
jjw24: 11%
Yusyuriv: 4%

Flow.Launcher.Core/Resource/Theme.cs

Knowledge based on git-blame:
jjw24: 19%
Yusyuriv: 15%

Flow.Launcher.Core/Updater.cs

Knowledge based on git-blame:
jjw24: 12%

Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj

Knowledge based on git-blame:
jjw24: 12%

Flow.Launcher.Infrastructure/PinyinAlphabet.cs

Knowledge based on git-blame:
jjw24: 5%

Flow.Launcher.Infrastructure/StringMatcher.cs

Knowledge based on git-blame:
jjw24: 65%

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Knowledge based on git-blame:
Yusyuriv: 15%
jjw24: 3%

Flow.Launcher/ActionKeywords.xaml.cs

Knowledge based on git-blame:
jjw24: 25%

Flow.Launcher/App.xaml.cs

Knowledge based on git-blame:
jjw24: 15%
Yusyuriv: 3%

Flow.Launcher/CustomQueryHotkeySetting.xaml.cs

Knowledge based on git-blame:
Yusyuriv: 19%
jjw24: 17%

Flow.Launcher/CustomShortcutSetting.xaml.cs

Knowledge based on git-blame:
Yusyuriv: 14%

Flow.Launcher/Flow.Launcher.csproj

Knowledge based on git-blame:
jjw24: 12%

Flow.Launcher/Helper/HotKeyMapper.cs

Knowledge based on git-blame:
Yusyuriv: 64%

Flow.Launcher/PriorityChangeWindow.xaml.cs

Knowledge based on git-blame:

Flow.Launcher/PublicAPIInstance.cs

Knowledge based on git-blame:
jjw24: 9%

Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs

Knowledge based on git-blame:
Yusyuriv: 92%

Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs

Knowledge based on git-blame:
Yusyuriv: 94%

Flow.Launcher/SettingPages/ViewModels/SettingsPaneProxyViewModel.cs

Knowledge based on git-blame:
Yusyuriv: 98%

Flow.Launcher/SettingPages/ViewModels/SettingsPaneThemeViewModel.cs

Knowledge based on git-blame:
Yusyuriv: 73%

Flow.Launcher/ViewModel/MainViewModel.cs

Knowledge based on git-blame:
Yusyuriv: 3%
jjw24: 2%

Flow.Launcher/ViewModel/SettingWindowViewModel.cs

Knowledge based on git-blame:
Yusyuriv: 65%
jjw24: 8%

To learn more about /:\ gitStream - Visit our Docs

@Jack251970
Copy link
Contributor Author

I was thinking about unifying the access to IPublicAPI. Currently this is quite messy (some uses PluginManager.API some uses other technique).

Very earlier I was thinking about integrating dependency injection in flow, but that seems to be pretty complicated. Maybe we can do that gradually specifically for the PublicAPI?

I am not sure. What do others think about global state access?

Now I implement dependency injection model for this, and can you please take a look of this?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🔭 Outside diff range comments (1)
Flow.Launcher.Core/Plugin/PluginsLoader.cs (1)

Line range hint 123-127: Consider using constructor injection instead of service locator pattern.

The use of Ioc.Default.GetRequiredService is a service locator anti-pattern that makes the code harder to test and maintain. Consider:

  1. Making the class non-static
  2. Injecting IPublicAPI through the constructor
 public static class PluginsLoader
 {
+    private readonly IPublicAPI _api;
+
+    public PluginsLoader(IPublicAPI api)
+    {
+        _api = api;
+    }

     public static IEnumerable<PluginPair> DotNetPlugins(...)
     {
         // ...
-        Ioc.Default.GetRequiredService<IPublicAPI>().ShowMsgBox(...);
+        _api.ShowMsgBox(...);
🧹 Nitpick comments (19)
Flow.Launcher.Core/Resource/Internationalization.cs (2)

128-128: Consider constructor injection instead of service locator pattern.

While the change aligns with the PR's objective to unify API access, using Ioc.Default directly is a service locator anti-pattern. Consider injecting IPublicAPI through the constructor for better testability and maintainability.

Example refactor:

 public class Internationalization
 {
     public Settings Settings { get; set; }
+    private readonly IPublicAPI _api;
     private const string Folder = "Languages";
     // ... other fields ...

-    public Internationalization()
+    public Internationalization(IPublicAPI api)
     {
+        _api = api;
         AddFlowLauncherLanguageDirectory();
     }

     // ... other methods ...

     public bool PromptShouldUsePinyin(string languageCodeToSet)
     {
         // ... existing code ...
-        if (Ioc.Default.GetRequiredService<IPublicAPI>().ShowMsgBox(text, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
+        if (_api.ShowMsgBox(text, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
             return false;
         // ... existing code ...
     }
 }

Line range hint 114-131: Consider separating UI interaction from business logic.

The method currently mixes business logic (determining if Pinyin should be used) with UI concerns (showing dialog). Consider extracting the UI interaction to improve testability and maintainability.

Example approach:

+public interface IUserPrompt
+{
+    bool ConfirmPinyinUsage(Language language);
+}

 public class Internationalization
 {
     private readonly IPublicAPI _api;
+    private readonly IUserPrompt _userPrompt;

-    public Internationalization(IPublicAPI api)
+    public Internationalization(IPublicAPI api, IUserPrompt userPrompt)
     {
         _api = api;
+        _userPrompt = userPrompt;
     }

     public bool PromptShouldUsePinyin(string languageCodeToSet)
     {
         var languageToSet = GetLanguageByLanguageCode(languageCodeToSet);

         if (Settings.ShouldUsePinyin)
             return false;

         if (languageToSet != AvailableLanguages.Chinese && languageToSet != AvailableLanguages.Chinese_TW)
             return false;

-        string text = languageToSet == AvailableLanguages.Chinese ? "是否启用拼音搜索?" : "是否啓用拼音搜索?";
-        if (_api.ShowMsgBox(text, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
-            return false;
-
-        return true;
+        return _userPrompt.ConfirmPinyinUsage(languageToSet);
     }
 }
Flow.Launcher.Infrastructure/UserSettings/Settings.cs (2)

16-26: Consider constructor injection for better dependency management.

While the current implementation works, it adds another initialization requirement that needs to be managed. Given the discussion about unifying API access and potentially moving towards dependency injection, consider:

  1. Using constructor injection instead of manual initialization
  2. Making the class immutable where possible
  3. Using an interface for the storage dependency

This would better align with the goal of improving the development experience and make future DI adoption easier.

Example approach:

-    public class Settings : BaseModel, IHotkeySettings
+    public class Settings : BaseModel, IHotkeySettings, ISettings
     {
-        private FlowLauncherJsonStorage<Settings> _storage;
+        private readonly ISettingsStorage<Settings> _storage;
 
-        public void Initialize(FlowLauncherJsonStorage<Settings> storage)
-        {
-            _storage = storage;
-        }
+        public Settings(ISettingsStorage<Settings> storage)
+        {
+            _storage = storage ?? throw new ArgumentNullException(nameof(storage));
+        }

Line range hint 1-590: Consider breaking down the Settings class into smaller, focused components.

The Settings class has grown to handle multiple concerns, making it harder to maintain and test. Consider splitting it into smaller, focused classes:

  1. HotkeySettings (hotkey-related properties)
  2. UISettings (window size, fonts, themes)
  3. BrowserSettings (browser configurations)
  4. ExplorerSettings (explorer configurations)
  5. PluginSettings (already partially separated)

This would:

  • Improve maintainability
  • Make the code more testable
  • Reduce the cognitive load when making changes
  • Make it easier to implement proper dependency injection
Flow.Launcher/ViewModel/MainViewModel.cs (1)

62-68: Consider future refactoring to constructor injection.

While using Ioc.Default.GetRequiredService works as a transitional solution, it introduces service location which can make the code harder to test and maintain. Consider gradually moving towards constructor injection in future refactors.

A more maintainable approach would be:

-public MainViewModel()
+public MainViewModel(Settings settings)
{
    _queryTextBeforeLeaveResults = "";
    _queryText = "";
    _lastQuery = new Query();
-   Settings = Ioc.Default.GetRequiredService<Settings>();
+   Settings = settings;
Flow.Launcher/App.xaml.cs (6)

89-90: Avoid using static instances when employing dependency injection

In lines 89-90, you assign the StringMatcher.Instance static property to the instance retrieved from the IoC container:

StringMatcher.Instance = stringMatcher;

This practice introduces a global state, which undermines the benefits of dependency injection and can lead to harder-to-test code. Consider refactoring the code to inject StringMatcher where needed rather than relying on the static instance.


98-98: Refactor to eliminate the static App.API property

While transitioning to dependency injection, retaining the static App.API property may lead to inconsistencies and reduced testability. Instead, inject IPublicAPI into classes that require it, promoting better modularity and adherence to dependency injection principles.


106-107: Inject dependencies into MainWindow instead of passing _settings directly

In lines 106-107, _settings is passed directly to MainWindow's constructor:

var window = new MainWindow(_settings, mainVM);

To maintain consistency with the dependency injection approach, consider injecting Settings into MainWindow via the IoC container. This enhances testability and aligns with best practices.


114-114: Refactor HotKeyMapper to use dependency injection

Currently, HotKeyMapper is initialized statically:

HotKeyMapper.Initialize(mainVM);

Consider refactoring HotKeyMapper to accept dependencies through constructor injection. This change would improve modularity and make the codebase more maintainable.


163-167: Optimize Updater by injecting IPublicAPI

In the AutoUpdates method, API is passed explicitly to UpdateAppAsync:

await Ioc.Default.GetRequiredService<Updater>().UpdateAppAsync(API);

Since Updater is registered in the IoC container, consider injecting IPublicAPI into Updater directly. This reduces dependencies between components and enhances code readability.


210-210: Avoid overusing Ioc.Default for resolving services

In line 210, MainViewModel is resolved directly from the service locator:

Ioc.Default.GetRequiredService<MainViewModel>().Show();

Frequent use of the service locator pattern can lead to code that's harder to maintain and test. Consider injecting MainViewModel where needed instead of resolving it directly.

Flow.Launcher/ActionKeywords.xaml.cs (1)

47-47: Inject IPublicAPI instead of accessing App.API directly

In line 47, App.API.ShowMsgBox(msg); is used to display a message box:

App.API.ShowMsgBox(msg);

To adhere to dependency injection principles and improve testability, consider injecting IPublicAPI into the ActionKeywords class. This approach reduces coupling to the App class and enhances modularity.

Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs (1)

31-31: LGTM! Consider adding error handling.

The change from MessageBoxEx.Show to API.ShowMsgBox aligns with the PR objectives. The lambda syntax is appropriate for the callback scenario.

Consider wrapping the folder removal in a try-catch block to handle potential IO exceptions:

-            FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s));
+            try {
+                FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s));
+            } catch (System.IO.IOException ex) {
+                API.ShowMsgBox($"Failed to remove folder: {ex.Message}");
+            }
Flow.Launcher/PriorityChangeWindow.xaml.cs (1)

47-47: LGTM! Consider extracting the message preparation.

The change aligns with the PR objectives.

Consider extracting the message preparation to improve readability:

-                string msg = translater.GetTranslation("invalidPriority");
-                App.API.ShowMsgBox(msg);
+                App.API.ShowMsgBox(translater.GetTranslation("invalidPriority"));
Flow.Launcher/CustomShortcutSetting.xaml.cs (1)

52-52: LGTM! Consider consolidating validation logic.

The change aligns with the PR objectives.

Consider consolidating the validation logic into a separate method:

+        private bool ValidateShortcut(string key, string value)
+        {
+            if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value))
+            {
+                App.API.ShowMsgBox(InternationalizationManager.Instance.GetTranslation("emptyShortcut"));
+                return false;
+            }
+            if (((update && originalKey != key) || !update) && _hotkeyVm.DoesShortcutExist(key))
+            {
+                App.API.ShowMsgBox(InternationalizationManager.Instance.GetTranslation("duplicateShortcut"));
+                return false;
+            }
+            return true;
+        }
Flow.Launcher/CustomQueryHotkeySetting.xaml.cs (1)

66-66: LGTM! Error handling is maintained.

The change from MessageBoxEx.Show to App.API.ShowMsgBox maintains the existing error handling while aligning with the PR objectives.

Consider adding a descriptive error message that includes the invalid hotkey details:

-                App.API.ShowMsgBox(InternationalizationManager.Instance.GetTranslation("invalidPluginHotkey"));
+                var message = $"{InternationalizationManager.Instance.GetTranslation("invalidPluginHotkey")} (Action: {item.ActionKeyword}, Hotkey: {item.Hotkey})";
+                App.API.ShowMsgBox(message);
Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs (1)

Line range hint 65-72: LGTM! Consider extracting message strings to constants.

The migration from MessageBoxEx.Show to App.API.ShowMsgBox is implemented correctly. The internationalization and message box parameters are properly maintained.

Consider extracting the translation keys to constants at the class level for better maintainability and reusability:

+ private const string ClearLogFolderMessageKey = "clearlogfolderMessage";
+ private const string ClearLogFolderTitleKey = "clearlogfolder";

  private void AskClearLogFolderConfirmation()
  {
      var confirmResult = App.API.ShowMsgBox(
-         InternationalizationManager.Instance.GetTranslation("clearlogfolderMessage"),
-         InternationalizationManager.Instance.GetTranslation("clearlogfolder"),
+         InternationalizationManager.Instance.GetTranslation(ClearLogFolderMessageKey),
+         InternationalizationManager.Instance.GetTranslation(ClearLogFolderTitleKey),
          MessageBoxButton.YesNo
      );
Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs (2)

45-47: Extract common message to reduce duplication.

The "pleaseSelectAnItem" message is used multiple times. Consider extracting it to a constant or helper method.

+ private const string PleaseSelectItemKey = "pleaseSelectAnItem";
+ private void ShowPleaseSelectItemMessage() => 
+     App.API.ShowMsgBox(InternationalizationManager.Instance.GetTranslation(PleaseSelectItemKey));

  private void CustomHotkeyDelete()
  {
      var item = SelectedCustomPluginHotkey;
      if (item is null)
      {
-         App.API.ShowMsgBox(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
+         ShowPleaseSelectItemMessage();
          return;
      }

Also applies to: 70-72, 91-93, 115-117


Line range hint 49-56: Consider extracting confirmation dialog pattern.

Both delete operations follow the same confirmation pattern. Consider extracting this to a reusable method.

+ private bool ConfirmDeletion<T>(T item, string warningKey, string itemDisplay)
+ {
+     var result = App.API.ShowMsgBox(
+         string.Format(
+             InternationalizationManager.Instance.GetTranslation(warningKey),
+             itemDisplay
+         ),
+         InternationalizationManager.Instance.GetTranslation("delete"),
+         MessageBoxButton.YesNo
+     );
+     return result == MessageBoxResult.Yes;
+ }

  private void CustomHotkeyDelete()
  {
      var item = SelectedCustomPluginHotkey;
      if (item is null)
      {
          ShowPleaseSelectItemMessage();
          return;
      }

-     var result = App.API.ShowMsgBox(/*...*/);
-     if (result is MessageBoxResult.Yes)
+     if (ConfirmDeletion(item, "deleteCustomHotkeyWarning", item.Hotkey))
      {
          Settings.CustomPluginHotkeys.Remove(item);
          HotKeyMapper.RemoveHotkey(item.Hotkey);
      }
  }

Also applies to: 95-102

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cccbb0 and 3cb9d1d.

📒 Files selected for processing (30)
  • Flow.Launcher.Core/Configuration/Portable.cs (7 hunks)
  • Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs (5 hunks)
  • Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs (1 hunks)
  • Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs (1 hunks)
  • Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs (1 hunks)
  • Flow.Launcher.Core/Plugin/PluginManager.cs (1 hunks)
  • Flow.Launcher.Core/Plugin/PluginsLoader.cs (2 hunks)
  • Flow.Launcher.Core/Resource/Internationalization.cs (2 hunks)
  • Flow.Launcher.Core/Resource/Theme.cs (4 hunks)
  • Flow.Launcher.Core/Updater.cs (4 hunks)
  • Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj (1 hunks)
  • Flow.Launcher.Infrastructure/PinyinAlphabet.cs (2 hunks)
  • Flow.Launcher.Infrastructure/StringMatcher.cs (2 hunks)
  • Flow.Launcher.Infrastructure/UserSettings/Settings.cs (2 hunks)
  • Flow.Launcher/ActionKeywords.xaml.cs (1 hunks)
  • Flow.Launcher/App.xaml.cs (5 hunks)
  • Flow.Launcher/CustomQueryHotkeySetting.xaml.cs (1 hunks)
  • Flow.Launcher/CustomShortcutSetting.xaml.cs (1 hunks)
  • Flow.Launcher/Flow.Launcher.csproj (2 hunks)
  • Flow.Launcher/Helper/HotKeyMapper.cs (1 hunks)
  • Flow.Launcher/MessageBoxEx.xaml (1 hunks)
  • Flow.Launcher/MessageBoxEx.xaml.cs (1 hunks)
  • Flow.Launcher/PriorityChangeWindow.xaml.cs (2 hunks)
  • Flow.Launcher/PublicAPIInstance.cs (1 hunks)
  • Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs (1 hunks)
  • Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs (4 hunks)
  • Flow.Launcher/SettingPages/ViewModels/SettingsPaneProxyViewModel.cs (1 hunks)
  • Flow.Launcher/SettingPages/ViewModels/SettingsPaneThemeViewModel.cs (1 hunks)
  • Flow.Launcher/ViewModel/MainViewModel.cs (2 hunks)
  • Flow.Launcher/ViewModel/SettingWindowViewModel.cs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • Flow.Launcher/MessageBoxEx.xaml.cs
🧰 Additional context used
📓 Learnings (1)
Flow.Launcher/Flow.Launcher.csproj (1)
Learnt from: taooceros
PR: Flow-Launcher/Flow.Launcher#2616
File: Flow.Launcher/Flow.Launcher.csproj:7-7
Timestamp: 2024-11-12T03:58:56.325Z
Learning: In the Flow Launcher project, the version number in the `Flow.Launcher.csproj` file is dynamically updated during the CI/CD process.
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: gitStream.cm
  • GitHub Check: gitStream.cm
🔇 Additional comments (20)
Flow.Launcher.Core/Resource/Internationalization.cs (1)

14-14: LGTM! Using CommunityToolkit.Mvvm for dependency injection.

The addition of CommunityToolkit.Mvvm's dependency injection aligns well with the PR's objective to improve API access patterns.

Flow.Launcher.Infrastructure/UserSettings/Settings.cs (1)

7-7: LGTM!

The addition of the Storage namespace import is appropriate for the new storage functionality.

Flow.Launcher/PublicAPIInstance.cs (1)

36-36: Good use of abstraction by changing _alphabet to IAlphabet

Switching the type from PinyinAlphabet to the IAlphabet interface enhances flexibility and allows for different implementations, promoting a more extensible design.

Flow.Launcher/ViewModel/MainViewModel.cs (2)

28-28: LGTM! Using statement aligns with DI changes.

The addition of CommunityToolkit.Mvvm.DependencyInjection enables proper dependency injection support.


68-68: Verify DI container configuration.

Ensure that Settings is properly registered in the DI container before MainViewModel is instantiated.

Run this script to verify the DI setup:

✅ Verification successful

DI container configuration for Settings is properly set up

The Settings class is correctly registered as a singleton in the DI container before MainViewModel is instantiated, ensuring proper dependency management.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for proper DI registration of Settings
# Look for container configuration and Settings registration
rg -A 5 'AddSingleton<Settings>|services\.Add.*Settings'

Length of output: 58


Script:

#!/bin/bash
# First, find Settings class definition
ast-grep --pattern 'class Settings'

# Then look for service collection setup and registration patterns
rg -l "IServiceCollection|ServiceCollection|BuildServiceProvider"

# Also search for any Settings usage in startup/configuration files
rg -l "Settings" "*Program.cs" "*Startup.cs"

Length of output: 34619


Script:

#!/bin/bash
# Look for DI configuration in App.xaml.cs and service registration patterns
rg -A 10 "CreateHost|Host\.CreateDefault|ConfigureServices|AddSingleton|\.Services\." "Flow.Launcher/App.xaml.cs"

# Search for service registration using ast-grep to find method calls
ast-grep --pattern 'AddSingleton<$_>($_)'

# Look for Settings usage in App initialization
rg -A 5 "new Settings\(\)|GetService<Settings>|GetRequiredService<Settings>" "Flow.Launcher/App.xaml.cs"

Length of output: 1522

Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs (1)

28-28: Confirmed refactoring to centralized message handling

The update to use API.ShowMsgBox(s) aligns with the project's shift towards centralized message handling via IPublicAPI. This enhances consistency across the codebase.

Flow.Launcher/PriorityChangeWindow.xaml.cs (1)

27-27: LGTM! Error handling is maintained.

The change from MessageBoxEx.Show to App.API.ShowMsgBox maintains the existing error handling while aligning with the PR objectives.

Flow.Launcher/CustomShortcutSetting.xaml.cs (1)

46-46: LGTM! Validation is maintained.

The change from MessageBoxEx.Show to App.API.ShowMsgBox maintains the existing validation while aligning with the PR objectives.

Flow.Launcher/MessageBoxEx.xaml (1)

2-2: LGTM! Namespace changes align with project reorganization.

The MessageBoxEx class has been correctly moved from Flow.Launcher.Core to Flow.Launcher namespace, aligning with the PR objectives.

Let's verify that all references to MessageBoxEx have been updated:

Also applies to: 6-6

✅ Verification successful

✅ Namespace changes are properly implemented

All references to MessageBoxEx have been updated to use the new Flow.Launcher namespace. No remaining references to the old Flow.Launcher.Core namespace were found.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining references to Flow.Launcher.Core.MessageBoxEx
rg "Flow\.Launcher\.Core\.MessageBoxEx"

Length of output: 41


Script:

#!/bin/bash
# Search for MessageBoxEx references in all files
rg "MessageBoxEx" -A 2

# Specifically look for XAML references
fd -e xaml -x grep -l "MessageBoxEx" {} \;

Length of output: 1685

Flow.Launcher.Core/Updater.cs (2)

59-59: LGTM! Consistent API usage for message boxes.

The changes to use API.ShowMsgBox are consistent with the project-wide changes and maintain the same functionality.

Also applies to: 74-76, 89-89


26-26: Consider thread safety implications of singleton API instance.

While using dependency injection is good, retrieving the API instance at field initialization might cause issues if the IoC container isn't set up when the class is instantiated.

Consider injecting IPublicAPI through the constructor instead:

-private readonly IPublicAPI API = Ioc.Default.GetRequiredService<IPublicAPI>();
+private readonly IPublicAPI API;
+
+public Updater(IPublicAPI api)
+{
+    API = api;
+}
Flow.Launcher.Core/Configuration/Portable.cs (1)

19-19: LGTM! Well-structured dependency injection.

The changes properly implement dependency injection by using a private readonly field initialized through the constructor.

Flow.Launcher.Core/Resource/Theme.cs (2)

14-14: LGTM: Dependency injection setup looks good.

The addition of CommunityToolkit.Mvvm.DependencyInjection and initialization of IPublicAPI through dependency injection aligns with the PR objectives of improving the development experience.

Also applies to: 27-27


114-114: LGTM: Message box calls properly migrated.

The MessageBoxEx.Show calls have been consistently replaced with API.ShowMsgBox, maintaining the same functionality while using the new centralized message handling approach.

Also applies to: 124-124

Flow.Launcher.Core/Plugin/PluginManager.cs (1)

522-522: LGTM: Consistent message handling approach.

The change to use API.ShowMsgBox via lambda expression maintains consistency with the PR's objective of centralizing message handling.

Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs (1)

28-28: LGTM: Consistent message handling approach.

The change to use API.ShowMsgBox via lambda expression maintains consistency with the PR's objective of centralizing message handling.

Flow.Launcher/SettingPages/ViewModels/SettingsPaneProxyViewModel.cs (1)

25-25: LGTM! Change aligns with unified API access pattern.

The replacement of MessageBoxEx.Show with App.API.ShowMsgBox is consistent with the PR objective of unifying API access.

Let's verify error handling in proxy testing scenarios:

✅ Verification successful

Error handling verification successful

The proxy-related error handling is comprehensive and properly maintained:

  • Input validation for server and port
  • Connection failure handling
  • All error messages are properly internationalized
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other proxy-related error handling patterns
rg -A 2 "proxyConnectFailed|serverCantBeEmpty|portCantBeEmpty" --type cs

Length of output: 1129

Flow.Launcher/Helper/HotKeyMapper.cs (1)

49-49: LGTM! Consistent error handling pattern.

The change to App.API.ShowMsgBox maintains consistent error handling across the application.

Let's verify the consistency of error handling in hotkey-related scenarios:

✅ Verification successful

Verified: Message box usage is consistent across the codebase

The change from MessageBoxEx.Show to App.API.ShowMsgBox in HotKeyMapper.cs aligns with the application-wide pattern where all UI components use the API abstraction for showing message boxes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for similar hotkey registration error handling patterns
rg "registerHotkeyFailed|HotkeyManager.Current" --type cs -A 2

Length of output: 1387


Script:

#!/bin/bash
# Search for MessageBoxEx.Show and App.API.ShowMsgBox usage
rg "MessageBoxEx\.Show|App\.API\.ShowMsgBox" --type cs -A 2

Length of output: 5488

Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj (1)

57-57: LGTM! Addition of MVVM toolkit enhances development experience.

The CommunityToolkit.Mvvm package addition supports the MVVM pattern implementation across the project.

Flow.Launcher/Flow.Launcher.csproj (1)

91-92: Review framework and package version compatibility.

The project targets .NET 7 but uses .NET 8 packages (Microsoft.Extensions.DependencyInjection and Microsoft.Extensions.Hosting version 8.0.1). This version mismatch might cause compatibility issues.

Consider downgrading to version 7.x.x or upgrading the target framework to .NET 8.

Let's verify the impact:

✅ Verification successful

Version mismatch is safe for current DI usage patterns

The codebase uses only basic DI features (Host builder and singleton registration) that are stable between .NET 7 and 8. While aligning versions with the target framework is recommended, the current implementation doesn't use any .NET 8 specific features that would cause compatibility issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for DI usage patterns that might be affected
rg "IServiceCollection|IServiceProvider|IHost" --type cs -A 2

Length of output: 1080


Script:

#!/bin/bash
# Search for DI setup and usage patterns
rg "using Microsoft\.Extensions\.(DependencyInjection|Hosting)" --type cs -A 3

# Search for common DI patterns
rg "AddSingleton|AddScoped|AddTransient|BuildServiceProvider|CreateDefaultBuilder|ConfigureServices" --type cs -A 3

Length of output: 1767

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3cb9d1d and 2a423f0.

📒 Files selected for processing (1)
  • Flow.Launcher.Infrastructure/StringMatcher.cs (3 hunks)
🔇 Additional comments (2)
Flow.Launcher.Infrastructure/StringMatcher.cs (2)

11-11: LGTM!

The use of target-typed new() expression improves code conciseness while maintaining readability.


Line range hint 254-268: LGTM!

The implementation of CalculateClosestSpaceIndex is correct and the change to static is appropriate as it doesn't use instance state.

This comment has been minimized.

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
Flow.Launcher.Infrastructure/StringMatcher.cs (2)

17-26: 🛠️ Refactor suggestion

Consider using constructor injection instead of service locator pattern.

The current implementation uses the service locator pattern which is generally considered an anti-pattern. While the test constructor provides a workaround, it would be better to use constructor injection consistently.

-public StringMatcher()
-{
-    _alphabet = Ioc.Default.GetRequiredService<IAlphabet>();
-}
-
-// This is a workaround to allow unit tests to set the instance
-public StringMatcher(IAlphabet alphabet)
-{
-    _alphabet = alphabet;
-}
+public StringMatcher(IAlphabet alphabet)
+{
+    _alphabet = alphabet ?? throw new ArgumentNullException(nameof(alphabet));
+}

256-257: ⚠️ Potential issue

Fix numeric character comparison in IsAcronymNumber.

The current implementation incorrectly compares character codes with integers.

-private static bool IsAcronymNumber(string stringToCompare, int compareStringIndex)
-    => stringToCompare[compareStringIndex] >= 0 && stringToCompare[compareStringIndex] <= 9;
+private static bool IsAcronymNumber(string stringToCompare, int compareStringIndex)
+    => char.IsDigit(stringToCompare[compareStringIndex]);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff110b3 and 3bebb69.

📒 Files selected for processing (2)
  • Flow.Launcher.Infrastructure/StringMatcher.cs (3 hunks)
  • Flow.Launcher.Test/FuzzyMatcherTest.cs (11 hunks)
🔇 Additional comments (2)
Flow.Launcher.Infrastructure/StringMatcher.cs (2)

251-254: LGTM! Good static method refactoring.

The change to make IsAcronymChar static is appropriate as it doesn't depend on instance state.


Line range hint 260-274: LGTM! Good static method refactoring.

The change to make CalculateClosestSpaceIndex static is appropriate as it doesn't depend on instance state.

Flow.Launcher.Test/FuzzyMatcherTest.cs Show resolved Hide resolved

This comment has been minimized.

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (8)
Flow.Launcher/ViewModel/SettingWindowViewModel.cs (1)

7-21: Consider a more gradual transition to proper DI.

While the current changes introduce dependency injection, they rely on the service locator pattern which can make the code harder to test and maintain. Consider these steps for a cleaner DI implementation:

  1. Create an interface for Settings management
  2. Use constructor injection instead of Ioc.Default
  3. Register dependencies at composition root
  4. Update tests to use mocked dependencies

This will improve testability while maintaining backward compatibility with existing code.

Flow.Launcher/PublicAPIInstance.cs (1)

50-55: Consider restructuring to avoid circular dependencies

The need for a separate Initialize method to avoid recursive dependency injection suggests a potential architectural issue. Consider:

  1. Breaking the circular dependency by extracting a common interface
  2. Using an event-based approach
  3. Implementing a mediator pattern

This would eliminate the need for the two-phase initialization and make the dependencies more explicit.

Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs (1)

162-164: Consider adding error handling for the update process.

The update process could fail for various reasons (network issues, permissions, etc.). Consider wrapping the async call with try-catch and providing user feedback.

 private void UpdateApp()
 {
-    _ = _updater.UpdateAppAsync(false);
+    try
+    {
+        _ = _updater.UpdateAppAsync(false);
+    }
+    catch (Exception ex)
+    {
+        Notification.Show(
+            InternationalizationManager.Instance.GetTranslation("updateError"),
+            ex.Message);
+    }
 }
Flow.Launcher/SettingWindow.xaml.cs (2)

27-35: Consider using constructor injection for dependencies

Currently, dependencies are being resolved within the constructor using Ioc.Default.GetRequiredService<T>(), which follows the service locator pattern. This can make unit testing and maintenance more challenging. Consider injecting dependencies via constructor parameters to enhance testability and adhere to dependency injection best practices.


169-169: Allow pages to resolve their own dependencies

Passing _settings, _updater, and _portable through PaneData couples SettingWindow tightly with its child pages. To improve modularity and leverage dependency injection fully, consider allowing each page to resolve its own dependencies from the IoC container.

Flow.Launcher/CustomQueryHotkeySetting.xaml.cs (2)

18-22: Inject IPublicAPI for consistent dependency management

With the shift towards dependency injection, consider injecting IPublicAPI into the constructor alongside Settings. This promotes consistency in dependency management and enhances testability by reducing reliance on the static App.API.


63-63: Avoid direct access to App.API for better testability

Accessing App.API directly in the UpdateItem method increases coupling and hinders unit testing. Injecting IPublicAPI as a dependency would adhere to dependency injection principles and improve maintainability.

Flow.Launcher/App.xaml.cs (1)

209-209: Reuse the resolved MainViewModel instance

MainViewModel is resolved multiple times using Ioc.Default.GetRequiredService<MainViewModel>(). Storing the instance in a private field or property after the first resolution can improve performance and code readability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3bebb69 and 8d83849.

📒 Files selected for processing (9)
  • Flow.Launcher.Core/Updater.cs (5 hunks)
  • Flow.Launcher/App.xaml.cs (5 hunks)
  • Flow.Launcher/CustomQueryHotkeySetting.xaml.cs (2 hunks)
  • Flow.Launcher/PublicAPIInstance.cs (4 hunks)
  • Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs (2 hunks)
  • Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs (1 hunks)
  • Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs (4 hunks)
  • Flow.Launcher/SettingWindow.xaml.cs (5 hunks)
  • Flow.Launcher/ViewModel/SettingWindowViewModel.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs
  • Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs
  • Flow.Launcher.Core/Updater.cs
🔇 Additional comments (6)
Flow.Launcher/ViewModel/SettingWindowViewModel.cs (2)

9-9: Well-designed immutable Settings property!

The use of the init accessor ensures Settings cannot be modified after initialization, which is a good practice for dependency injection.


20-21: Clean and focused Save implementation!

The simplified Save method properly delegates the responsibility to the Settings object, adhering to the Single Responsibility Principle.

Flow.Launcher/PublicAPIInstance.cs (3)

28-28: LGTM! Using Microsoft's MVVM Toolkit for DI

The addition of CommunityToolkit.Mvvm.DependencyInjection aligns well with the PR's objective of introducing dependency injection.


42-47: Consider using constructor injection over service location

Using Ioc.Default.GetRequiredService<T>() within the constructor makes the code harder to test and maintain. Consider using constructor injection instead:

-public PublicAPIInstance()
+public PublicAPIInstance(
+    SettingWindowViewModel settingsVM,
+    MainViewModel mainVM)
{
-    _settingsVM = Ioc.Default.GetRequiredService<SettingWindowViewModel>();
-    _mainVM = Ioc.Default.GetRequiredService<MainViewModel>();
+    _settingsVM = settingsVM;
+    _mainVM = mainVM;
     GlobalHotkey.hookedKeyboardCallback = KListener_hookedKeyboardCallback;
     WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
}

114-117: LGTM! Simplified window opening logic

The change to use SingletonWindowOpener reduces coupling and simplifies the method implementation.

Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs (1)

163-163: LGTM! Good progress on dependency injection.

The removal of the direct App.API parameter aligns well with the PR's objective of implementing proper dependency injection. This change suggests that the Updater class now internally manages its API dependencies.

Let's verify that the Updater class properly handles the API dependency:

✅ Verification successful

Verified: API dependency properly managed through DI

The change to remove the App.API parameter from UpdateAppAsync is correct and consistent with the codebase. The Updater class is properly managed through dependency injection, as evidenced by:

  • All consumers obtain the Updater instance through DI
  • The method signature is consistently used across the codebase
  • The IoC container properly manages the Updater registration
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the Updater class implementation to verify API injection
ast-grep --pattern 'class Updater {
  $$$
  UpdateAppAsync($$$) {
    $$$
  }
  $$$
}'

Length of output: 88


Script:

#!/bin/bash
# Find files containing Updater
fd -t f "Updater"

# Search for UpdateAppAsync method implementation
rg "UpdateAppAsync" -A 5

Length of output: 2645

Flow.Launcher/PublicAPIInstance.cs Outdated Show resolved Hide resolved
Flow.Launcher/App.xaml.cs Outdated Show resolved Hide resolved
{
// We need to initialize Updater not in the constructor because we want to avoid
// recrusive dependency injection
_updater = Ioc.Default.GetRequiredService<Updater>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember this is one of the reason I forfeit DI before. Not elegant but maybe good enough.

@@ -145,7 +151,7 @@ private double WindowLeft()
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0);
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.Width, 0);
var left = (dip2.X - this.ActualWidth) / 2 + dip1.X;
var left = (dip2.X - ActualWidth) / 2 + dip1.X;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You sure this is correct? I think it's very instance dependent

Copy link
Contributor Author

@Jack251970 Jack251970 Jan 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is only necessary under the occasions as follows:

Disambiguation:
If a local variable or parameter has the same name as a class property or field, you need this. to distinguish the instance member from the local scope.

Accessing the current instance explicitly:
When passing the current object as a parameter to a method or event handler.

So I think I can remove this here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I think I read it wrongly. Somehow when I read it I think I saw somewhere you add a static.

I will recheck later

@taooceros
Copy link
Member

Will this create conflict with #2774 ?

@Jack251970
Copy link
Contributor Author

Will this create conflict with #2774 ?

@taooceros From my view, it will not cause any conflicts. PublicAPI instance is created before other instances. And messageboxEx api function should work.

This comment has been minimized.

@Jack251970 Jack251970 requested a review from taooceros January 21, 2025 08:28
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
Flow.Launcher/PublicAPIInstance.cs (2)

40-43: 🛠️ Refactor suggestion

Consider using constructor injection over service location.

Using Ioc.Default.GetRequiredService<T>() within the constructor makes the code harder to test and maintain. Consider using constructor injection instead:

-public PublicAPIInstance()
+public PublicAPIInstance(
+    SettingWindowViewModel settingsVM,
+    MainViewModel mainVM)
{
-    _settingsVM = Ioc.Default.GetRequiredService<SettingWindowViewModel>();
-    _mainVM = Ioc.Default.GetRequiredService<MainViewModel>();
+    _settingsVM = settingsVM;
+    _mainVM = mainVM;
     GlobalHotkey.hookedKeyboardCallback = KListener_hookedKeyboardCallback;
     WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
}

80-80: ⚠️ Potential issue

Implement proper async/await handling for update checks.

The current implementation discards the Task with _, which could hide potential errors. Consider implementing proper error handling:

-public void CheckForNewUpdate() => _ = Ioc.Default.GetRequiredService<Updater>().UpdateAppAsync(false);
+public async Task CheckForNewUpdate()
+{
+    try
+    {
+        await Ioc.Default.GetRequiredService<Updater>().UpdateAppAsync(false);
+    }
+    catch (Exception ex)
+    {
+        LogException(nameof(PublicAPIInstance), "Failed to check for updates", ex);
+        ShowMsgError("Update Check Failed", ex.Message);
+    }
+}
🧹 Nitpick comments (2)
Flow.Launcher/App.xaml.cs (2)

58-70: Consider reviewing service lifetime scopes.

While the DI setup is well-structured, registering all services as singletons might not be appropriate for every component. Consider reviewing each service's lifecycle requirements:

  • Stateful services might benefit from scoped or transient lifetimes
  • Services that manage disposable resources might need special handling

Example services to review:

  • MainViewModel - Could be scoped if it maintains window-specific state
  • StringMatcher - Could be transient if it's stateful per operation

161-161: Consider making update check interval configurable.

While the DI usage is correct, the 5-hour interval for update checks is hardcoded. Consider moving this to configuration:

-var timer = new PeriodicTimer(TimeSpan.FromHours(5));
+var timer = new PeriodicTimer(TimeSpan.FromHours(_settings.UpdateCheckIntervalHours));

Also applies to: 165-165

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cdc5f0e and 8b290a6.

📒 Files selected for processing (3)
  • Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj (1 hunks)
  • Flow.Launcher/App.xaml.cs (5 hunks)
  • Flow.Launcher/PublicAPIInstance.cs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
🔇 Additional comments (6)
Flow.Launcher/App.xaml.cs (3)

7-7: LGTM! Good architectural improvement.

The transition from concrete PublicAPIInstance to IPublicAPI interface improves testability and follows dependency injection best practices. The necessary DI framework imports have been correctly added.

Also applies to: 22-23, 30-30


73-78: Review API initialization and service ordering.

The initialization sequence of services is logical, but there are two concerns:

  1. The API initialization might involve downcasting to call Initialize(), which was flagged in a previous review
  2. Consider making the initialization order explicit through a dedicated initialization service

Consider implementing an IInitializable interface:

public interface IInitializable
{
    void Initialize();
}

public class InitializationService
{
    private readonly IEnumerable<IInitializable> _initializables;
    
    public InitializationService(IEnumerable<IInitializable> initializables)
    {
        _initializables = initializables;
    }
    
    public void Initialize()
    {
        foreach (var initializable in _initializables)
        {
            initializable.Initialize();
        }
    }
}

104-105: LGTM! Consistent DI usage.

The changes correctly integrate DI for MainWindow creation and second instance handling, maintaining consistency with the new architecture.

Also applies to: 208-208

Flow.Launcher/PublicAPIInstance.cs (3)

28-28: LGTM: Import added for dependency injection support.

The addition of CommunityToolkit.Mvvm.DependencyInjection import aligns with the PR's objective of implementing dependency injection.


107-107: LGTM: Improved window management.

The change to use SingletonWindowOpener improves separation of concerns and aligns with the PR's dependency management goals.


87-87: ⚠️ Potential issue

Add proper error handling for image saving.

The current implementation discards the Task with _, which could hide potential errors. Consider implementing proper error handling:

-_ = ImageLoader.Save();
+try
+{
+    await ImageLoader.Save();
+}
+catch (Exception ex)
+{
+    LogException(nameof(PublicAPIInstance), "Failed to save images", ex);
+}

Likely invalid or redundant comment.

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
Flow.Launcher/App.xaml.cs (1)

Line range hint 7-57: Well-structured dependency injection implementation.

The overall architectural changes are well-executed:

  • Proper use of Microsoft.Extensions.Hosting for DI setup
  • Consistent service registration pattern
  • Clean transition from static access to DI
  • Good separation of concerns

However, consider creating an IFlowLauncherHost interface to encapsulate the DI container setup, making it easier to modify the DI configuration in the future:

public interface IFlowLauncherHost
{
    void ConfigureServices(IServiceCollection services);
    IServiceProvider BuildServiceProvider();
}

public class DefaultFlowLauncherHost : IFlowLauncherHost
{
    private readonly Settings _settings;

    public DefaultFlowLauncherHost(Settings settings)
    {
        _settings = settings;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddSingleton(_ => _settings)
            .AddSingleton<Updater>()
            .AddSingleton<Portable>()
            // ... other services
    }

    public IServiceProvider BuildServiceProvider()
    {
        var host = Host.CreateDefaultBuilder()
            .UseContentRoot(AppContext.BaseDirectory)
            .ConfigureServices(ConfigureServices)
            .Build();
        
        return host.Services;
    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8b290a6 and f9983b5.

📒 Files selected for processing (1)
  • Flow.Launcher/App.xaml.cs (5 hunks)
🔇 Additional comments (3)
Flow.Launcher/App.xaml.cs (3)

30-34: LGTM! Good architectural improvement.

The change from PublicAPIInstance to IPublicAPI improves the design by programming to an interface rather than an implementation. This change:

  • Enhances testability through better abstraction
  • Enables dependency injection
  • Makes the code more maintainable

35-57: LGTM! Well-structured dependency injection setup.

Good implementation using Microsoft.Extensions.Hosting with proper service registration. The singleton scoping is appropriate for the registered services.


211-211: LGTM! Proper use of dependency injection.

The change correctly uses DI to resolve MainViewModel instance.

Flow.Launcher/App.xaml.cs Show resolved Hide resolved
Flow.Launcher/App.xaml.cs Show resolved Hide resolved
Flow.Launcher/App.xaml.cs Show resolved Hide resolved

This comment has been minimized.

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
Flow.Launcher.Infrastructure/Http/Http.cs (1)

Line range hint 39-47: Reconsider the Proxy property's accessibility pattern.

The current design with a public setter and private getter is unusual and could lead to confusion:

  • Consumers can set the proxy but can't read its current state
  • Makes it difficult to validate the proxy's state externally
  • Violates encapsulation principles

Consider one of these alternatives:

  1. Make both getter and setter private and expose methods for proxy configuration:
-public static HttpProxy Proxy
+private static HttpProxy Proxy
 {
     private get { return proxy; }
-    set
+    private set
     {
         proxy = value;
         proxy.PropertyChanged += UpdateProxy;
         UpdateProxy(ProxyProperty.Enabled);
     }
 }
+
+public static void ConfigureProxy(HttpProxy proxySettings)
+{
+    Proxy = proxySettings;
+}
  1. Make the getter public but return an immutable copy:
 public static HttpProxy Proxy
 {
-    private get { return proxy; }
+    get { return proxy.Clone(); }
     set
     {
         proxy = value;
         proxy.PropertyChanged += UpdateProxy;
         UpdateProxy(ProxyProperty.Enabled);
     }
 }
🧹 Nitpick comments (2)
Flow.Launcher.Infrastructure/Http/Http.cs (2)

21-21: Move API initialization to static constructor to handle DI failures gracefully.

Initializing the API property directly during declaration could throw if the IoC container isn't ready. Moving it to the static constructor would allow for proper error handling.

-private static IPublicAPI API { get; set; } = Ioc.Default.GetRequiredService<IPublicAPI>();
+private static IPublicAPI API { get; set; }

 static Http()
 {
+    try
+    {
+        API = Ioc.Default.GetRequiredService<IPublicAPI>();
+    }
+    catch (Exception ex)
+    {
+        Log.Exception("Http", "Failed to initialize API", ex);
+        throw;
+    }
+
     // existing constructor code...
 }

Line range hint 1-199: Consider breaking down the Http class to improve testability and maintainability.

The current static class design has several architectural concerns:

  • Global state makes unit testing difficult
  • Concurrent access to shared HttpClient instance could cause issues
  • Mixing HTTP client operations with UI notifications (via API.ShowMsg)

Consider splitting this into multiple focused classes:

  1. IHttpClientFactory for managing HttpClient instances
  2. IProxyConfiguration for proxy management
  3. IHttpService for the actual HTTP operations

This would:

  • Make dependencies explicit
  • Improve testability
  • Allow for better separation of concerns
  • Enable proper dependency injection

Would you like me to provide a detailed example of this architecture?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb25774 and ed16d34.

📒 Files selected for processing (3)
  • Flow.Launcher.Core/Plugin/PluginManager.cs (4 hunks)
  • Flow.Launcher.Infrastructure/Http/Http.cs (2 hunks)
  • Flow.Launcher/App.xaml.cs (5 hunks)
🔇 Additional comments (6)
Flow.Launcher/App.xaml.cs (3)

7-7: LGTM: Good architectural improvement using dependency injection.

The transition from concrete PublicAPIInstance to IPublicAPI interface improves modularity and testability. The addition of Microsoft.Extensions.DependencyInjection and Hosting packages provides a robust DI framework.

Also applies to: 22-23, 30-30


93-95: Fix potential race condition with StringMatcher.Instance.

The current implementation could lead to race conditions in a multi-threaded environment. Consider using thread-safe initialization or removing the static instance entirely.


164-168: Make update checks cancellable.

The update check task should be cancellable when the app exits to prevent potential memory leaks or hanging operations.

Flow.Launcher.Core/Plugin/PluginManager.cs (3)

162-162: LGTM: Simplified method signature.

Removing the IPublicAPI parameter and using the static property improves the API design by reducing unnecessary parameters.


522-522: LGTM: Consistent message handling through API.

Good change to use API.ShowMsgBox instead of direct message box calls, maintaining consistency with the new dependency injection pattern.


32-32: Verify thread-safety of API property initialization.

The static property initialization using DI could lead to race conditions if accessed from multiple threads during startup.

Flow.Launcher.Infrastructure/Http/Http.cs Show resolved Hide resolved
Flow.Launcher/App.xaml.cs Show resolved Hide resolved
Copy link

@check-spelling-bot Report

🔴 Please review

See the 📂 files view, the 📜action log, or 📝 job summary for details.

❌ Errors Count
❌ forbidden-pattern 22
⚠️ ignored-expect-variant 1
⚠️ non-alpha-in-dictionary 19

See ❌ Event descriptions for more information.

If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
Flow.Launcher.Infrastructure/Http/Http.cs (1)

11-11: 🛠️ Refactor suggestion

Consider using constructor-based dependency injection instead of static IoC resolution.

The current implementation using Ioc.Default.GetRequiredService<IPublicAPI>() maintains tight coupling to the IoC container and makes the code harder to test.

This was previously highlighted in an earlier review. The recommendation to make the class non-static and use constructor injection still stands:

-public static class Http
-{
+public class Http : IHttp 
+{
+    private readonly IPublicAPI _api;
+    
+    public Http(IPublicAPI api)
+    {
+        _api = api;
+    }

Also applies to: 80-80

🧹 Nitpick comments (2)
Flow.Launcher.Infrastructure/Http/Http.cs (2)

80-82: Enhance error handling with more specific information.

The current error messages could be more helpful:

  1. The user message "Please try again" doesn't guide the user on what to correct
  2. The log message "Unable to parse Uri" could include the attempted proxy values

Consider this improvement:

-Ioc.Default.GetRequiredService<IPublicAPI>().ShowMsg("Please try again", "Unable to parse Http Proxy");
-Log.Exception("Flow.Launcher.Infrastructure.Http", "Unable to parse Uri", e);
+var errorDetails = $"Invalid proxy configuration - Server: {Proxy.Server}, Port: {Proxy.Port}";
+Ioc.Default.GetRequiredService<IPublicAPI>().ShowMsg(
+    "Please check your proxy server and port values",
+    "Invalid Proxy Configuration");
+Log.Exception("Flow.Launcher.Infrastructure.Http", errorDetails, e);

Line range hint 39-39: Consider making WebProxy property internal or private.

The public WebProxy property allows external modification of proxy settings, which could lead to inconsistent state. Consider encapsulating this implementation detail.

-public static WebProxy WebProxy { get; } = new WebProxy();
+internal static WebProxy WebProxy { get; } = new WebProxy();
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ed16d34 and 6a2389f.

📒 Files selected for processing (1)
  • Flow.Launcher.Infrastructure/Http/Http.cs (2 hunks)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants