Skip to content

Conversation

@BrycensRanch
Copy link
Member

@BrycensRanch BrycensRanch commented Jul 12, 2025

Preface

SnapX is our cross-platform evolution of ShareX. While we’ve already removed the original WinForms UI code—a necessary step for making SnapX build and run beyond Windows—this left significant gaps in the core logic.

Much of SnapX.Core was historically intertwined with direct UI calls. Removing the WinForms layer exposed how deeply this coupling ran, leaving several core features incomplete or blocked because the business logic still assumed UI components were directly accessible.

Features like region-based screen OCR or triggering notifications are key examples. Previously, these relied on tightly integrated UI calls, which no longer exist. As a result, SnapX.Core couldn’t properly request UI-driven actions or surface user interactions.

This PR addresses that gap to ensure SnapX can move forward toward a stable cross-platform release.

Description of Change

This PR refactors SnapX.Core to decouple it cleanly from any UI dependencies. Instead of assuming direct calls to UI elements, the core now exposes well-defined interfaces and contracts for operations that require user interaction or visual feedback.

Key changes include:

  • Introduced abstractions in SnapX.Core for:
    • Region selection (e.g. for OCR or screenshot capture)
    • User notifications
    • Error reporting dialogs
  • Updated existing features to call these abstractions rather than direct UI code
  • Prepared SnapX.Core so that SnapX.Avalonia (or any other UI) can handle UI responsibilities separately
  • Established a clearer separation of concerns between business logic and UI layers

This ensures that SnapX.Core can remain UI-agnostic while enabling frontends like Avalonia to implement platform-specific user interactions.

Possible Alternatives

We briefly considered patching core logic with conditionals to call Avalonia-specific methods directly. However, that approach would have reintroduced tight coupling between SnapX.Core and SnapX.Avalonia, defeating the purpose of modularizing the app for cross-platform support.

Another alternative was to postpone this refactoring and only address UI calls feature by feature. We decided against this, as it would have prolonged technical debt and slowed down the release schedule for upcoming versions.

Implementation Details

  • Core services now define events or interfaces instead of direct method calls to UI components.
  • SnapX.Avalonia subscribes to these events and handles the appropriate UI workflows (e.g. displaying dialogs, selecting regions).
  • Some legacy method stubs in SnapX.Core were removed or rewritten to fit this new architecture.
  • The refactoring ensures no runtime references to UI assemblies remain in SnapX.Core, preserving its portability.

Notes

This refactor paves the way for completing several previously blocked features, including region-based OCR and proper notification handling.

It’s expected to land as part of the upcoming bi-weekly v0.4.0 pre-release.

Additionally, I've fixed a lot of the types for the ApplicationConfig, that the unfinished types caused corruption.

Future work includes:

  • Fully implementing region selection in SnapX.Avalonia to match legacy ShareX capabilities
  • Completing missing integrations for other UI-driven features

Disclosure: This PR overview was auto-generated by ChatGPT. As an experiment to save developer time.

@github-actions github-actions bot added documentation Improvements or additions to documentation packaging Application packaging ie (RPM, deb, PKGBUILD) Avalonia Related to SnapX.Avalonia Core Related to SnapX.Core build Related to building labels Jul 12, 2025

public partial class SettingsHomePageView : UserControl
{
private SettingsHomePageViewVM ViewModel;
Copy link
Contributor

Choose a reason for hiding this comment

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

An opening brace should not be followed by a blank line.

Suggested change
private SettingsHomePageViewVM ViewModel;

return process.ExitCode;
}

return -1;
Copy link
Contributor

Choose a reason for hiding this comment

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

A closing brace should not be preceded by a blank line.

Suggested change
return -1;


public void Emit(LogEvent logEvent)
{

Copy link
Contributor

Choose a reason for hiding this comment

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

An opening brace should not be followed by a blank line.

Suggested change

ICaptureService CaptureService)
: CaptureBase(MainWindowService, NotificationService, UploadManager, DelayService, LoggerService, CaptureService)
{

Copy link
Contributor

Choose a reason for hiding this comment

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

An opening brace should not be followed by a blank line.

Suggested change

if (destinationType != typeof(string)) return base.ConvertTo(context, culture, value, destinationType) ?? throw new FormatException($"Cannot convert '{value}' to ImageSharp Color.");
var list = (List<string>)value;
return string.Join(", ", list);

Copy link
Contributor

Choose a reason for hiding this comment

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

A closing brace should not be preceded by a blank line.

Suggested change

Directory.Delete(testDir, recursive: true);
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

A closing brace should not be preceded by a blank line.

Suggested change

@BrycensRanch BrycensRanch changed the title refactor/clean-architecture refactor: clean architecture Jul 12, 2025
@BrycensRanch BrycensRanch marked this pull request as draft July 12, 2025 00:01
…hitecture

# Conflicts:
#	SnapX.Avalonia/ViewModels/HomePageViewModel.cs
@github-actions github-actions bot removed the packaging Application packaging ie (RPM, deb, PKGBUILD) label Jul 12, 2025
@github-actions github-actions bot added the actions GitHub Actions label Jul 12, 2025
@socket-security
Copy link

socket-security bot commented Jul 12, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedmimetypecore@​2.0.49110087100100
Addedtunit@​0.25.219610089100100
Addedtmds.dbus.sourcegenerator@​0.0.219910089100100

View full report


return await responseMessage.Content.ReadAsStringAsync();
Copy link
Contributor

Choose a reason for hiding this comment

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

A closing brace should not be preceded by a blank line.

Suggested change
return await responseMessage.Content.ReadAsStringAsync();

…hitecture

# Conflicts:
#	SnapX.Core/SnapX.Core.csproj
@github-actions github-actions bot added the macOS Relating to macOS label Jul 18, 2025
…hitecture

# Conflicts:
#	README.md
#	SnapX.Core/SnapX.cs
…ask updates

- Now scales to a large amount of items without flickering.
- Resolved missing symbol 'FindIndex' by introducing an extension method for AvaloniaList<T>.
- Optimized recentTasks update logic:
  - Replaced full list clear/add with incremental mutation using RemoveAt and Insert.
  - Used reverse iteration for safe in-place removal of old items (`toRemove`).
  - Applied targeted replacement for items in `toUpdate` via FindIndex.
  - Prepended new items (`toAdd`) to maintain order and avoid unnecessary sorting.
- Wrapped UI update logic in Dispatcher.UIThread.InvokeAsync to ensure thread safety.
- Appended GetTask().ConfigureAwait(false) to ensure the continuation is offloaded from the UI thread, improving responsiveness and avoiding unnecessary context switches.

These changes improve UI smoothness, avoid layout flicker, prevent unnecessary reallocation, and ensure the async flow is context-aware and lightweight.
List<int> toRemove;

newDesiredTasks = tasks
.OrderByDescending(item => item.task.Id)
Copy link
Contributor

Choose a reason for hiding this comment

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

Opening braces should not be preceded by blank line.

Suggested change
.OrderByDescending(item => item.task.Id)

// Warning: Computations on the UIThread are precious.
await Dispatcher.UIThread.InvokeAsync(() =>
{
if (newDesiredTasks.Count > 50_000)
Copy link
Contributor

Choose a reason for hiding this comment

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

An opening brace should not be followed by a blank line.

Suggested change
if (newDesiredTasks.Count > 50_000)

Copy link
Member

Choose a reason for hiding this comment

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

What does it mean? There is no line?

TypeInfoResolver = SettingsContext.Default
TypeInfoResolver = SettingsContext.Default,
Converters = { new JsonStringEnumConverter() }

Copy link
Contributor

Choose a reason for hiding this comment

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

A closing brace should not be preceded by a blank line.

Suggested change

@ok-coder1
Copy link
Member

ok-coder1 commented Aug 3, 2025 via email

@BrycensRanch
Copy link
Member Author

Why does this always send reviews like this every big PR?

That's because the CodeFactor bot is meant to improve code quality, but unfortunately, all it's done is add noise.

…hitecture

# Conflicts:
#	SnapX.CLI/Program.cs
#	SnapX.Core/SnapX.Core.csproj
…hitecture

# Conflicts:
#	SnapX.Avalonia/Views/HomePageView.axaml
#	SnapX.Avalonia/Views/HomePageView.axaml.cs
@ok-coder1
Copy link
Member

Just why.

Disclosure: This PR overview was auto-generated by ChatGPT. As an experiment to save developer time.

@BrycensRanch
Copy link
Member Author

Just why.

Disclosure: This PR overview was auto-generated by ChatGPT. As an experiment to save developer time.

I understand the reaction 😅. As someone curious & technologically adventurous, I’m always exploring ways to streamline workflows, and this was an experiment to see if auto-generating PR overviews could save time.

Disclosure: This PR reply was also auto-generated by ChatGPT. Experiment ongoing.

@github-actions
Copy link
Contributor

This PR is being marked as stale due to inactivity.

@github-actions github-actions bot added the stale Inactive label Nov 13, 2025
@BrycensRanch
Copy link
Member Author

Nuhuh.

@BrycensRanch BrycensRanch removed the stale Inactive label Nov 13, 2025
@ok-coder1
Copy link
Member

ok-coder1 commented Nov 13, 2025 via email

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

Labels

actions GitHub Actions Avalonia Related to SnapX.Avalonia build Related to building Core Related to SnapX.Core documentation Improvements or additions to documentation macOS Relating to macOS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants